Small UI fixes for left pane dialogs
This commit is contained in:
parent
6c906d5da8
commit
f3715411c6
7 changed files with 298 additions and 226 deletions
|
@ -2337,6 +2337,9 @@
|
||||||
"autoUpdateLaterButtonLabel": {
|
"autoUpdateLaterButtonLabel": {
|
||||||
"message": "Later"
|
"message": "Later"
|
||||||
},
|
},
|
||||||
|
"autoUpdateIgnoreButtonLabel": {
|
||||||
|
"message": "Ignore update"
|
||||||
|
},
|
||||||
"leftTheGroup": {
|
"leftTheGroup": {
|
||||||
"message": "$name$ left the group.",
|
"message": "$name$ left the group.",
|
||||||
"description": "Shown in the conversation history when a single person leaves the group",
|
"description": "Shown in the conversation history when a single person leaves the group",
|
||||||
|
|
|
@ -8,12 +8,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.LeftPaneDialog {
|
.LeftPaneDialog {
|
||||||
|
@include button-reset;
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background: $color-ultramarine;
|
background: $color-ultramarine;
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
min-height: 64px;
|
min-height: 64px;
|
||||||
padding: 12px 18px;
|
padding: 12px 18px;
|
||||||
|
user-select: none;
|
||||||
|
cursor: inherit;
|
||||||
|
|
||||||
&__container {
|
&__container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -46,10 +51,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
width: 20px;
|
width: 24px;
|
||||||
height: 20px;
|
height: 24px;
|
||||||
margin-right: 18px;
|
margin-right: 18px;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
|
-webkit-mask-size: contain;
|
||||||
|
|
||||||
&--relink {
|
&--relink {
|
||||||
-webkit-mask: url('../images/icons/v2/link-broken-16.svg') no-repeat
|
-webkit-mask: url('../images/icons/v2/link-broken-16.svg') no-repeat
|
||||||
|
|
|
@ -5,6 +5,8 @@ import React from 'react';
|
||||||
|
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
|
import { LeftPaneDialog } from './LeftPaneDialog';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
hasExpired: boolean;
|
hasExpired: boolean;
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
|
@ -19,19 +21,17 @@ export const DialogExpiredBuild = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="LeftPaneDialog LeftPaneDialog--error">
|
<LeftPaneDialog type="error">
|
||||||
<div className="LeftPaneDialog__message">
|
{i18n('expiredWarning')}{' '}
|
||||||
{i18n('expiredWarning')}{' '}
|
<a
|
||||||
<a
|
className="LeftPaneDialog__action-text"
|
||||||
className="LeftPaneDialog__action-text"
|
href="https://signal.org/download/"
|
||||||
href="https://signal.org/download/"
|
rel="noreferrer"
|
||||||
rel="noreferrer"
|
tabIndex={-1}
|
||||||
tabIndex={-1}
|
target="_blank"
|
||||||
target="_blank"
|
>
|
||||||
>
|
{i18n('upgrade')}
|
||||||
{i18n('upgrade')}
|
</a>
|
||||||
</a>
|
</LeftPaneDialog>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
// Copyright 2020-2021 Signal Messenger, LLC
|
// Copyright 2020-2021 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { LeftPaneDialog } from './LeftPaneDialog';
|
||||||
import { Spinner } from './Spinner';
|
import { Spinner } from './Spinner';
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
import { SocketStatus } from '../types/SocketStatus';
|
import { SocketStatus } from '../types/SocketStatus';
|
||||||
|
@ -16,42 +17,6 @@ export type PropsType = NetworkStateType & {
|
||||||
manualReconnect: () => void;
|
manualReconnect: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type RenderDialogTypes = {
|
|
||||||
isConnecting?: boolean;
|
|
||||||
title: string;
|
|
||||||
subtext: string;
|
|
||||||
renderActionableButton?: () => JSX.Element;
|
|
||||||
};
|
|
||||||
|
|
||||||
function renderDialog({
|
|
||||||
isConnecting,
|
|
||||||
title,
|
|
||||||
subtext,
|
|
||||||
renderActionableButton,
|
|
||||||
}: RenderDialogTypes): JSX.Element {
|
|
||||||
return (
|
|
||||||
<div className="LeftPaneDialog LeftPaneDialog--warning">
|
|
||||||
{isConnecting ? (
|
|
||||||
<div className="LeftPaneDialog__spinner-container">
|
|
||||||
<Spinner
|
|
||||||
direction="on-avatar"
|
|
||||||
moduleClassName="LeftPaneDialog__spinner"
|
|
||||||
size="22px"
|
|
||||||
svgSize="small"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="LeftPaneDialog__icon LeftPaneDialog__icon--network" />
|
|
||||||
)}
|
|
||||||
<div className="LeftPaneDialog__message">
|
|
||||||
<h3>{title}</h3>
|
|
||||||
<span>{subtext}</span>
|
|
||||||
<div>{renderActionableButton && renderActionableButton()}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DialogNetworkStatus = ({
|
export const DialogNetworkStatus = ({
|
||||||
hasNetworkDialog,
|
hasNetworkDialog,
|
||||||
i18n,
|
i18n,
|
||||||
|
@ -59,8 +24,10 @@ export const DialogNetworkStatus = ({
|
||||||
socketStatus,
|
socketStatus,
|
||||||
manualReconnect,
|
manualReconnect,
|
||||||
}: PropsType): JSX.Element | null => {
|
}: PropsType): JSX.Element | null => {
|
||||||
const [isConnecting, setIsConnecting] = React.useState<boolean>(false);
|
const [isConnecting, setIsConnecting] = React.useState<boolean>(
|
||||||
React.useEffect(() => {
|
socketStatus === SocketStatus.CONNECTING
|
||||||
|
);
|
||||||
|
useEffect(() => {
|
||||||
if (!hasNetworkDialog) {
|
if (!hasNetworkDialog) {
|
||||||
return () => null;
|
return () => null;
|
||||||
}
|
}
|
||||||
|
@ -80,62 +47,46 @@ export const DialogNetworkStatus = ({
|
||||||
};
|
};
|
||||||
}, [hasNetworkDialog, isConnecting, setIsConnecting]);
|
}, [hasNetworkDialog, isConnecting, setIsConnecting]);
|
||||||
|
|
||||||
if (!hasNetworkDialog) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reconnect = () => {
|
const reconnect = () => {
|
||||||
setIsConnecting(true);
|
setIsConnecting(true);
|
||||||
manualReconnect();
|
manualReconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
const manualReconnectButton = (): JSX.Element => (
|
if (!hasNetworkDialog) {
|
||||||
<button
|
return null;
|
||||||
className="LeftPaneDialog__action-text"
|
}
|
||||||
onClick={reconnect}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{i18n('connect')}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isConnecting) {
|
if (isConnecting) {
|
||||||
return renderDialog({
|
const spinner = (
|
||||||
isConnecting: true,
|
<div className="LeftPaneDialog__spinner-container">
|
||||||
subtext: i18n('connectingHangOn'),
|
<Spinner
|
||||||
title: i18n('connecting'),
|
direction="on-avatar"
|
||||||
});
|
moduleClassName="LeftPaneDialog__spinner"
|
||||||
|
size="22px"
|
||||||
|
svgSize="small"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LeftPaneDialog
|
||||||
|
type="warning"
|
||||||
|
icon={spinner}
|
||||||
|
title={i18n('connecting')}
|
||||||
|
subtitle={i18n('connectingHangOn')}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOnline) {
|
return (
|
||||||
return renderDialog({
|
<LeftPaneDialog
|
||||||
renderActionableButton: manualReconnectButton,
|
type="warning"
|
||||||
subtext: i18n('checkNetworkConnection'),
|
icon="network"
|
||||||
title: i18n('offline'),
|
title={isOnline ? i18n('disconnected') : i18n('offline')}
|
||||||
});
|
subtitle={i18n('checkNetworkConnection')}
|
||||||
}
|
hasAction
|
||||||
|
clickLabel={i18n('connect')}
|
||||||
let subtext = '';
|
onClick={reconnect}
|
||||||
let title = '';
|
/>
|
||||||
let renderActionableButton;
|
);
|
||||||
|
|
||||||
switch (socketStatus) {
|
|
||||||
case SocketStatus.CONNECTING:
|
|
||||||
subtext = i18n('connectingHangOn');
|
|
||||||
title = i18n('connecting');
|
|
||||||
break;
|
|
||||||
case SocketStatus.CLOSED:
|
|
||||||
case SocketStatus.CLOSING:
|
|
||||||
default:
|
|
||||||
renderActionableButton = manualReconnectButton;
|
|
||||||
title = i18n('disconnected');
|
|
||||||
subtext = i18n('checkNetworkConnection');
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderDialog({
|
|
||||||
isConnecting: socketStatus === SocketStatus.CONNECTING,
|
|
||||||
renderActionableButton,
|
|
||||||
subtext,
|
|
||||||
title,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,8 @@ import React from 'react';
|
||||||
|
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
|
||||||
|
import { LeftPaneDialog } from './LeftPaneDialog';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
isRegistrationDone: boolean;
|
isRegistrationDone: boolean;
|
||||||
|
@ -21,20 +23,13 @@ export const DialogRelink = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="LeftPaneDialog LeftPaneDialog--warning">
|
<LeftPaneDialog
|
||||||
<div className="LeftPaneDialog__icon LeftPaneDialog__icon--relink" />
|
type="warning"
|
||||||
<div className="LeftPaneDialog__message">
|
icon="relink"
|
||||||
<h3>{i18n('unlinked')}</h3>
|
clickLabel={i18n('unlinkedWarning')}
|
||||||
<div>
|
onClick={relinkDevice}
|
||||||
<button
|
title={i18n('unlinked')}
|
||||||
className="LeftPaneDialog__action-text"
|
hasAction
|
||||||
onClick={relinkDevice}
|
/>
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{i18n('unlinkedWarning')}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,8 +5,9 @@ import React from 'react';
|
||||||
import formatFileSize from 'filesize';
|
import formatFileSize from 'filesize';
|
||||||
|
|
||||||
import { DialogType } from '../types/Dialogs';
|
import { DialogType } from '../types/Dialogs';
|
||||||
import { Intl } from './Intl';
|
|
||||||
import { LocalizerType } from '../types/Util';
|
import { LocalizerType } from '../types/Util';
|
||||||
|
import { Intl } from './Intl';
|
||||||
|
import { LeftPaneDialog } from './LeftPaneDialog';
|
||||||
|
|
||||||
export type PropsType = {
|
export type PropsType = {
|
||||||
dialogType: DialogType;
|
dialogType: DialogType;
|
||||||
|
@ -48,132 +49,99 @@ export const DialogUpdate = ({
|
||||||
|
|
||||||
if (dialogType === DialogType.Cannot_Update) {
|
if (dialogType === DialogType.Cannot_Update) {
|
||||||
return (
|
return (
|
||||||
<div className="LeftPaneDialog LeftPaneDialog--warning">
|
<LeftPaneDialog type="warning" title={i18n('cannotUpdate')}>
|
||||||
<div className="LeftPaneDialog__message">
|
<span>
|
||||||
<h3>{i18n('cannotUpdate')}</h3>
|
<Intl
|
||||||
<span>
|
components={[
|
||||||
<Intl
|
<a
|
||||||
components={[
|
key="signal-download"
|
||||||
<a
|
href="https://signal.org/download/"
|
||||||
key="signal-download"
|
rel="noreferrer"
|
||||||
href="https://signal.org/download/"
|
target="_blank"
|
||||||
rel="noreferrer"
|
>
|
||||||
target="_blank"
|
https://signal.org/download/
|
||||||
>
|
</a>,
|
||||||
https://signal.org/download/
|
]}
|
||||||
</a>,
|
i18n={i18n}
|
||||||
]}
|
id="cannotUpdateDetail"
|
||||||
i18n={i18n}
|
/>
|
||||||
id="cannotUpdateDetail"
|
</span>
|
||||||
/>
|
</LeftPaneDialog>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dialogType === DialogType.MacOS_Read_Only) {
|
if (dialogType === DialogType.MacOS_Read_Only) {
|
||||||
return (
|
return (
|
||||||
<div className="LeftPaneDialog LeftPaneDialog--warning">
|
<LeftPaneDialog
|
||||||
<div className="LeftPaneDialog__container">
|
type="warning"
|
||||||
<div className="LeftPaneDialog__message">
|
title={i18n('cannotUpdate')}
|
||||||
<h3>{i18n('cannotUpdate')}</h3>
|
hasXButton
|
||||||
<span>
|
closeLabel={i18n('close')}
|
||||||
<Intl
|
onClose={dismissDialog}
|
||||||
components={{
|
>
|
||||||
app: <strong key="app">Signal.app</strong>,
|
<span>
|
||||||
folder: <strong key="folder">/Applications</strong>,
|
<Intl
|
||||||
}}
|
components={{
|
||||||
i18n={i18n}
|
app: <strong key="app">Signal.app</strong>,
|
||||||
id="readOnlyVolume"
|
folder: <strong key="folder">/Applications</strong>,
|
||||||
/>
|
}}
|
||||||
</span>
|
i18n={i18n}
|
||||||
</div>
|
id="readOnlyVolume"
|
||||||
</div>
|
|
||||||
<div className="LeftPaneDialog__container-close">
|
|
||||||
<button
|
|
||||||
aria-label={i18n('close')}
|
|
||||||
className="LeftPaneDialog__close-button"
|
|
||||||
onClick={dismissDialog}
|
|
||||||
tabIndex={0}
|
|
||||||
type="button"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</LeftPaneDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let size: string | undefined;
|
let title = i18n('autoUpdateNewVersionTitle');
|
||||||
|
|
||||||
if (
|
if (
|
||||||
downloadSize &&
|
downloadSize &&
|
||||||
(dialogType === DialogType.DownloadReady ||
|
(dialogType === DialogType.DownloadReady ||
|
||||||
dialogType === DialogType.Downloading)
|
dialogType === DialogType.Downloading)
|
||||||
) {
|
) {
|
||||||
size = `(${formatFileSize(downloadSize, { round: 0 })})`;
|
title += ` (${formatFileSize(downloadSize, { round: 0 })})`;
|
||||||
}
|
|
||||||
|
|
||||||
let updateSubText: JSX.Element;
|
|
||||||
if (dialogType === DialogType.DownloadReady) {
|
|
||||||
updateSubText = (
|
|
||||||
<button
|
|
||||||
className="LeftPaneDialog__action-text"
|
|
||||||
onClick={startUpdate}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{i18n('downloadNewVersionMessage')}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
} else if (dialogType === DialogType.Downloading) {
|
|
||||||
const width = Math.ceil(
|
|
||||||
((downloadedSize || 1) / (downloadSize || 1)) * 100
|
|
||||||
);
|
|
||||||
|
|
||||||
updateSubText = (
|
|
||||||
<div className="LeftPaneDialog__progress--container">
|
|
||||||
<div
|
|
||||||
className="LeftPaneDialog__progress--bar"
|
|
||||||
style={{ width: `${width}%` }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
updateSubText = (
|
|
||||||
<button
|
|
||||||
className="LeftPaneDialog__action-text"
|
|
||||||
onClick={startUpdate}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
{i18n('autoUpdateNewVersionMessage')}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const versionTitle = version
|
const versionTitle = version
|
||||||
? i18n('DialogUpdate--version-available', [version])
|
? i18n('DialogUpdate--version-available', [version])
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return (
|
if (dialogType === DialogType.Downloading) {
|
||||||
<div className="LeftPaneDialog" title={versionTitle}>
|
const width = Math.ceil(
|
||||||
<div className="LeftPaneDialog__container">
|
((downloadedSize || 1) / (downloadSize || 1)) * 100
|
||||||
<div className="LeftPaneDialog__icon LeftPaneDialog__icon--update" />
|
);
|
||||||
<div className="LeftPaneDialog__message">
|
|
||||||
<h3>
|
return (
|
||||||
{i18n('autoUpdateNewVersionTitle')} {size}
|
<LeftPaneDialog icon="update" title={title} hoverText={versionTitle}>
|
||||||
</h3>
|
<div className="LeftPaneDialog__progress--container">
|
||||||
{updateSubText}
|
<div
|
||||||
</div>
|
className="LeftPaneDialog__progress--bar"
|
||||||
</div>
|
style={{ width: `${width}%` }}
|
||||||
<div className="LeftPaneDialog__container-close">
|
|
||||||
{dialogType !== DialogType.Downloading && (
|
|
||||||
<button
|
|
||||||
aria-label={i18n('close')}
|
|
||||||
className="LeftPaneDialog__close-button"
|
|
||||||
onClick={snoozeUpdate}
|
|
||||||
tabIndex={0}
|
|
||||||
type="button"
|
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
</div>
|
</LeftPaneDialog>
|
||||||
</div>
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let clickLabel: string;
|
||||||
|
if (dialogType === DialogType.DownloadReady) {
|
||||||
|
clickLabel = i18n('downloadNewVersionMessage');
|
||||||
|
} else {
|
||||||
|
clickLabel = i18n('autoUpdateNewVersionMessage');
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LeftPaneDialog
|
||||||
|
icon="update"
|
||||||
|
title={title}
|
||||||
|
hoverText={versionTitle}
|
||||||
|
hasAction
|
||||||
|
onClick={startUpdate}
|
||||||
|
clickLabel={clickLabel}
|
||||||
|
hasXButton
|
||||||
|
onClose={snoozeUpdate}
|
||||||
|
closeLabel={i18n('autoUpdateIgnoreButtonLabel')}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
149
ts/components/LeftPaneDialog.tsx
Normal file
149
ts/components/LeftPaneDialog.tsx
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
// Copyright 2021 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
import React, { ReactNode } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
const BASE_CLASS_NAME = 'LeftPaneDialog';
|
||||||
|
|
||||||
|
export type PropsType = {
|
||||||
|
type?: 'warning' | 'error';
|
||||||
|
icon?: 'update' | 'relink' | 'network' | ReactNode;
|
||||||
|
title?: string;
|
||||||
|
subtitle?: string;
|
||||||
|
children?: ReactNode;
|
||||||
|
hoverText?: string;
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
onClick?: undefined;
|
||||||
|
clickLabel?: undefined;
|
||||||
|
hasAction?: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
onClick: () => void;
|
||||||
|
clickLabel: string;
|
||||||
|
hasAction: true;
|
||||||
|
}
|
||||||
|
) &
|
||||||
|
(
|
||||||
|
| {
|
||||||
|
onClose?: undefined;
|
||||||
|
closeLabel?: undefined;
|
||||||
|
hasXButton?: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
onClose: () => void;
|
||||||
|
closeLabel: string;
|
||||||
|
hasXButton: true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
export const LeftPaneDialog: React.FC<PropsType> = ({
|
||||||
|
icon,
|
||||||
|
type,
|
||||||
|
onClick,
|
||||||
|
clickLabel,
|
||||||
|
title,
|
||||||
|
subtitle,
|
||||||
|
children,
|
||||||
|
hoverText,
|
||||||
|
hasAction,
|
||||||
|
|
||||||
|
hasXButton,
|
||||||
|
onClose,
|
||||||
|
closeLabel,
|
||||||
|
}) => {
|
||||||
|
const onClickWrap = (e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
onClick?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCloseWrap = (e: React.MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
onClose?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const iconClassName =
|
||||||
|
typeof icon === 'string'
|
||||||
|
? classNames([
|
||||||
|
`${BASE_CLASS_NAME}__icon`,
|
||||||
|
`${BASE_CLASS_NAME}__icon--${icon}`,
|
||||||
|
])
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
let action: ReactNode;
|
||||||
|
if (hasAction) {
|
||||||
|
action = (
|
||||||
|
<button
|
||||||
|
title={clickLabel}
|
||||||
|
aria-label={clickLabel}
|
||||||
|
className={`${BASE_CLASS_NAME}__action-text`}
|
||||||
|
onClick={onClickWrap}
|
||||||
|
tabIndex={0}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{clickLabel}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let xButton: ReactNode;
|
||||||
|
if (hasXButton) {
|
||||||
|
xButton = (
|
||||||
|
<div className={`${BASE_CLASS_NAME}__container-close`}>
|
||||||
|
<button
|
||||||
|
title={closeLabel}
|
||||||
|
aria-label={closeLabel}
|
||||||
|
className={`${BASE_CLASS_NAME}__close-button`}
|
||||||
|
onClick={onCloseWrap}
|
||||||
|
tabIndex={0}
|
||||||
|
type="button"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const className = classNames([
|
||||||
|
BASE_CLASS_NAME,
|
||||||
|
type === undefined ? undefined : `${BASE_CLASS_NAME}--${type}`,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const content = (
|
||||||
|
<>
|
||||||
|
<div className={`${BASE_CLASS_NAME}__container`}>
|
||||||
|
{typeof icon === 'string' ? <div className={iconClassName} /> : icon}
|
||||||
|
<div className={`${BASE_CLASS_NAME}__message`}>
|
||||||
|
{title === undefined ? undefined : <h3>{title}</h3>}
|
||||||
|
{subtitle === undefined ? undefined : <div>{subtitle}</div>}
|
||||||
|
{children}
|
||||||
|
{action}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{xButton}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (onClick) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={className}
|
||||||
|
type="button"
|
||||||
|
onClick={onClickWrap}
|
||||||
|
aria-label={clickLabel}
|
||||||
|
title={hoverText}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className} title={hoverText}>
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue