mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-05-31 12:03:08 +01:00
Update composition area buttons and menus with axo components
Co-authored-by: Jamie <113370520+jamiebuilds-signal@users.noreply.github.com>
This commit is contained in:
@@ -13,90 +13,6 @@
|
||||
align-items: center;
|
||||
background: none;
|
||||
|
||||
&__microphone {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
background: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
padding: 0;
|
||||
border: none;
|
||||
|
||||
@include mixins.keyboard-mode {
|
||||
&:focus {
|
||||
outline: 2px solid variables.$color-ultramarine;
|
||||
}
|
||||
}
|
||||
|
||||
outline: none;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/mic/mic.svg',
|
||||
var(--color-label-primary)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
&__recorder-button {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 32px;
|
||||
opacity: 0.3;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
outline: none;
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
||||
&--complete {
|
||||
background: color.adjust(variables.$color-accent-green, $lightness: 20%);
|
||||
border: 1px solid variables.$color-accent-green;
|
||||
|
||||
.icon {
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/check/check.svg',
|
||||
variables.$color-accent-green
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
&--cancel {
|
||||
background: color.adjust(variables.$color-accent-red, $lightness: 20%);
|
||||
border: 1px solid variables.$color-accent-red;
|
||||
|
||||
.icon {
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/x/x.svg',
|
||||
variables.$color-accent-red
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__time {
|
||||
color: variables.$color-gray-60;
|
||||
font-variant: tabular-nums;
|
||||
|
||||
@@ -99,26 +99,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__send-button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: none;
|
||||
border: none;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
&::after {
|
||||
display: block;
|
||||
content: '';
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/send/send-fill.svg',
|
||||
variables.$color-ultramarine
|
||||
);
|
||||
}
|
||||
}
|
||||
&__input {
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
|
||||
@@ -44,44 +44,6 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__send-button {
|
||||
align-items: center;
|
||||
border: none;
|
||||
border-radius: 100%;
|
||||
display: flex;
|
||||
height: 32px;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
&--continue {
|
||||
&::after {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/arrow/arrow-right.svg',
|
||||
variables.$color-white
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
&--forward {
|
||||
&::after {
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/send/send-fill.svg',
|
||||
variables.$color-white
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable vertical scrolling on the modal pages
|
||||
// since the elements inside are scrollable themselves
|
||||
.module-Modal__body {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright 2021 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
@use '../mixins';
|
||||
@use '../variables';
|
||||
|
||||
.MediaQualitySelector {
|
||||
&__popper {
|
||||
@include mixins.module-composition-popper;
|
||||
& {
|
||||
color: var(--color-label-primary);
|
||||
padding-block: 12px;
|
||||
padding-inline: 16px;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include mixins.font-body-1-bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&__option {
|
||||
@include mixins.button-reset();
|
||||
|
||||
& {
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
height: 42px;
|
||||
margin-block: 2px;
|
||||
margin-inline: 0;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
&--checkmark {
|
||||
height: 12px;
|
||||
margin-block: 0;
|
||||
margin-inline: 6px;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
&--selected {
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/check/check-compact.svg',
|
||||
currentColor
|
||||
);
|
||||
}
|
||||
|
||||
&--title {
|
||||
@include mixins.font-body-2;
|
||||
}
|
||||
|
||||
&--description {
|
||||
@include mixins.font-subtitle;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include mixins.light-theme() {
|
||||
background-color: variables.$color-gray-05;
|
||||
}
|
||||
|
||||
@include mixins.dark-theme() {
|
||||
background-color: variables.$color-gray-65;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 1px 1px variables.$color-ultramarine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,12 +29,4 @@
|
||||
background: variables.$color-gray-75;
|
||||
}
|
||||
}
|
||||
|
||||
&__button {
|
||||
font-size: 13px;
|
||||
min-width: 76px;
|
||||
line-height: 18px;
|
||||
padding-block: 5px;
|
||||
padding-inline: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.FunButton__Icon--FunPicker,
|
||||
.FunButton__Icon--EmojiPicker {
|
||||
@include mixins.color-svg(
|
||||
'../images/icons/v3/emoji/emoji.svg',
|
||||
|
||||
@@ -128,7 +128,6 @@ $is-storybook: false !default;
|
||||
@use 'components/ListTile.scss';
|
||||
@use 'components/LowDiskSpaceBackupImportModal.scss';
|
||||
@use 'components/MediaEditor.scss';
|
||||
@use 'components/MediaQualitySelector.scss';
|
||||
@use 'components/MessageAudio.scss';
|
||||
@use 'components/MessageBody.scss';
|
||||
@use 'components/MessageTextRenderer.scss';
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { FC, Ref, MouseEvent } from 'react';
|
||||
import type { FC, Ref, MouseEvent, FocusEvent } from 'react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { AxoSymbol } from './AxoSymbol.dom.tsx';
|
||||
import { tw } from './tw.dom.tsx';
|
||||
@@ -174,6 +173,14 @@ export namespace AxoIconButton {
|
||||
* Called when the button is clicked. Not called when `pending` or `disabled`.
|
||||
*/
|
||||
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
|
||||
/**
|
||||
* Called when the mouse enters the button.
|
||||
*/
|
||||
onMouseEnter?: (event: MouseEvent<HTMLButtonElement>) => void;
|
||||
/**
|
||||
* Called when the mouse focuses the button.
|
||||
*/
|
||||
onFocus?: (event: FocusEvent<HTMLButtonElement>) => void;
|
||||
}>;
|
||||
|
||||
/**
|
||||
@@ -215,6 +222,8 @@ export namespace AxoIconButton {
|
||||
pressed,
|
||||
disabled,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
onFocus,
|
||||
...rest
|
||||
} = props;
|
||||
const intl = useAxoIntl();
|
||||
@@ -249,6 +258,8 @@ export namespace AxoIconButton {
|
||||
aria-pressed={pressed ?? undefined}
|
||||
aria-disabled={(pending || disabled) ?? undefined}
|
||||
onClick={handleClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onFocus={onFocus}
|
||||
className={tw(baseStyles, Variants.get(variant), Sizes.get(size))}
|
||||
{...rest}
|
||||
>
|
||||
|
||||
@@ -870,11 +870,12 @@ export const CompositionArea = memo(function CompositionArea({
|
||||
<div className="CompositionArea__placeholder" />
|
||||
<div className="CompositionArea__button-cell">
|
||||
<div className={actionSlotClassName}>
|
||||
<button
|
||||
type="button"
|
||||
className="CompositionArea__send-button"
|
||||
<AxoIconButton.Root
|
||||
symbol="send-fill"
|
||||
variant="primary"
|
||||
size="md"
|
||||
label={i18n('icu:sendMessageToContact')}
|
||||
onClick={handleForceSend}
|
||||
aria-label={i18n('icu:sendMessageToContact')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1294,11 +1295,12 @@ export const CompositionArea = memo(function CompositionArea({
|
||||
{isViewOnceActive && (
|
||||
<div className="CompositionArea__button-cell">
|
||||
<div className={actionSlotClassName}>
|
||||
<button
|
||||
type="button"
|
||||
className="CompositionArea__send-button"
|
||||
<AxoIconButton.Root
|
||||
size="md"
|
||||
variant="primary"
|
||||
symbol="send-fill"
|
||||
label={i18n('icu:sendMessageToContact')}
|
||||
onClick={handleForceSend}
|
||||
aria-label={i18n('icu:sendMessageToContact')}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
} from 'react';
|
||||
import { AttachmentList } from './conversation/AttachmentList.dom.tsx';
|
||||
import type { AttachmentForUIType } from '../types/Attachment.std.ts';
|
||||
import { Button } from './Button.dom.tsx';
|
||||
import { ContactCheckboxDisabledReason } from './conversationList/ContactCheckbox.dom.tsx';
|
||||
import type { Row } from './ConversationList.dom.tsx';
|
||||
import { ConversationList, RowType } from './ConversationList.dom.tsx';
|
||||
@@ -44,6 +43,7 @@ import { missingCaseError } from '../util/missingCaseError.std.ts';
|
||||
import { Theme } from '../util/theme.std.ts';
|
||||
import { Emoji } from '../axo/emoji.std.ts';
|
||||
import { AxoConfirmDialog } from '../axo/AxoConfirmDialog.dom.tsx';
|
||||
import { AxoIconButton } from '../axo/AxoIconButton.dom.tsx';
|
||||
|
||||
export enum ForwardMessagesModalType {
|
||||
Forward,
|
||||
@@ -260,16 +260,20 @@ export function ForwardMessagesModal({
|
||||
</div>
|
||||
<div>
|
||||
{isEditingMessage || !isLonelyDraftEditable ? (
|
||||
<Button
|
||||
aria-label={i18n('icu:ForwardMessageModal--continue')}
|
||||
className="module-ForwardMessageModal__send-button module-ForwardMessageModal__send-button--forward"
|
||||
aria-disabled={!canForwardMessages}
|
||||
<AxoIconButton.Root
|
||||
size="md"
|
||||
variant="primary"
|
||||
symbol="send-fill"
|
||||
label={i18n('icu:ForwardMessageModal--continue')}
|
||||
disabled={!canForwardMessages}
|
||||
onClick={forwardMessages}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
aria-label={i18n('icu:forwardMessage')}
|
||||
className="module-ForwardMessageModal__send-button module-ForwardMessageModal__send-button--continue"
|
||||
<AxoIconButton.Root
|
||||
size="md"
|
||||
variant="primary"
|
||||
symbol="arrow-[end]"
|
||||
label={i18n('icu:forwardMessage')}
|
||||
disabled={!hasContactsSelected}
|
||||
onClick={() => setIsEditingMessage(true)}
|
||||
/>
|
||||
|
||||
@@ -1394,7 +1394,6 @@ export function MediaEditor({
|
||||
i18n={i18n}
|
||||
isHighQuality={localIsHighQuality}
|
||||
onSelectQuality={handleSelectQuality}
|
||||
theme={pickerTheme}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -5,18 +5,20 @@ import type { JSX } from 'react';
|
||||
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import type { PropsType } from './MediaQualitySelector.dom.tsx';
|
||||
import type { MediaQualitySelectorProps } from './MediaQualitySelector.dom.tsx';
|
||||
import { MediaQualitySelector } from './MediaQualitySelector.dom.tsx';
|
||||
|
||||
export default {
|
||||
title: 'Components/MediaQualitySelector',
|
||||
argTypes: {},
|
||||
args: {},
|
||||
} satisfies Meta<PropsType>;
|
||||
} satisfies Meta<MediaQualitySelectorProps>;
|
||||
|
||||
const { i18n } = window.SignalContext;
|
||||
|
||||
const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
||||
const createProps = (
|
||||
overrideProps: Partial<MediaQualitySelectorProps> = {}
|
||||
): MediaQualitySelectorProps => ({
|
||||
conversationId: 'abc123',
|
||||
i18n,
|
||||
isHighQuality: overrideProps.isHighQuality ?? false,
|
||||
|
||||
@@ -1,60 +1,45 @@
|
||||
// Copyright 2018 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { KeyboardEvent, JSX } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Popover } from 'radix-ui';
|
||||
import type { JSX } from 'react';
|
||||
import { useMemo, useCallback } from 'react';
|
||||
import type { LocalizerType } from '../types/Util.std.ts';
|
||||
import { ThemeType } from '../types/Util.std.ts';
|
||||
import { AxoIconButton } from '../axo/AxoIconButton.dom.tsx';
|
||||
import { AxoDropdownMenu } from '../axo/AxoDropdownMenu.dom.tsx';
|
||||
import { tw } from '../axo/tw.dom.tsx';
|
||||
|
||||
export type PropsType = {
|
||||
export type MediaQualitySelectorProps = Readonly<{
|
||||
conversationId: string;
|
||||
i18n: LocalizerType;
|
||||
isHighQuality: boolean;
|
||||
onSelectQuality: (conversationId: string, isHQ: boolean) => unknown;
|
||||
theme?: ThemeType;
|
||||
};
|
||||
onSelectQuality: (conversationId: string, isHighQuality: boolean) => unknown;
|
||||
}>;
|
||||
|
||||
enum MediaQuality {
|
||||
Standard = 'standard',
|
||||
High = 'high',
|
||||
}
|
||||
|
||||
export function MediaQualitySelector({
|
||||
conversationId,
|
||||
i18n,
|
||||
isHighQuality,
|
||||
onSelectQuality,
|
||||
theme,
|
||||
}: PropsType): JSX.Element {
|
||||
const [open, setOpen] = useState(false);
|
||||
const standardRef = useRef<HTMLButtonElement>(null);
|
||||
const highRef = useRef<HTMLButtonElement>(null);
|
||||
}: MediaQualitySelectorProps): JSX.Element {
|
||||
const value = useMemo(() => {
|
||||
return isHighQuality ? MediaQuality.High : MediaQuality.Standard;
|
||||
}, [isHighQuality]);
|
||||
|
||||
const handleOpenAutoFocus = useCallback(
|
||||
(e: Event) => {
|
||||
e.preventDefault();
|
||||
if (isHighQuality) {
|
||||
highRef.current?.focus();
|
||||
} else {
|
||||
standardRef.current?.focus();
|
||||
}
|
||||
const handleValueChange = useCallback(
|
||||
(selected: string) => {
|
||||
onSelectQuality(conversationId, selected === MediaQuality.High);
|
||||
},
|
||||
[isHighQuality]
|
||||
[conversationId, onSelectQuality]
|
||||
);
|
||||
|
||||
const handleContentKeyDown = useCallback((ev: KeyboardEvent) => {
|
||||
if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {
|
||||
if (document.activeElement === standardRef.current) {
|
||||
highRef.current?.focus();
|
||||
} else {
|
||||
standardRef.current?.focus();
|
||||
}
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Popover.Root open={open} onOpenChange={setOpen}>
|
||||
<Popover.Trigger asChild>
|
||||
<AxoDropdownMenu.Root>
|
||||
<AxoDropdownMenu.Trigger>
|
||||
<AxoIconButton.Root
|
||||
variant="borderless-secondary"
|
||||
size="md"
|
||||
@@ -63,86 +48,32 @@ export function MediaQualitySelector({
|
||||
label={i18n('icu:MediaQualitySelector--button')}
|
||||
tooltip={false}
|
||||
/>
|
||||
</Popover.Trigger>
|
||||
{open && (
|
||||
<Popover.Portal>
|
||||
<div
|
||||
className={classNames({
|
||||
'light-theme': theme === ThemeType.light,
|
||||
'dark-theme': theme === ThemeType.dark,
|
||||
})}
|
||||
</AxoDropdownMenu.Trigger>
|
||||
<AxoDropdownMenu.Content>
|
||||
<AxoDropdownMenu.RadioGroup
|
||||
value={value}
|
||||
onValueChange={handleValueChange}
|
||||
>
|
||||
<AxoDropdownMenu.Label>
|
||||
{i18n('icu:MediaQualitySelector--title')}
|
||||
</AxoDropdownMenu.Label>
|
||||
<AxoDropdownMenu.RadioItem
|
||||
value={MediaQuality.Standard}
|
||||
symbol="hd-slash"
|
||||
>
|
||||
<Popover.Content
|
||||
className="MediaQualitySelector__popper"
|
||||
side="top"
|
||||
align="start"
|
||||
sideOffset={4}
|
||||
onOpenAutoFocus={handleOpenAutoFocus}
|
||||
onKeyDown={handleContentKeyDown}
|
||||
>
|
||||
<div className="MediaQualitySelector__title">
|
||||
{i18n('icu:MediaQualitySelector--title')}
|
||||
</div>
|
||||
<button
|
||||
ref={standardRef}
|
||||
aria-label={i18n(
|
||||
'icu:MediaQualitySelector--standard-quality-title'
|
||||
)}
|
||||
className="MediaQualitySelector__option"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onSelectQuality(conversationId, false);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={classNames({
|
||||
'MediaQualitySelector__option--checkmark': true,
|
||||
'MediaQualitySelector__option--selected': !isHighQuality,
|
||||
})}
|
||||
/>
|
||||
<div>
|
||||
<div className="MediaQualitySelector__option--title">
|
||||
{i18n('icu:MediaQualitySelector--standard-quality-title')}
|
||||
</div>
|
||||
<div className="MediaQualitySelector__option--description">
|
||||
{i18n(
|
||||
'icu:MediaQualitySelector--standard-quality-description'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
ref={highRef}
|
||||
aria-label={i18n(
|
||||
'icu:MediaQualitySelector--high-quality-title'
|
||||
)}
|
||||
className="MediaQualitySelector__option"
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onSelectQuality(conversationId, true);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className={classNames({
|
||||
'MediaQualitySelector__option--checkmark': true,
|
||||
'MediaQualitySelector__option--selected': isHighQuality,
|
||||
})}
|
||||
/>
|
||||
<div>
|
||||
<div className="MediaQualitySelector__option--title">
|
||||
{i18n('icu:MediaQualitySelector--high-quality-title')}
|
||||
</div>
|
||||
<div className="MediaQualitySelector__option--description">
|
||||
{i18n('icu:MediaQualitySelector--high-quality-description')}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</Popover.Content>
|
||||
</div>
|
||||
</Popover.Portal>
|
||||
)}
|
||||
</Popover.Root>
|
||||
{i18n('icu:MediaQualitySelector--standard-quality-title')}
|
||||
<div className={tw('type-body-small text-label-secondary')}>
|
||||
{i18n('icu:MediaQualitySelector--standard-quality-description')}
|
||||
</div>
|
||||
</AxoDropdownMenu.RadioItem>
|
||||
<AxoDropdownMenu.RadioItem value={MediaQuality.High} symbol="hd">
|
||||
{i18n('icu:MediaQualitySelector--high-quality-title')}
|
||||
<div className={tw('type-body-small text-label-secondary')}>
|
||||
{i18n('icu:MediaQualitySelector--high-quality-description')}
|
||||
</div>
|
||||
</AxoDropdownMenu.RadioItem>
|
||||
</AxoDropdownMenu.RadioGroup>
|
||||
</AxoDropdownMenu.Content>
|
||||
</AxoDropdownMenu.Root>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import type { ReactNode, JSX } from 'react';
|
||||
import type { LocalizerType } from '../types/I18N.std.ts';
|
||||
import { Button, ButtonSize, ButtonVariant } from './Button.dom.tsx';
|
||||
import { AxoButton } from '../axo/AxoButton.dom.tsx';
|
||||
|
||||
type Props = {
|
||||
i18n: LocalizerType;
|
||||
@@ -21,21 +21,16 @@ export function RecordingComposer({
|
||||
return (
|
||||
<div className="RecordingComposer">
|
||||
<div className="RecordingComposer__content">{children}</div>
|
||||
<Button
|
||||
className="RecordingComposer__button"
|
||||
<AxoButton.Root
|
||||
variant="borderless-secondary"
|
||||
size="md"
|
||||
onClick={onCancel}
|
||||
size={ButtonSize.Medium}
|
||||
variant={ButtonVariant.Secondary}
|
||||
>
|
||||
{i18n('icu:RecordingComposer__cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className="RecordingComposer__button"
|
||||
onClick={onSend}
|
||||
size={ButtonSize.Medium}
|
||||
>
|
||||
</AxoButton.Root>
|
||||
<AxoButton.Root variant="primary" size="md" onClick={onSend}>
|
||||
{i18n('icu:RecordingComposer__send')}
|
||||
</Button>
|
||||
</AxoButton.Root>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
useStartRecordingShortcut,
|
||||
useKeyboardShortcuts,
|
||||
} from '../../hooks/useKeyboardShortcuts.dom.tsx';
|
||||
import { AxoIconButton } from '../../axo/AxoIconButton.dom.tsx';
|
||||
|
||||
export type PropsType = {
|
||||
conversationId: string;
|
||||
@@ -50,14 +51,15 @@ export function AudioCapture({
|
||||
|
||||
return (
|
||||
<div className="AudioCapture">
|
||||
<button
|
||||
aria-label={i18n('icu:voiceRecording--start')}
|
||||
className="AudioCapture__microphone"
|
||||
<AxoIconButton.Root
|
||||
symbol="mic"
|
||||
variant="borderless-secondary"
|
||||
size="md"
|
||||
label={i18n('icu:voiceRecording--start')}
|
||||
onClick={handleClick}
|
||||
onMouseEnter={handleWarmup}
|
||||
onFocus={handleWarmup}
|
||||
title={i18n('icu:voiceRecording--start')}
|
||||
type="button"
|
||||
tooltip={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
import { type JSX } from 'react';
|
||||
import { VisuallyHidden } from 'react-aria';
|
||||
import { Pressable, VisuallyHidden } from 'react-aria';
|
||||
import { Button } from 'react-aria-components';
|
||||
import type { LocalizerType } from '../../types/I18N.std.ts';
|
||||
import { FunStaticEmoji } from './FunEmoji.dom.tsx';
|
||||
import { Emoji } from '../../axo/emoji.std.ts';
|
||||
import { AxoIconButton } from '../../axo/AxoIconButton.dom.tsx';
|
||||
|
||||
/**
|
||||
* Fun Picker Button
|
||||
@@ -18,10 +19,15 @@ export type FunPickerButtonProps = Readonly<{
|
||||
export function FunPickerButton(props: FunPickerButtonProps): JSX.Element {
|
||||
const { i18n } = props;
|
||||
return (
|
||||
<Button className="FunButton">
|
||||
<span className="FunButton__Icon FunButton__Icon--FunPicker" />
|
||||
<VisuallyHidden>{i18n('icu:FunButton__Label--FunPicker')}</VisuallyHidden>
|
||||
</Button>
|
||||
<Pressable>
|
||||
<AxoIconButton.Root
|
||||
symbol="emoji"
|
||||
variant="borderless-secondary"
|
||||
label={i18n('icu:FunButton__Label--FunPicker')}
|
||||
size="md"
|
||||
tooltip={false}
|
||||
/>
|
||||
</Pressable>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user