Merge pull request #2977 from KeeJef/delete-and-backspace

Add keyboard shortcuts to modals
pull/3067/head
Audric Ackermann 2 months ago committed by GitHub
commit 0f069984c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -91,6 +91,7 @@
"emoji-mart": "^5.5.2",
"filesize": "3.6.1",
"firstline": "1.2.1",
"focus-trap-react": "^10.2.3",
"fs-extra": "9.0.0",
"glob": "7.1.2",
"image-type": "^4.1.0",

@ -1,5 +1,6 @@
import React, { useRef } from 'react';
import classNames from 'classnames';
import FocusTrap from 'focus-trap-react';
import React, { useRef } from 'react';
import useKey from 'react-use/lib/useKey';
import { SessionIconButton } from './icon';
@ -62,69 +63,74 @@ export const SessionWrapperModal = (props: SessionWrapperModalType) => {
}
};
const fallbackFocusId = 'session-wrapper-modal';
return (
<div
className={classNames('loki-dialog modal', additionalClassName || null)}
onClick={handleClick}
role="dialog"
>
<div className="session-confirm-wrapper">
<div ref={modalRef} className="session-modal">
{showHeader ? (
<div className={classNames('session-modal__header', headerReverse && 'reverse')}>
<div className="session-modal__header__close">
{showExitIcon ? (
<SessionIconButton
iconType="exit"
iconSize="small"
onClick={props.onClose}
dataTestId="modal-close-button"
/>
) : null}
<FocusTrap focusTrapOptions={{ fallbackFocus: `#${fallbackFocusId}`, allowOutsideClick: true }}>
<div
className={classNames('loki-dialog modal', additionalClassName || null)}
onClick={handleClick}
role="dialog"
id={fallbackFocusId}
>
<div className="session-confirm-wrapper">
<div ref={modalRef} className="session-modal">
{showHeader ? (
<div className={classNames('session-modal__header', headerReverse && 'reverse')}>
<div className="session-modal__header__close">
{showExitIcon ? (
<SessionIconButton
iconType="exit"
iconSize="small"
onClick={props.onClose}
dataTestId="modal-close-button"
/>
) : null}
</div>
<div className="session-modal__header__title">{title}</div>
<div className="session-modal__header__icons">
{headerIconButtons
? headerIconButtons.map((iconItem: any) => {
return (
<SessionIconButton
key={iconItem.iconType}
iconType={iconItem.iconType}
iconSize={'large'}
iconRotation={iconItem.iconRotation}
onClick={iconItem.onClick}
/>
);
})
: null}
</div>
</div>
<div className="session-modal__header__title">{title}</div>
<div className="session-modal__header__icons">
{headerIconButtons
? headerIconButtons.map((iconItem: any) => {
return (
<SessionIconButton
key={iconItem.iconType}
iconType={iconItem.iconType}
iconSize={'large'}
iconRotation={iconItem.iconRotation}
onClick={iconItem.onClick}
/>
);
})
: null}
</div>
</div>
) : null}
) : null}
<div className="session-modal__body">
<div className="session-modal__centered">
{props.children}
<div className="session-modal__body">
<div className="session-modal__centered">
{props.children}
<div className="session-modal__button-group">
{onConfirm ? (
<SessionButton buttonType={SessionButtonType.Simple} onClick={props.onConfirm}>
{confirmText || window.i18n('ok')}
</SessionButton>
) : null}
{onClose && showClose ? (
<SessionButton
buttonType={SessionButtonType.Simple}
buttonColor={SessionButtonColor.Danger}
onClick={props.onClose}
>
{cancelText || window.i18n('close')}
</SessionButton>
) : null}
<div className="session-modal__button-group">
{onConfirm ? (
<SessionButton buttonType={SessionButtonType.Simple} onClick={props.onConfirm}>
{confirmText || window.i18n('ok')}
</SessionButton>
) : null}
{onClose && showClose ? (
<SessionButton
buttonType={SessionButtonType.Simple}
buttonColor={SessionButtonColor.Danger}
onClick={props.onClose}
>
{cancelText || window.i18n('close')}
</SessionButton>
) : null}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</FocusTrap>
);
};

@ -1,5 +1,5 @@
import React, { ReactNode } from 'react';
import classNames from 'classnames';
import React, { ReactNode } from 'react';
import styled from 'styled-components';
export enum SessionButtonType {
@ -28,7 +28,7 @@ export enum SessionButtonColor {
None = 'transparent',
}
const StyledButton = styled.div<{
const StyledButton = styled.button<{
color: string | undefined;
buttonType: SessionButtonType;
buttonShape: SessionButtonShape;

@ -2,6 +2,11 @@ import React, { ChangeEvent } from 'react';
import styled, { CSSProperties } from 'styled-components';
import { Flex } from './Flex';
const StyledButton = styled.button<{ disabled: boolean }>`
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
min-height: 30px;
`;
const StyledInput = styled.input<{
filledSize: number;
outlineOffset: number;
@ -9,7 +14,6 @@ const StyledInput = styled.input<{
}>`
opacity: 0;
position: absolute;
cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')};
width: ${props => props.filledSize + props.outlineOffset}px;
height: ${props => props.filledSize + props.outlineOffset}px;
@ -71,7 +75,7 @@ export const SessionRadio = (props: SessionRadioProps) => {
style,
} = props;
const clickHandler = (e: ChangeEvent<any>) => {
const clickHandler = (e: React.SyntheticEvent<any>) => {
if (!disabled && onClick) {
// let something else catch the event if our click handler is not set
e.stopPropagation();
@ -83,37 +87,48 @@ export const SessionRadio = (props: SessionRadioProps) => {
const outlineOffset = 2;
return (
<Flex
container={true}
flexDirection={radioPosition === 'left' ? 'row' : 'row-reverse'}
justifyContent={radioPosition === 'left' ? 'flex-start' : 'flex-end'}
style={{ ...style, position: 'relative' }}
<StyledButton
onKeyDown={e => {
if (e.code === 'Space') {
clickHandler(e);
}
}}
onClick={clickHandler}
disabled={disabled}
>
<StyledInput
type="radio"
name={inputName || ''}
value={value}
aria-checked={active}
checked={active}
onChange={clickHandler}
filledSize={filledSize * 2}
outlineOffset={outlineOffset}
disabled={disabled}
data-testid={`input-${value.replaceAll(' ', '-')}`} // data-testid cannot have spaces
/>
<StyledLabel
role="button"
onClick={clickHandler}
filledSize={filledSize - 1}
outlineOffset={outlineOffset}
beforeMargins={beforeMargins}
aria-label={label}
disabled={disabled}
data-testid={`label-${value}`}
<Flex
container={true}
flexDirection={radioPosition === 'left' ? 'row' : 'row-reverse'}
justifyContent={radioPosition === 'left' ? 'flex-start' : 'flex-end'}
style={{ ...style, position: 'relative' }}
>
{label}
</StyledLabel>
</Flex>
<StyledInput
type="radio"
name={inputName || ''}
value={value}
aria-checked={active}
checked={active}
onChange={clickHandler}
tabIndex={-1} // clickHandler is on the parent button, so we need to skip this input while pressing Tab
filledSize={filledSize * 2}
outlineOffset={outlineOffset}
disabled={disabled}
data-testid={`input-${value.replaceAll(' ', '-')}`} // data-testid cannot have spaces
/>
<StyledLabel
role="button"
onClick={clickHandler}
filledSize={filledSize - 1}
outlineOffset={outlineOffset}
beforeMargins={beforeMargins}
aria-label={label}
disabled={disabled}
data-testid={`label-${value}`}
>
{label}
</StyledLabel>
</Flex>
</StyledButton>
);
};

@ -41,6 +41,7 @@ const StyledYourSessionIDSelectable = styled.p`
font-weight: 300;
font-size: var(--font-size-sm);
color: var(--text-primary-color);
flex-shrink: 0;
`;
export const YourSessionIDSelectable = () => {

@ -60,7 +60,6 @@ import { SessionSpinner } from '../basic/SessionSpinner';
import { RightPanel, StyledRightPanelContainer } from './right-panel/RightPanel';
const DEFAULT_JPEG_QUALITY = 0.85;
interface State {
isDraggingFile: boolean;
}
@ -354,6 +353,7 @@ export class SessionConversation extends React.Component<Props, State> {
}
break;
default:
break;
}
}
}

@ -1,7 +1,7 @@
import React from 'react';
import styled from 'styled-components';
import { SessionIconButton } from '../../icon';
import { Noop } from '../../../types/Util';
import { SessionIconButton } from '../../icon';
const StyledChatButtonContainer = styled.div`
.session-icon-button {
@ -50,7 +50,7 @@ export const StartRecordingButton = (props: { onClick: Noop }) => {
};
// eslint-disable-next-line react/display-name
export const ToggleEmojiButton = React.forwardRef<HTMLDivElement, { onClick: Noop }>(
export const ToggleEmojiButton = React.forwardRef<HTMLButtonElement, { onClick: Noop }>(
(props, ref) => {
return (
<StyledChatButtonContainer>

@ -1,8 +1,12 @@
import FocusTrap from 'focus-trap-react';
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import {
deleteMessagesById,
deleteMessagesByIdForEveryone,
deleteMessagesForX,
} from '../../../interactions/conversations/unsendingInteractions';
import { resetSelectedMessageIds } from '../../../state/ducks/conversations';
import { getSelectedMessageIds } from '../../../state/selectors/conversations';
@ -36,35 +40,71 @@ export const SelectionOverlay = () => {
function onCloseOverlay() {
dispatch(resetSelectedMessageIds());
}
/**
* This is a duplicate with the onKeyDown of SessionConversation.
* At some point we'll make a global handler to deal with the key presses
* and handle them depending on what is visible, but that's not part of this PR
*/
useKey(
shouldProcess => {
return (
shouldProcess.code === 'Escape' ||
shouldProcess.code === 'Backspace' ||
shouldProcess.code === 'Delete'
);
},
event => {
const selectionMode = !!selectedMessageIds.length;
switch (event.key) {
case 'Escape':
if (selectionMode) {
onCloseOverlay();
}
return true;
case 'Backspace':
case 'Delete':
if (selectionMode && selectedConversationKey) {
void deleteMessagesForX(selectedMessageIds, selectedConversationKey, isPublic);
}
return true;
default:
}
return false;
}
);
const isOnlyServerDeletable = isPublic;
const classNameAndId = 'message-selection-overlay';
return (
<div className="message-selection-overlay">
<div className="close-button">
<SessionIconButton iconType="exit" iconSize="medium" onClick={onCloseOverlay} />
</div>
<FocusTrap focusTrapOptions={{ fallbackFocus: `#${classNameAndId}`, allowOutsideClick: true }}>
<div className={classNameAndId} id={classNameAndId}>
<div className="close-button">
<SessionIconButton iconType="exit" iconSize="medium" onClick={onCloseOverlay} />
</div>
<div className="button-group">
<SessionButton
buttonColor={SessionButtonColor.Danger}
buttonShape={SessionButtonShape.Square}
buttonType={SessionButtonType.Solid}
text={window.i18n('delete')}
onClick={() => {
if (selectedConversationKey) {
if (isOnlyServerDeletable) {
void onDeleteSelectedMessagesForEveryone(
selectedConversationKey,
selectedMessageIds
);
} else {
void deleteMessagesById(selectedMessageIds, selectedConversationKey);
<div className="button-group">
<SessionButton
buttonColor={SessionButtonColor.Danger}
buttonShape={SessionButtonShape.Square}
buttonType={SessionButtonType.Solid}
text={window.i18n('delete')}
onClick={() => {
if (selectedConversationKey) {
if (isOnlyServerDeletable) {
void onDeleteSelectedMessagesForEveryone(
selectedConversationKey,
selectedMessageIds
);
} else {
void deleteMessagesById(selectedMessageIds, selectedConversationKey);
}
}
}
}}
/>
}}
/>
</div>
</div>
</div>
</FocusTrap>
);
};

@ -10,10 +10,7 @@ import { Data } from '../../../../data/data';
import { MessageInteraction } from '../../../../interactions';
import { replyToMessage } from '../../../../interactions/conversationInteractions';
import {
deleteMessagesById,
deleteMessagesByIdForEveryone,
} from '../../../../interactions/conversations/unsendingInteractions';
import { deleteMessagesForX } from '../../../../interactions/conversations/unsendingInteractions';
import {
addSenderAsModerator,
removeSenderFromModerator,
@ -97,14 +94,9 @@ const DeleteItem = ({ messageId }: { messageId: string }) => {
const onDelete = useCallback(() => {
if (convoId) {
if (!isPublic && isDeletable) {
void deleteMessagesById([messageId], convoId);
}
if (isPublic && isDeletableForEveryone) {
void deleteMessagesByIdForEveryone([messageId], convoId);
}
void deleteMessagesForX([messageId], convoId, isPublic);
}
}, [convoId, isDeletable, isDeletableForEveryone, isPublic, messageId]);
}, [convoId, isPublic, messageId]);
if (!convoId || (isPublic && !isDeletableForEveryone) || (!isPublic && !isDeletable)) {
return null;

@ -21,11 +21,13 @@ export const StyledRightPanelContainer = styled.div`
background-color: var(--background-primary-color);
border-left: 1px solid var(--border-color);
visibility: hidden;
&.show {
transform: none;
transition: transform 0.3s ease-in-out;
z-index: 3;
visibility: visible;
}
`;

@ -1,6 +1,7 @@
import { shell } from 'electron';
import React, { Dispatch, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import useKey from 'react-use/lib/useKey';
import styled from 'styled-components';
import { useLastMessage } from '../../hooks/useParamSelector';
import { MessageInteraction } from '../../interactions';
@ -119,6 +120,14 @@ export const SessionConfirm = (props: SessionConfirmDialogProps) => {
}
};
useKey('Enter', () => {
void onClickOkHandler();
});
useKey('Escape', () => {
onClickCancelHandler();
});
useEffect(() => {
if (isLoading) {
if (conversationId && lastMessage?.interactionType) {

@ -6,7 +6,7 @@ import { SessionIcon, SessionIconProps } from '.';
import { SessionNotificationCount, SessionUnreadCount } from './SessionNotificationCount';
interface SProps extends SessionIconProps {
onClick?: (e?: React.MouseEvent<HTMLDivElement>) => void;
onClick?: (e?: React.MouseEvent<HTMLButtonElement>) => void;
notificationCount?: number;
isSelected?: boolean;
isHidden?: boolean;
@ -18,7 +18,7 @@ interface SProps extends SessionIconProps {
tabIndex?: number;
}
const StyledSessionIconButton = styled.div<{ color?: string; isSelected?: boolean }>`
const StyledSessionIconButton = styled.button<{ color?: string; isSelected?: boolean }>`
background-color: var(--button-icon-background-color);
svg path {
@ -39,7 +39,7 @@ const StyledSessionIconButton = styled.div<{ color?: string; isSelected?: boolea
`;
// eslint-disable-next-line react/display-name
const SessionIconButtonInner = React.forwardRef<HTMLDivElement, SProps>((props, ref) => {
const SessionIconButtonInner = React.forwardRef<HTMLButtonElement, SProps>((props, ref) => {
const {
iconType,
iconSize,
@ -62,13 +62,13 @@ const SessionIconButtonInner = React.forwardRef<HTMLDivElement, SProps>((props,
tabIndex,
unreadCount,
} = props;
const clickHandler = (e: React.MouseEvent<HTMLDivElement>) => {
const clickHandler = (e: React.MouseEvent<HTMLButtonElement>) => {
if (props.onClick) {
e.stopPropagation();
props.onClick(e);
}
};
const keyPressHandler = (e: KeyboardEvent<HTMLDivElement>) => {
const keyPressHandler = (e: KeyboardEvent<HTMLButtonElement>) => {
if (e.currentTarget.tabIndex > -1 && e.key === 'Enter' && props.onClick) {
e.stopPropagation();
props.onClick();
@ -80,7 +80,6 @@ const SessionIconButtonInner = React.forwardRef<HTMLDivElement, SProps>((props,
color={iconColor}
isSelected={isSelected}
className={classNames('session-icon-button', iconSize)}
role="button"
ref={ref}
id={id}
onClick={clickHandler}

@ -61,6 +61,7 @@ const StyledBannerInner = styled.div`
.session-button {
margin-top: var(--margins-md);
flex-grow: 1;
}
`;
@ -75,11 +76,13 @@ const BannerInner = () => {
return (
<StyledBannerInner>
<p>{window.i18n('recoveryPhraseRevealMessage')}</p>
<SessionButton
text={window.i18n('recoveryPhraseRevealButtonText')}
onClick={showRecoveryPhraseModal}
dataTestId="reveal-recovery-phrase"
/>
<Flex container={true} alignItems="center" justifyContent="center">
<SessionButton
text={window.i18n('recoveryPhraseRevealButtonText')}
onClick={showRecoveryPhraseModal}
dataTestId="reveal-recovery-phrase"
/>
</Flex>
</StyledBannerInner>
);
};

@ -138,7 +138,7 @@ export const OverlayMessage = () => {
justifyContent="space-between"
alignItems="center"
width="100%"
padding="0 var(--margins-md)" // YourSessionIDSelectable already has a left margin of 15px
padding="0 var(--margins-sm)" // YourSessionIDSelectable already has a left margin of 15px
>
<YourSessionIDSelectable />
<SessionIconButton iconSize="small" iconType="copy" onClick={copyOurSessionID} />

@ -335,6 +335,24 @@ const doDeleteSelectedMessages = async ({
// #endregion
};
/**
* Either delete for everyone or not, based on the props
*/
export async function deleteMessagesForX(
messageIds: Array<string>,
conversationId: string,
isPublic: boolean
) {
if (conversationId) {
if (!isPublic) {
void deleteMessagesById(messageIds, conversationId);
}
if (isPublic) {
void deleteMessagesByIdForEveryone(messageIds, conversationId);
}
}
}
export async function deleteMessagesByIdForEveryone(
messageIds: Array<string>,
conversationId: string

@ -20,7 +20,7 @@
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.24"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2":
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2":
version "7.24.2"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae"
integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==
@ -54,7 +54,7 @@
json5 "^2.2.3"
semver "^6.3.1"
"@babel/generator@^7.20.0", "@babel/generator@^7.22.15", "@babel/generator@^7.24.1":
"@babel/generator@^7.20.0", "@babel/generator@^7.24.1":
version "7.24.1"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.1.tgz#e67e06f68568a4ebf194d1c6014235344f0476d0"
integrity sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==
@ -117,7 +117,7 @@
lodash.debounce "^4.0.8"
resolve "^1.14.2"
"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5":
"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
@ -213,12 +213,12 @@
dependencies:
"@babel/types" "^7.22.5"
"@babel/helper-string-parser@^7.22.5", "@babel/helper-string-parser@^7.23.4":
"@babel/helper-string-parser@^7.23.4":
version "7.24.1"
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e"
integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==
"@babel/helper-validator-identifier@^7.22.15", "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5":
"@babel/helper-validator-identifier@^7.22.20":
version "7.22.20"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
@ -246,7 +246,7 @@
"@babel/traverse" "^7.24.1"
"@babel/types" "^7.24.0"
"@babel/highlight@^7.22.13", "@babel/highlight@^7.24.2":
"@babel/highlight@^7.24.2":
version "7.24.2"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26"
integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==
@ -256,7 +256,7 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"
"@babel/parser@^7.13.16", "@babel/parser@^7.20.0", "@babel/parser@^7.20.15", "@babel/parser@^7.22.15", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1":
"@babel/parser@^7.13.16", "@babel/parser@^7.20.0", "@babel/parser@^7.20.15", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1":
version "7.24.1"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.1.tgz#1e416d3627393fab1cb5b0f2f1796a100ae9133a"
integrity sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==
@ -667,7 +667,7 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/template@^7.0.0", "@babel/template@^7.22.15", "@babel/template@^7.22.5", "@babel/template@^7.24.0":
"@babel/template@^7.0.0", "@babel/template@^7.22.15", "@babel/template@^7.24.0":
version "7.24.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==
@ -692,7 +692,7 @@
debug "^4.3.1"
globals "^11.1.0"
"@babel/types@^7.20.0", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.0":
"@babel/types@^7.20.0", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.0":
version "7.24.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf"
integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==
@ -1088,7 +1088,7 @@
"@types/yargs" "^17.0.8"
chalk "^4.0.0"
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5":
"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.5":
version "0.3.5"
resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
@ -1102,7 +1102,7 @@
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721"
integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==
"@jridgewell/set-array@^1.0.1", "@jridgewell/set-array@^1.2.1":
"@jridgewell/set-array@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
@ -2019,21 +2019,21 @@
"@types/prop-types" "*"
"@types/react" "*"
"@types/react@*", "@types/react@^17", "@types/react@^17.0.2":
version "17.0.65"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.65.tgz#95f6a2ab61145ffb69129d07982d047f9e0870cd"
integrity sha512-oxur785xZYHvnI7TRS61dXbkIhDPnGfsXKv0cNXR/0ml4SipRIFpSMzA7HMEfOywFwJ5AOnPrXYTEiTRUQeGlQ==
"@types/react@*", "@types/react@17.0.2", "@types/react@^17":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8"
integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/react@17.0.2":
version "17.0.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.2.tgz#3de24c4efef902dd9795a49c75f760cbe4f7a5a8"
integrity sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==
"@types/react@^17.0.2":
version "17.0.65"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.65.tgz#95f6a2ab61145ffb69129d07982d047f9e0870cd"
integrity sha512-oxur785xZYHvnI7TRS61dXbkIhDPnGfsXKv0cNXR/0ml4SipRIFpSMzA7HMEfOywFwJ5AOnPrXYTEiTRUQeGlQ==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/redux-logger@3.0.7":
@ -2686,7 +2686,7 @@ argparse@^2.0.1:
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1:
array-buffer-byte-length@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f"
integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==
@ -2768,7 +2768,7 @@ array.prototype.tosorted@^1.1.1:
es-shim-unscopables "^1.0.0"
get-intrinsic "^1.1.3"
arraybuffer.prototype.slice@^1.0.1, arraybuffer.prototype.slice@^1.0.3:
arraybuffer.prototype.slice@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6"
integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==
@ -3264,7 +3264,7 @@ camelize@^1.0.0:
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001587:
caniuse-lite@^1.0.30001587:
version "1.0.30001600"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz#93a3ee17a35aa6a9f0c6ef1b2ab49507d1ab9079"
integrity sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==
@ -4253,7 +4253,7 @@ electron-publish@23.6.0:
lazy-val "^1.0.5"
mime "^2.5.2"
electron-to-chromium@^1.4.477, electron-to-chromium@^1.4.668:
electron-to-chromium@^1.4.668:
version "1.4.717"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.717.tgz#99db370cae8cd090d5b01f8748e9ad369924d0f8"
integrity sha512-6Fmg8QkkumNOwuZ/5mIbMU9WI3H2fmn5ajcVya64I5Yr5CcNmO7vcLt0Y7c96DCiMO5/9G+4sI2r6eEvdg1F7A==
@ -5052,6 +5052,21 @@ flow-parser@^0.206.0:
resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.206.0.tgz#f4f794f8026535278393308e01ea72f31000bfef"
integrity sha512-HVzoK3r6Vsg+lKvlIZzaWNBVai+FXTX1wdYhz/wVlH13tb/gOdLXmlTqy6odmTBhT5UoWUbq0k8263Qhr9d88w==
focus-trap-react@^10.2.3:
version "10.2.3"
resolved "https://registry.yarnpkg.com/focus-trap-react/-/focus-trap-react-10.2.3.tgz#a5a2ea7fbb042ffa4337fde72758325ed0fb793a"
integrity sha512-YXBpFu/hIeSu6NnmV2xlXzOYxuWkoOtar9jzgp3lOmjWLWY59C/b8DtDHEAV4SPU07Nd/t+nS/SBNGkhUBFmEw==
dependencies:
focus-trap "^7.5.4"
tabbable "^6.2.0"
focus-trap@^7.5.4:
version "7.5.4"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-7.5.4.tgz#6c4e342fe1dae6add9c2aa332a6e7a0bbd495ba2"
integrity sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==
dependencies:
tabbable "^6.2.0"
follow-redirects@^1.15.0:
version "1.15.3"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a"
@ -5200,7 +5215,7 @@ get-func-name@^2.0.0:
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==
get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
@ -5223,7 +5238,7 @@ get-stream@^6.0.0, get-stream@^6.0.1:
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
get-symbol-description@^1.0.0, get-symbol-description@^1.0.2:
get-symbol-description@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5"
integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==
@ -5475,13 +5490,6 @@ has-yarn@^2.1.0:
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
hasown@^2.0.0, hasown@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.1.tgz#26f48f039de2c0f8d3356c223fb8d50253519faa"
@ -5762,7 +5770,7 @@ invert-kv@^3.0.0:
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-3.0.1.tgz#a93c7a3d4386a1dc8325b97da9bb1620c0282523"
integrity sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==
is-array-buffer@^3.0.1, is-array-buffer@^3.0.2, is-array-buffer@^3.0.4:
is-array-buffer@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98"
integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==
@ -7416,7 +7424,7 @@ node-loader@^2.0.0:
dependencies:
loader-utils "^2.0.0"
node-releases@^2.0.13, node-releases@^2.0.14:
node-releases@^2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
@ -7500,7 +7508,7 @@ object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-inspect@^1.12.3, object-inspect@^1.13.1, object-inspect@^1.9.0:
object-inspect@^1.13.1, object-inspect@^1.9.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
@ -8862,7 +8870,7 @@ safe-json-stringify@~1:
resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd"
integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==
safe-regex-test@^1.0.0, safe-regex-test@^1.0.3:
safe-regex-test@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377"
integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==
@ -9378,7 +9386,7 @@ string.prototype.matchall@^4.0.8:
regexp.prototype.flags "^1.5.0"
side-channel "^1.0.4"
string.prototype.trim@^1.2.7, string.prototype.trim@^1.2.8:
string.prototype.trim@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd"
integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==
@ -9387,7 +9395,7 @@ string.prototype.trim@^1.2.7, string.prototype.trim@^1.2.8:
define-properties "^1.2.0"
es-abstract "^1.22.1"
string.prototype.trimend@^1.0.6, string.prototype.trimend@^1.0.7:
string.prototype.trimend@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e"
integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==
@ -9396,7 +9404,7 @@ string.prototype.trimend@^1.0.6, string.prototype.trimend@^1.0.7:
define-properties "^1.2.0"
es-abstract "^1.22.1"
string.prototype.trimstart@^1.0.6, string.prototype.trimstart@^1.0.7:
string.prototype.trimstart@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298"
integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==
@ -9554,6 +9562,11 @@ symbol-tree@^3.2.4:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
tabbable@^6.2.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-6.2.0.tgz#732fb62bc0175cfcec257330be187dcfba1f3b97"
integrity sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==
tapable@^2.1.1, tapable@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
@ -9847,7 +9860,7 @@ type-fest@^1.0.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"
integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==
typed-array-buffer@^1.0.0, typed-array-buffer@^1.0.1:
typed-array-buffer@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3"
integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==
@ -9978,7 +9991,7 @@ unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
update-browserslist-db@^1.0.11, update-browserslist-db@^1.0.13:
update-browserslist-db@^1.0.13:
version "1.0.13"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4"
integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==
@ -10273,7 +10286,7 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409"
integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==
which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.14, which-typed-array@^1.1.9:
which-typed-array@^1.1.14, which-typed-array@^1.1.9:
version "1.1.14"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.14.tgz#1f78a111aee1e131ca66164d8bdc3ab062c95a06"
integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==

Loading…
Cancel
Save