Merge branch 'accessibility' into 'develop'

Accessibility improvements

See merge request soapbox-pub/soapbox-fe!697
This commit is contained in:
Alex Gleason 2021-08-28 18:26:33 +00:00
commit e652de227c
21 changed files with 222 additions and 77 deletions

View File

@ -9,8 +9,9 @@ export function openModal(type, props) {
}; };
} }
export function closeModal() { export function closeModal(type) {
return { return {
type: MODAL_CLOSE, type: MODAL_CLOSE,
modalType: type,
}; };
} }

View File

@ -66,7 +66,7 @@ export default class Button extends React.PureComponent {
if (this.props.to) { if (this.props.to) {
return ( return (
<Link to={this.props.to}> <Link to={this.props.to} tabIndex={-1}>
{btn} {btn}
</Link> </Link>
); );

View File

@ -45,7 +45,9 @@ class DropdownMenu extends React.PureComponent {
document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('keydown', this.handleKeyDown, false); document.addEventListener('keydown', this.handleKeyDown, false);
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
if (this.focusedItem && this.props.openedViaKeyboard) this.focusedItem.focus(); if (this.focusedItem && this.props.openedViaKeyboard) {
this.focusedItem.focus({ preventScroll: true });
}
this.setState({ mounted: true }); this.setState({ mounted: true });
} }
@ -66,38 +68,42 @@ class DropdownMenu extends React.PureComponent {
handleKeyDown = e => { handleKeyDown = e => {
const items = Array.from(this.node.getElementsByTagName('a')); const items = Array.from(this.node.getElementsByTagName('a'));
const index = items.indexOf(document.activeElement); const index = items.indexOf(document.activeElement);
let element; let element = null;
switch(e.key) { switch(e.key) {
case 'ArrowDown': case 'ArrowDown':
element = items[index+1]; element = items[index+1] || items[0];
if (element) {
element.focus();
}
break; break;
case 'ArrowUp': case 'ArrowUp':
element = items[index-1]; element = items[index-1] || items[items.length-1];
if (element) { break;
element.focus(); case 'Tab':
if (e.shiftKey) {
element = items[index-1] || items[items.length-1];
} else {
element = items[index+1] || items[0];
} }
break; break;
case 'Home': case 'Home':
element = items[0]; element = items[0];
if (element) {
element.focus();
}
break; break;
case 'End': case 'End':
element = items[items.length-1]; element = items[items.length-1];
if (element) {
element.focus();
}
break; break;
case 'Escape':
this.props.onClose();
break;
}
if (element) {
element.focus();
e.preventDefault();
e.stopPropagation();
} }
} }
handleItemKeyDown = e => { handleItemKeyPress = e => {
if (e.key === 'Enter') { if (e.key === 'Enter' || e.key === ' ') {
this.handleClick(e); this.handleClick(e);
} }
} }
@ -151,7 +157,7 @@ class DropdownMenu extends React.PureComponent {
ref={i === 0 ? this.setFocusRef : null} ref={i === 0 ? this.setFocusRef : null}
onClick={this.handleClick} onClick={this.handleClick}
onAuxClick={this.handleAuxClick} onAuxClick={this.handleAuxClick}
onKeyDown={this.handleItemKeyDown} onKeyPress={this.handleItemKeyPress}
data-index={i} data-index={i}
target={newTab ? '_blank' : null} target={newTab ? '_blank' : null}
data-method={isLogout ? 'delete' : null} data-method={isLogout ? 'delete' : null}
@ -226,19 +232,36 @@ export default class Dropdown extends React.PureComponent {
} }
handleClose = () => { handleClose = () => {
if (this.activeElement) {
this.activeElement.focus();
this.activeElement = null;
}
this.props.onClose(this.state.id); this.props.onClose(this.state.id);
} }
handleKeyDown = e => { handleMouseDown = () => {
if (!this.state.open) {
this.activeElement = document.activeElement;
}
}
handleButtonKeyDown = (e) => {
switch(e.key) {
case ' ':
case 'Enter':
this.handleMouseDown();
break;
}
}
handleKeyPress = (e) => {
switch(e.key) { switch(e.key) {
case ' ': case ' ':
case 'Enter': case 'Enter':
this.handleClick(e); this.handleClick(e);
e.stopPropagation();
e.preventDefault(); e.preventDefault();
break; break;
case 'Escape':
this.handleClose();
break;
} }
} }
@ -276,7 +299,7 @@ export default class Dropdown extends React.PureComponent {
const open = this.state.id === openDropdownId; const open = this.state.id === openDropdownId;
return ( return (
<div onKeyDown={this.handleKeyDown}> <div>
<IconButton <IconButton
icon={icon} icon={icon}
title={title} title={title}
@ -285,6 +308,9 @@ export default class Dropdown extends React.PureComponent {
size={size} size={size}
ref={this.setTargetRef} ref={this.setTargetRef}
onClick={this.handleClick} onClick={this.handleClick}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
onKeyPress={this.handleKeyPress}
/> />
<Overlay show={open} placement={dropdownPlacement} target={this.findTarget}> <Overlay show={open} placement={dropdownPlacement} target={this.findTarget}>

View File

@ -13,8 +13,10 @@ export default class IconButton extends React.PureComponent {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
icon: PropTypes.string.isRequired, icon: PropTypes.string.isRequired,
onClick: PropTypes.func, onClick: PropTypes.func,
onMouseDown: PropTypes.func,
onKeyUp: PropTypes.func, onKeyUp: PropTypes.func,
onKeyDown: PropTypes.func, onKeyDown: PropTypes.func,
onKeyPress: PropTypes.func,
onMouseEnter: PropTypes.func, onMouseEnter: PropTypes.func,
onMouseLeave: PropTypes.func, onMouseLeave: PropTypes.func,
size: PropTypes.number, size: PropTypes.number,
@ -54,6 +56,30 @@ export default class IconButton extends React.PureComponent {
} }
} }
handleMouseDown = (e) => {
if (!this.props.disabled && this.props.onMouseDown) {
this.props.onMouseDown(e);
}
}
handleKeyDown = (e) => {
if (!this.props.disabled && this.props.onKeyDown) {
this.props.onKeyDown(e);
}
}
handleKeyUp = (e) => {
if (!this.props.disabled && this.props.onKeyUp) {
this.props.onKeyUp(e);
}
}
handleKeyPress = (e) => {
if (this.props.onKeyPress && !this.props.disabled) {
this.props.onKeyPress(e);
}
}
render() { render() {
const style = { const style = {
fontSize: `${this.props.size}px`, fontSize: `${this.props.size}px`,
@ -98,8 +124,10 @@ export default class IconButton extends React.PureComponent {
title={title} title={title}
className={classes} className={classes}
onClick={this.handleClick} onClick={this.handleClick}
onKeyUp={this.props.onKeyUp} onMouseDown={this.handleMouseDown}
onKeyDown={this.props.onKeyDown} onKeyDown={this.handleKeyDown}
onKeyUp={this.handleKeyUp}
onKeyPress={this.handleKeyPress}
onMouseEnter={this.props.onMouseEnter} onMouseEnter={this.props.onMouseEnter}
onMouseLeave={this.props.onMouseLeave} onMouseLeave={this.props.onMouseLeave}
tabIndex={tabIndex} tabIndex={tabIndex}
@ -125,8 +153,10 @@ export default class IconButton extends React.PureComponent {
title={title} title={title}
className={classes} className={classes}
onClick={this.handleClick} onClick={this.handleClick}
onKeyUp={this.props.onKeyUp} onMouseDown={this.handleMouseDown}
onKeyDown={this.props.onKeyDown} onKeyDown={this.handleKeyDown}
onKeyUp={this.handleKeyUp}
onKeyPress={this.handleKeyPress}
onMouseEnter={this.props.onMouseEnter} onMouseEnter={this.props.onMouseEnter}
onMouseLeave={this.props.onMouseLeave} onMouseLeave={this.props.onMouseLeave}
tabIndex={tabIndex} tabIndex={tabIndex}

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import 'wicg-inert';
import { injectIntl, FormattedMessage, defineMessages } from 'react-intl'; import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { openModal } from '../actions/modal'; import { openModal } from '../actions/modal';
@ -74,8 +75,31 @@ class ModalRoot extends React.PureComponent {
} }
}; };
handleKeyDown = (e) => {
if (e.key === 'Tab') {
const focusable = Array.from(this.node.querySelectorAll('button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter((x) => window.getComputedStyle(x).display !== 'none');
const index = focusable.indexOf(e.target);
let element;
if (e.shiftKey) {
element = focusable[index - 1] || focusable[focusable.length - 1];
} else {
element = focusable[index + 1] || focusable[0];
}
if (element) {
element.focus();
e.stopPropagation();
e.preventDefault();
}
}
}
componentDidMount() { componentDidMount() {
window.addEventListener('keyup', this.handleKeyUp, false); window.addEventListener('keyup', this.handleKeyUp, false);
window.addEventListener('keydown', this.handleKeyDown, false);
} }
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
@ -101,6 +125,7 @@ class ModalRoot extends React.PureComponent {
componentWillUnmount() { componentWillUnmount() {
window.removeEventListener('keyup', this.handleKeyUp); window.removeEventListener('keyup', this.handleKeyUp);
window.removeEventListener('keydown', this.handleKeyDown);
} }
getSiblings = () => { getSiblings = () => {

View File

@ -213,6 +213,21 @@ class Status extends ImmutablePureComponent {
this.props.OnOpenAudio(media, startTime); this.props.OnOpenAudio(media, startTime);
} }
handleHotkeyOpenMedia = e => {
const { onOpenMedia, onOpenVideo } = this.props;
const status = this._properStatus();
e.preventDefault();
if (status.get('media_attachments').size > 0) {
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
onOpenVideo(status.getIn(['media_attachments', 0]), 0);
} else {
onOpenMedia(status.get('media_attachments'), 0);
}
}
}
handleHotkeyReply = e => { handleHotkeyReply = e => {
e.preventDefault(); e.preventDefault();
this.props.onReply(this._properStatus(), this.context.router.history); this.props.onReply(this._properStatus(), this.context.router.history);
@ -461,6 +476,7 @@ class Status extends ImmutablePureComponent {
moveDown: this.handleHotkeyMoveDown, moveDown: this.handleHotkeyMoveDown,
toggleHidden: this.handleHotkeyToggleHidden, toggleHidden: this.handleHotkeyToggleHidden,
toggleSensitive: this.handleHotkeyToggleSensitive, toggleSensitive: this.handleHotkeyToggleSensitive,
openMedia: this.handleHotkeyOpenMedia,
react: this.handleHotkeyReact, react: this.handleHotkeyReact,
}; };

View File

@ -20,7 +20,7 @@ const mapDispatchToProps = (dispatch, { status, items }) => ({
}) : openDropdownMenu(id, dropdownPlacement, keyboard)); }) : openDropdownMenu(id, dropdownPlacement, keyboard));
}, },
onClose(id) { onClose(id) {
dispatch(closeModal()); dispatch(closeModal('ACTIONS'));
dispatch(closeDropdownMenu(id)); dispatch(closeDropdownMenu(id));
}, },
}); });

View File

@ -15,6 +15,8 @@ import UI from '../features/ui';
// import Introduction from '../features/introduction'; // import Introduction from '../features/introduction';
import { preload } from '../actions/preload'; import { preload } from '../actions/preload';
import { IntlProvider } from 'react-intl'; import { IntlProvider } from 'react-intl';
import { previewState as previewMediaState } from 'soapbox/features/ui/components/media_modal';
import { previewState as previewVideoState } from 'soapbox/features/ui/components/video_modal';
import ErrorBoundary from '../components/error_boundary'; import ErrorBoundary from '../components/error_boundary';
import { fetchInstance } from 'soapbox/actions/instance'; import { fetchInstance } from 'soapbox/actions/instance';
import { fetchSoapboxConfig } from 'soapbox/actions/soapbox'; import { fetchSoapboxConfig } from 'soapbox/actions/soapbox';
@ -104,6 +106,10 @@ class SoapboxMount extends React.PureComponent {
this.maybeUpdateMessages(prevProps); this.maybeUpdateMessages(prevProps);
} }
shouldUpdateScroll(_, { location }) {
return location.state !== previewMediaState && location.state !== previewVideoState;
}
render() { render() {
const { me, themeCss, locale, customCss } = this.props; const { me, themeCss, locale, customCss } = this.props;
if (me === null) return null; if (me === null) return null;
@ -137,7 +143,7 @@ class SoapboxMount extends React.PureComponent {
<meta name='theme-color' content={this.props.brandColor} /> <meta name='theme-color' content={this.props.brandColor} />
</Helmet> </Helmet>
<BrowserRouter> <BrowserRouter>
<ScrollContext> <ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
<Switch> <Switch>
{!me && <Route exact path='/' component={PublicLayout} />} {!me && <Route exact path='/' component={PublicLayout} />}
<Route exact path='/about/:slug?' component={PublicLayout} /> <Route exact path='/about/:slug?' component={PublicLayout} />

View File

@ -314,10 +314,6 @@ export default class ComposeForm extends ImmutablePureComponent {
/> />
</div> </div>
<div className='emoji-picker-wrapper'>
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
</div>
<AutosuggestTextarea <AutosuggestTextarea
ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea} ref={(isModalOpen && shouldCondense) ? null : this.setAutosuggestTextarea}
placeholder={intl.formatMessage(messages.placeholder)} placeholder={intl.formatMessage(messages.placeholder)}
@ -333,6 +329,7 @@ export default class ComposeForm extends ImmutablePureComponent {
onPaste={onPaste} onPaste={onPaste}
autoFocus={shouldAutoFocus} autoFocus={shouldAutoFocus}
> >
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
{ {
!condensed && !condensed &&
<div className='compose-form__modifiers'> <div className='compose-form__modifiers'>

View File

@ -50,7 +50,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
const index = items.findIndex(item => { const index = items.findIndex(item => {
return (item.value === value); return (item.value === value);
}); });
let element; let element = null;
switch(e.key) { switch(e.key) {
case 'Escape': case 'Escape':
@ -60,34 +60,32 @@ class PrivacyDropdownMenu extends React.PureComponent {
this.handleClick(e); this.handleClick(e);
break; break;
case 'ArrowDown': case 'ArrowDown':
element = this.node.childNodes[index + 1]; element = this.node.childNodes[index + 1] || this.node.firstChild;
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break; break;
case 'ArrowUp': case 'ArrowUp':
element = this.node.childNodes[index - 1]; element = this.node.childNodes[index - 1] || this.node.lastChild;
if (element) { break;
element.focus(); case 'Tab':
this.props.onChange(element.getAttribute('data-index')); if (e.shiftKey) {
element = this.node.childNodes[index - 1] || this.node.lastChild;
} else {
element = this.node.childNodes[index + 1] || this.node.firstChild;
} }
break; break;
case 'Home': case 'Home':
element = this.node.firstChild; element = this.node.firstChild;
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break; break;
case 'End': case 'End':
element = this.node.lastChild; element = this.node.lastChild;
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
}
break; break;
} }
if (element) {
element.focus();
this.props.onChange(element.getAttribute('data-index'));
e.preventDefault();
e.stopPropagation();
}
} }
handleClick = e => { handleClick = e => {
@ -102,7 +100,7 @@ class PrivacyDropdownMenu extends React.PureComponent {
componentDidMount() { componentDidMount() {
document.addEventListener('click', this.handleDocumentClick, false); document.addEventListener('click', this.handleDocumentClick, false);
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions); document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
if (this.focusedItem) this.focusedItem.focus(); if (this.focusedItem) this.focusedItem.focus({ preventScroll: true });
this.setState({ mounted: true }); this.setState({ mounted: true });
} }
@ -192,6 +190,9 @@ class PrivacyDropdown extends React.PureComponent {
} }
} else { } else {
const { top } = target.getBoundingClientRect(); const { top } = target.getBoundingClientRect();
if (this.state.open && this.activeElement) {
this.activeElement.focus();
}
this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' }); this.setState({ placement: top * 2 < innerHeight ? 'bottom' : 'top' });
this.setState({ open: !this.state.open }); this.setState({ open: !this.state.open });
} }
@ -214,7 +215,25 @@ class PrivacyDropdown extends React.PureComponent {
} }
} }
handleMouseDown = () => {
if (!this.state.open) {
this.activeElement = document.activeElement;
}
}
handleButtonKeyDown = (e) => {
switch(e.key) {
case ' ':
case 'Enter':
this.handleMouseDown();
break;
}
}
handleClose = () => { handleClose = () => {
if (this.state.open && this.activeElement) {
this.activeElement.focus();
}
this.setState({ open: false }); this.setState({ open: false });
} }
@ -240,6 +259,8 @@ class PrivacyDropdown extends React.PureComponent {
active={open} active={open}
inverted inverted
onClick={this.handleToggle} onClick={this.handleToggle}
onMouseDown={this.handleMouseDown}
onKeyDown={this.handleButtonKeyDown}
style={{ height: null, lineHeight: '27px' }} style={{ height: null, lineHeight: '27px' }}
/> />
</div> </div>

View File

@ -263,6 +263,21 @@ class Status extends ImmutablePureComponent {
this.props.dispatch(openModal('VIDEO', { media, time })); this.props.dispatch(openModal('VIDEO', { media, time }));
} }
handleHotkeyOpenMedia = e => {
const { onOpenMedia, onOpenVideo } = this.props;
const status = this._properStatus();
e.preventDefault();
if (status.get('media_attachments').size > 0) {
if (status.getIn(['media_attachments', 0, 'type']) === 'video') {
onOpenVideo(status.getIn(['media_attachments', 0]), 0);
} else {
onOpenMedia(status.get('media_attachments'), 0);
}
}
}
handleMuteClick = (account) => { handleMuteClick = (account) => {
this.props.dispatch(initMuteModal(account)); this.props.dispatch(initMuteModal(account));
} }
@ -548,6 +563,7 @@ class Status extends ImmutablePureComponent {
openProfile: this.handleHotkeyOpenProfile, openProfile: this.handleHotkeyOpenProfile,
toggleHidden: this.handleHotkeyToggleHidden, toggleHidden: this.handleHotkeyToggleHidden,
toggleSensitive: this.handleHotkeyToggleSensitive, toggleSensitive: this.handleHotkeyToggleSensitive,
openMedia: this.handleHotkeyOpenMedia,
react: this.handleHotkeyReact, react: this.handleHotkeyReact,
}; };

View File

@ -62,12 +62,8 @@ class HotkeysModal extends ImmutablePureComponent {
<td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open post' /></td> <td><FormattedMessage id='keyboard_shortcuts.enter' defaultMessage='to open post' /></td>
</tr> </tr>
<tr> <tr>
<td><kbd>x</kbd></td> <td><kbd>a</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td> <td><FormattedMessage id='keyboard_shortcuts.open_media' defaultMessage='to open media' /></td>
</tr>
<tr>
<td><kbd>h</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -78,6 +74,14 @@ class HotkeysModal extends ImmutablePureComponent {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<td><kbd>x</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toggle_hidden' defaultMessage='to show/hide text behind CW' /></td>
</tr>
<tr>
<td><kbd>h</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toggle_sensitivity' defaultMessage='to show/hide media' /></td>
</tr>
<tr> <tr>
<td><kbd>up</kbd>, <kbd>k</kbd></td> <td><kbd>up</kbd>, <kbd>k</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td> <td><FormattedMessage id='keyboard_shortcuts.up' defaultMessage='to move up in the list' /></td>
@ -106,10 +110,6 @@ class HotkeysModal extends ImmutablePureComponent {
<td><kbd>esc</kbd></td> <td><kbd>esc</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.unfocus' defaultMessage='to un-focus compose textarea/search' /></td> <td><FormattedMessage id='keyboard_shortcuts.unfocus' defaultMessage='to un-focus compose textarea/search' /></td>
</tr> </tr>
<tr>
<td><kbd>g</kbd> + <kbd>h</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.home' defaultMessage='to open home timeline' /></td>
</tr>
</tbody> </tbody>
</table> </table>
<table> <table>
@ -119,6 +119,10 @@ class HotkeysModal extends ImmutablePureComponent {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<td><kbd>g</kbd> + <kbd>h</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.home' defaultMessage='to open home timeline' /></td>
</tr>
<tr> <tr>
<td><kbd>g</kbd> + <kbd>n</kbd></td> <td><kbd>g</kbd> + <kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.notifications' defaultMessage='to open notifications column' /></td> <td><FormattedMessage id='keyboard_shortcuts.notifications' defaultMessage='to open notifications column' /></td>

View File

@ -155,6 +155,7 @@ const keyMap = {
goToRequests: 'g r', goToRequests: 'g r',
toggleHidden: 'x', toggleHidden: 'x',
toggleSensitive: 'h', toggleSensitive: 'h',
openMedia: 'a',
}; };
class SwitchingColumnsArea extends React.PureComponent { class SwitchingColumnsArea extends React.PureComponent {

View File

@ -461,7 +461,7 @@ class Video extends React.PureComponent {
<div className='video-player__buttons-bar'> <div className='video-player__buttons-bar'>
<div className='video-player__buttons left'> <div className='video-player__buttons left'>
<button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button> <button type='button' aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} className='player-button' onClick={this.togglePlay} autoFocus={detailed}><Icon id={paused ? 'play' : 'pause'} fixedWidth /></button>
<button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button> <button type='button' aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} className='player-button' onClick={this.toggleMute}><Icon id={muted ? 'volume-off' : 'volume-up'} fixedWidth /></button>
<div className={classNames('video-player__volume', { active: this.state.hovered })} onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}> <div className={classNames('video-player__volume', { active: this.state.hovered })} onMouseDown={this.handleVolumeMouseDown} ref={this.setVolumeRef}>

View File

@ -10,7 +10,7 @@ export default function modal(state = initialState, action) {
case MODAL_OPEN: case MODAL_OPEN:
return { modalType: action.modalType, modalProps: action.modalProps }; return { modalType: action.modalType, modalProps: action.modalProps };
case MODAL_CLOSE: case MODAL_CLOSE:
return initialState; return (action.modalType === undefined || action.modalType === state.modalType) ? initialState : state;
default: default:
return state; return state;
} }

View File

@ -221,6 +221,7 @@
} }
&:hover, &:hover,
&:focus,
&.active { &.active {
border-bottom: 2px solid var(--primary-text-color); border-bottom: 2px solid var(--primary-text-color);
} }

View File

@ -480,7 +480,8 @@
color: var(--primary-text-color--faint); color: var(--primary-text-color--faint);
background: transparent; background: transparent;
&:hover { &:hover,
&:focus {
color: hsla(var(--primary-text-color_hsl), 0.8); color: hsla(var(--primary-text-color_hsl), 0.8);
} }

View File

@ -62,9 +62,8 @@
.emoji-picker-dropdown { .emoji-picker-dropdown {
position: absolute; position: absolute;
top: 5px; top: 10px;
right: 5px; right: 5px;
z-index: 1;
} }
.compose-form__autosuggest-wrapper { .compose-form__autosuggest-wrapper {
@ -141,7 +140,6 @@
} }
} }
.emoji-picker-wrapper,
.autosuggest-textarea__suggestions-wrapper { .autosuggest-textarea__suggestions-wrapper {
position: relative; position: relative;
height: 0; height: 0;

View File

@ -43,7 +43,7 @@
&:hover, &:hover,
&:active, &:active,
&:focus { &:focus {
color: var(--primary-text-color--faint); color: var(--primary-text-color);
} }
&.disabled { &.disabled {
@ -93,7 +93,7 @@
&:hover, &:hover,
&:active, &:active,
&:focus { &:focus {
color: var(--primary-text-color--faint); color: var(--primary-text-color);
transition: color 200ms ease-out; transition: color 200ms ease-out;
} }
@ -148,10 +148,6 @@
padding: 20px; padding: 20px;
margin-bottom: 20px; margin-bottom: 20px;
.emoji-picker-wrapper {
.emoji-picker-dropdown { top: 10px; }
}
.compose-form { .compose-form {
flex: 1 1; flex: 1 1;
padding: 0 0 0 20px !important; padding: 0 0 0 20px !important;

View File

@ -146,7 +146,8 @@
"webpack-bundle-analyzer": "^4.0.0", "webpack-bundle-analyzer": "^4.0.0",
"webpack-cli": "^3.3.2", "webpack-cli": "^3.3.2",
"webpack-merge": "^5.2.0", "webpack-merge": "^5.2.0",
"websocket.js": "^0.1.12" "websocket.js": "^0.1.12",
"wicg-inert": "^3.1.1"
}, },
"devDependencies": { "devDependencies": {
"axios-mock-adapter": "^1.18.1", "axios-mock-adapter": "^1.18.1",

View File

@ -13062,6 +13062,11 @@ which@^2.0.1:
dependencies: dependencies:
isexe "^2.0.0" isexe "^2.0.0"
wicg-inert@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/wicg-inert/-/wicg-inert-3.1.1.tgz#b033fd4fbfb9e3fd709e5d84becbdf2e06e5c229"
integrity sha512-PhBaNh8ur9Xm4Ggy4umelwNIP6pPP1bv3EaWaKqfb/QNme2rdLjm7wIInvV4WhxVHhzA4Spgw9qNSqWtB/ca2A==
wide-align@^1.1.0: wide-align@^1.1.0:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"