Migrate all preferences buttons to axo button

This commit is contained in:
Jamie
2025-10-17 12:43:08 -07:00
committed by GitHub
parent 5d1a9d22f0
commit 0906da9806
18 changed files with 371 additions and 485 deletions

View File

@@ -819,10 +819,6 @@ $secondary-text-color: light-dark(
} }
} }
.Preferences--BackupsAuthButton[disabled] {
cursor: auto;
}
.Preferences--BackupsRow { .Preferences--BackupsRow {
padding-block: 8px; padding-block: 8px;
margin-block-start: 8px; margin-block-start: 8px;
@@ -915,6 +911,7 @@ $secondary-text-color: light-dark(
} }
.Preferences--LocalBackupsSetupScreenPane-top { .Preferences--LocalBackupsSetupScreenPane-top {
flex-grow: 0;
min-height: 154px; min-height: 154px;
} }
@@ -923,25 +920,6 @@ $secondary-text-color: light-dark(
width: 100%; width: 100%;
} }
.Preferences--LocalBackupsSetupScreenCopyButton {
@include mixins.font-body-small;
padding-inline: 15px 21px;
font-weight: 500;
vertical-align: text-top;
&::before {
content: '';
display: inline-block;
height: 16px;
width: 16px;
margin-inline-end: 6px;
@include mixins.color-svg(
'../images/icons/v3/copy/copy-compact.svg',
variables.$color-black
);
}
}
.Preferences--LocalBackupsSetupScreenPane-footer { .Preferences--LocalBackupsSetupScreenPane-footer {
flex-direction: row; flex-direction: row;
flex-grow: 0; flex-grow: 0;
@@ -958,30 +936,14 @@ $secondary-text-color: light-dark(
justify-content: right; justify-content: right;
} }
.Preferences--LocalBackupsSetupScreenFooterSeeKeyButton {
@include mixins.font-body-1-bold;
padding-block: 0;
padding-inline: 0;
background: none;
border: none;
outline: none;
color: variables.$color-ultramarine;
@include mixins.keyboard-mode {
&:focus {
outline: 2px solid variables.$color-ultramarine;
}
}
}
.Preferences--LocalBackupsSetupScreenFooterButton {
padding-inline: 34px;
}
.Preferences--LocalBackupsSetupScreenBody { .Preferences--LocalBackupsSetupScreenBody {
@include mixins.font-body-1; @include mixins.font-body-1;
margin-block: 8px; margin-block: 8px;
color: $secondary-text-color; color: $secondary-text-color;
a {
text-decoration: none;
}
} }
.Preferences--LocalBackupsSetupScreenBody--folder { .Preferences--LocalBackupsSetupScreenBody--folder {
@@ -1082,237 +1044,6 @@ $secondary-text-color: light-dark(
color: $secondary-text-color; color: $secondary-text-color;
} }
.Preferences--LocalBackupsConfirmKeyModalButton {
padding-inline: 32px;
}
.Preferences--LocalBackupsConfirmKeyModal .module-Modal__button-footer {
justify-content: center;
}
.Preferences__BackupsIcon {
@include mixins.light-theme {
@include mixins.color-svg(
'../images/icons/v3/signal_backups/signal_backups.svg',
variables.$color-gray-75
);
}
@include mixins.dark-theme {
@include mixins.color-svg(
'../images/icons/v3/signal_backups/signal_backups.svg',
variables.$color-gray-15
);
}
}
.Preferences__LocalBackupsIcon {
@include mixins.light-theme {
@include mixins.color-svg(
'../images/icons/v3/device/device-laptop.svg',
variables.$color-gray-75
);
}
@include mixins.dark-theme {
@include mixins.color-svg(
'../images/icons/v3/device/device-laptop.svg',
variables.$color-gray-15
);
}
}
.Preferences--LocalBackupsSetupScreen {
display: flex;
flex-direction: column;
text-align: center;
}
.Preferences--LocalBackupsSetupScreenHeader {
@include mixins.font-title-2;
margin-block: 8px;
}
.Preferences--LocalBackupsSetupScreenPane {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.Preferences--LocalBackupsSetupScreenPane-top {
flex-grow: 0;
min-height: 154px;
}
.Preferences--LocalBackupsSetupScreenPaneContent {
display: block;
width: 100%;
}
.Preferences--LocalBackupsSetupScreenCopyButton {
@include mixins.font-body-small;
padding-inline: 15px 21px;
font-weight: 500;
vertical-align: text-top;
&::before {
content: '';
display: inline-block;
height: 16px;
width: 16px;
margin-inline-end: 6px;
@include mixins.color-svg(
'../images/icons/v3/copy/copy-compact.svg',
variables.$color-black
);
}
}
.Preferences--LocalBackupsSetupScreenPane-footer {
flex-direction: row;
flex-grow: 0;
flex-shrink: 1;
}
.Preferences--LocalBackupsSetupScreenFooterSection {
display: flex;
flex-grow: 1;
}
.Preferences--LocalBackupsSetupScreenFooterSection-right {
justify-content: right;
}
.Preferences--LocalBackupsSetupScreenFooterSeeKeyButton {
@include mixins.font-body-1-bold;
padding-block: 0;
padding-inline: 0;
background: none;
border: none;
outline: none;
color: variables.$color-ultramarine;
@include mixins.keyboard-mode {
&:focus {
outline: 2px solid variables.$color-ultramarine;
}
}
}
.Preferences--LocalBackupsSetupScreenFooterButton {
padding-inline: 34px;
}
.Preferences--LocalBackupsSetupScreenBody {
@include mixins.font-body-1;
margin-block: 8px;
color: $secondary-text-color;
}
.Preferences--LocalBackupsSetupScreenBody a {
text-decoration: none;
}
.Preferences--LocalBackupsSetupScreenBody--folder {
margin-block-end: 57px;
}
.Preferences--LocalBackupsBackupKey {
width: 274px;
height: 201px;
padding-block: 28px;
padding-inline: 36px;
margin-block: 28px 20px;
background: variables.$color-gray-02;
border-radius: 12px;
border-width: 0;
outline: none;
color: variables.$color-gray-90;
font-family: variables.$monospace;
font-size: 16px;
font-weight: 400;
line-height: 36.128px;
letter-spacing: 0.624px;
overflow: hidden;
resize: none;
word-break: break-all;
text-transform: uppercase;
&::placeholder {
color: variables.$color-gray-45;
text-transform: none;
}
}
.Preferences--LocalBackupsSetupIcon {
display: inline-flex;
width: 64px;
height: 64px;
border-radius: 64px;
background: variables.$color-ultramarine-pale;
align-items: center;
justify-content: center;
&::before {
height: 38px;
width: 38px;
content: '';
}
}
.Preferences--LocalBackupsSetupIcon-folder {
margin-block-start: 60px;
margin-block-end: 12px;
&::before {
@include mixins.color-svg(
'../images/icons/v3/folder/folder.svg',
variables.$color-ultramarine-logo
);
}
}
.Preferences--LocalBackupsSetupIcon-key {
&::before {
@include mixins.color-svg(
'../images/icons/v3/key/key.svg',
variables.$color-ultramarine-logo
);
}
}
.Preferences--LocalBackupsSetupIcon-lock {
&::before {
@include mixins.color-svg(
'../images/icons/v3/lock/lock.svg',
variables.$color-ultramarine-logo
);
}
}
.Preferences--LocalBackupsConfirmKeyModal {
padding-block: 36px 20px;
padding-inline: 32px;
text-align: center;
}
.Preferences--LocalBackupsConfirmKeyModal__body {
padding: 0;
}
.Preferences--LocalBackupsConfirmKeyModalTitle {
@include mixins.font-title-medium;
margin-block: 12px;
}
.Preferences--LocalBackupsConfirmKeyModalBody {
@include mixins.font-body-1;
margin-block: 8px 32px;
color: $secondary-text-color;
}
.Preferences--LocalBackupsConfirmKeyModalButton {
padding-inline: 32px;
}
.Preferences--LocalBackupsConfirmKeyModal .module-Modal__button-footer { .Preferences--LocalBackupsConfirmKeyModal .module-Modal__button-footer {
justify-content: center; justify-content: center;
} }

View File

@@ -42,10 +42,6 @@
} }
} }
&__donate-button {
margin-block-end: 32px;
}
&__separator { &__separator {
width: 100%; width: 100%;
height: 0.5px; height: 0.5px;
@@ -466,15 +462,6 @@
} }
} }
.PreferencesDonations__PrimaryButton {
@include mixins.font-body-2;
padding-block: 5px;
padding-inline: 12px;
font-weight: 400;
border: 0.5px solid variables.$color-black-alpha-16;
border-radius: 6px;
}
.PreferencesDonations__badge-list { .PreferencesDonations__badge-list {
width: 100%; width: 100%;
margin-block: 4px 8px; margin-block: 4px 8px;

View File

@@ -392,12 +392,3 @@
justify-content: center; justify-content: center;
margin-block-end: 16px; margin-block-end: 16px;
} }
.ProfileEditor__EditPhoto {
@include mixins.font-subtitle;
padding-block: 5px;
padding-inline: 10px;
border-radius: 14px;
font-weight: 600;
}

View File

@@ -1,6 +1,6 @@
// Copyright 2025 Signal Messenger, LLC // Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React from 'react'; import React, { useState } from 'react';
import type { Meta } from '@storybook/react'; import type { Meta } from '@storybook/react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { import {
@@ -9,6 +9,7 @@ import {
AxoButton, AxoButton,
} from './AxoButton.dom.js'; } from './AxoButton.dom.js';
import { tw } from './tw.dom.js'; import { tw } from './tw.dom.js';
import { AxoSwitch } from './AxoSwitch.dom.js';
export default { export default {
title: 'Axo/AxoButton', title: 'Axo/AxoButton',
@@ -89,3 +90,46 @@ export function Basic(): JSX.Element {
</div> </div>
); );
} }
export function Spinner(): JSX.Element {
const sizes = _getAllAxoButtonSizes();
const variants = _getAllAxoButtonVariants();
const [loading, setLoading] = useState(true);
function handleClick() {
setLoading(true);
}
return (
<>
<div className={tw('mb-4 flex gap-2')}>
<AxoSwitch.Root checked={loading} onCheckedChange={setLoading} />
<span>Loading</span>
</div>
<div className={tw('flex flex-col gap-2')}>
{sizes.map(size => {
return (
<div key={size} className={tw('flex gap-2')}>
{variants.map(variant => {
return (
<AxoButton.Root
variant={variant}
size={size}
disabled={loading}
experimentalSpinner={
loading ? { 'aria-label': 'Loading' } : null
}
onClick={handleClick}
>
Save
</AxoButton.Root>
);
})}
</div>
);
})}
</div>
</>
);
}

View File

@@ -6,11 +6,13 @@ import type { TailwindStyles } from './tw.dom.js';
import { tw } from './tw.dom.js'; import { tw } from './tw.dom.js';
import { AxoSymbol } from './AxoSymbol.dom.js'; import { AxoSymbol } from './AxoSymbol.dom.js';
import { assert } from './_internal/assert.dom.js'; import { assert } from './_internal/assert.dom.js';
import type { SpinnerVariant } from '../components/SpinnerV2.dom.js';
import { SpinnerV2 } from '../components/SpinnerV2.dom.js';
const Namespace = 'AxoButton'; const Namespace = 'AxoButton';
const baseAxoButtonStyles = tw( const baseAxoButtonStyles = tw(
'flex items-center-safe justify-center-safe gap-1 truncate rounded-full select-none', 'relative inline-flex items-center-safe justify-center-safe rounded-full select-none',
'outline-0 outline-border-focused focused:outline-[2.5px]', 'outline-0 outline-border-focused focused:outline-[2.5px]',
'forced-colors:border' 'forced-colors:border'
); );
@@ -126,9 +128,9 @@ const AxoButtonVariants = {
}; };
const AxoButtonSizes = { const AxoButtonSizes = {
large: tw('px-4 py-2 type-body-medium font-medium'), large: tw('min-w-16 px-4 py-2 type-body-medium font-medium'),
medium: tw('px-3 py-1.5 type-body-medium font-medium'), medium: tw('min-w-14 px-3 py-1.5 type-body-medium font-medium'),
small: tw('px-2 py-1 type-body-small font-medium'), small: tw('min-w-12 px-2 py-1 type-body-small font-medium'),
} as const satisfies Record<string, TailwindStyles>; } as const satisfies Record<string, TailwindStyles>;
type BaseButtonAttrs = Omit< type BaseButtonAttrs = Omit<
@@ -147,21 +149,82 @@ export function _getAllAxoButtonSizes(): ReadonlyArray<AxoButtonSize> {
return Object.keys(AxoButtonSizes) as Array<AxoButtonSize>; return Object.keys(AxoButtonSizes) as Array<AxoButtonSize>;
} }
const AxoButtonSpinnerVariants: Record<AxoButtonVariant, SpinnerVariant> = {
primary: 'axo-button-spinner-on-color',
secondary: 'axo-button-spinner-secondary',
affirmative: 'axo-button-spinner-on-color',
destructive: 'axo-button-spinner-on-color',
'subtle-primary': 'axo-button-spinner-primary',
'subtle-affirmative': 'axo-button-spinner-affirmative',
'subtle-destructive': 'axo-button-spinner-destructive',
'floating-primary': 'axo-button-spinner-primary',
'floating-secondary': 'axo-button-spinner-secondary',
'floating-affirmative': 'axo-button-spinner-affirmative',
'floating-destructive': 'axo-button-spinner-destructive',
'borderless-primary': 'axo-button-spinner-primary',
'borderless-secondary': 'axo-button-spinner-secondary',
'borderless-affirmative': 'axo-button-spinner-affirmative',
'borderless-destructive': 'axo-button-spinner-destructive',
};
const AxoButtonSpinnerSizes: Record<
AxoButtonSize,
{ size: number; strokeWidth: number }
> = {
large: { size: 20, strokeWidth: 2 },
medium: { size: 20, strokeWidth: 2 },
small: { size: 16, strokeWidth: 1.5 },
};
type ExperimentalButtonSpinnerProps = Readonly<{
buttonVariant: AxoButtonVariant;
buttonSize: AxoButtonSize;
'aria-label': string;
}>;
function ExperimentalButtonSpinner(
props: ExperimentalButtonSpinnerProps
): JSX.Element {
const variant = AxoButtonSpinnerVariants[props.buttonVariant];
const sizeConfig = AxoButtonSpinnerSizes[props.buttonSize];
return (
<span className={tw('absolute inset-0 flex items-center justify-center')}>
<SpinnerV2
size={sizeConfig.size}
strokeWidth={sizeConfig.strokeWidth}
variant={variant}
value="indeterminate"
ariaLabel={props['aria-label']}
/>
</span>
);
}
export namespace AxoButton { export namespace AxoButton {
export type Variant = AxoButtonVariant; export type Variant = AxoButtonVariant;
export type Size = AxoButtonSize; export type Size = AxoButtonSize;
export type RootProps = BaseButtonAttrs & export type RootProps = BaseButtonAttrs &
Readonly<{ Readonly<{
variant: AxoButtonVariant; variant: AxoButtonVariant;
size: AxoButtonSize; size: AxoButtonSize;
symbol?: AxoSymbol.InlineGlyphName; symbol?: AxoSymbol.InlineGlyphName;
arrow?: boolean; arrow?: boolean;
experimentalSpinner?: { 'aria-label': string } | null;
children: ReactNode; children: ReactNode;
}>; }>;
export const Root: FC<RootProps> = memo( export const Root: FC<RootProps> = memo(
forwardRef((props, ref: ForwardedRef<HTMLButtonElement>) => { forwardRef((props, ref: ForwardedRef<HTMLButtonElement>) => {
const { variant, size, symbol, arrow, children, ...rest } = props; const {
variant,
size,
symbol,
arrow,
experimentalSpinner,
children,
...rest
} = props;
const variantStyles = assert( const variantStyles = assert(
AxoButtonVariants[variant], AxoButtonVariants[variant],
`${Namespace}: Invalid variant ${variant}` `${Namespace}: Invalid variant ${variant}`
@@ -170,6 +233,7 @@ export namespace AxoButton {
AxoButtonSizes[size], AxoButtonSizes[size],
`${Namespace}: Invalid size ${size}` `${Namespace}: Invalid size ${size}`
); );
return ( return (
<button <button
ref={ref} ref={ref}
@@ -177,12 +241,26 @@ export namespace AxoButton {
className={tw(variantStyles, sizeStyles)} className={tw(variantStyles, sizeStyles)}
{...rest} {...rest}
> >
{symbol != null && ( <span
<AxoSymbol.InlineGlyph symbol={symbol} label={null} /> className={tw(
)} 'flex shrink grow items-center-safe justify-center-safe gap-1 truncate',
{children} experimentalSpinner != null ? 'opacity-0' : null
{arrow && ( )}
<AxoSymbol.InlineGlyph symbol="chevron-[end]" label={null} /> >
{symbol != null && (
<AxoSymbol.InlineGlyph symbol={symbol} label={null} />
)}
{children}
{arrow && (
<AxoSymbol.InlineGlyph symbol="chevron-[end]" label={null} />
)}
</span>
{experimentalSpinner != null && (
<ExperimentalButtonSpinner
buttonVariant={variant}
buttonSize={size}
aria-label={experimentalSpinner['aria-label']}
/>
)} )}
</button> </button>
); );

View File

@@ -2,11 +2,10 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Button, ButtonVariant } from './Button.dom.js';
import { ConfirmDiscardDialog } from './ConfirmDiscardDialog.dom.js'; import { ConfirmDiscardDialog } from './ConfirmDiscardDialog.dom.js';
import type { LocalizerType } from '../types/Util.std.js'; import type { LocalizerType } from '../types/Util.std.js';
import { Modal } from './Modal.dom.js'; import { Modal } from './Modal.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
export type PropsType = { export type PropsType = {
hasChanges: boolean; hasChanges: boolean;
@@ -27,7 +26,9 @@ export function AvatarModalButtons({
return ( return (
<Modal.ButtonFooter> <Modal.ButtonFooter>
<Button <AxoButton.Root
variant="secondary"
size="large"
onClick={() => { onClick={() => {
if (hasChanges) { if (hasChanges) {
setConfirmDiscardAction(() => onCancel); setConfirmDiscardAction(() => onCancel);
@@ -35,13 +36,17 @@ export function AvatarModalButtons({
onCancel(); onCancel();
} }
}} }}
variant={ButtonVariant.Secondary}
> >
{i18n('icu:cancel')} {i18n('icu:cancel')}
</Button> </AxoButton.Root>
<Button disabled={!hasChanges} onClick={onSave}> <AxoButton.Root
variant="primary"
size="large"
disabled={!hasChanges}
onClick={onSave}
>
{i18n('icu:save')} {i18n('icu:save')}
</Button> </AxoButton.Root>
{confirmDiscardAction && ( {confirmDiscardAction && (
<ConfirmDiscardDialog <ConfirmDiscardDialog
i18n={i18n} i18n={i18n}

View File

@@ -16,8 +16,6 @@ import * as LocaleMatcher from '@formatjs/intl-localematcher';
import type { MutableRefObject, ReactNode } from 'react'; import type { MutableRefObject, ReactNode } from 'react';
import type { RowType } from '@signalapp/sqlcipher'; import type { RowType } from '@signalapp/sqlcipher';
import type { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js'; import type { BackupLevel } from '@signalapp/libsignal-client/zkgroup.js';
import { Button, ButtonVariant } from './Button.dom.js';
import { ChatColorPicker } from './ChatColorPicker.dom.js'; import { ChatColorPicker } from './ChatColorPicker.dom.js';
import { Checkbox } from './Checkbox.dom.js'; import { Checkbox } from './Checkbox.dom.js';
import { WidthBreakpoint } from './_util.std.js'; import { WidthBreakpoint } from './_util.std.js';
@@ -26,7 +24,6 @@ import { DisappearingTimeDialog } from './DisappearingTimeDialog.dom.js';
import { PhoneNumberDiscoverability } from '../util/phoneNumberDiscoverability.std.js'; import { PhoneNumberDiscoverability } from '../util/phoneNumberDiscoverability.std.js';
import { PhoneNumberSharingMode } from '../types/PhoneNumberSharingMode.std.js'; import { PhoneNumberSharingMode } from '../types/PhoneNumberSharingMode.std.js';
import { Select } from './Select.dom.js'; import { Select } from './Select.dom.js';
import { Spinner } from './Spinner.dom.js';
import { getCustomColorStyle } from '../util/getCustomColorStyle.dom.js'; import { getCustomColorStyle } from '../util/getCustomColorStyle.dom.js';
import { import {
DEFAULT_DURATIONS_IN_SECONDS, DEFAULT_DURATIONS_IN_SECONDS,
@@ -949,21 +946,23 @@ export function Preferences({
} }
modalFooter={ modalFooter={
<> <>
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
onClick={closeLanguageDialog} onClick={closeLanguageDialog}
> >
{i18n('icu:cancel')} {i18n('icu:cancel')}
</Button> </AxoButton.Root>
<Button <AxoButton.Root
variant={ButtonVariant.Primary} variant="primary"
size="large"
disabled={selectedLanguageLocale === localeOverride} disabled={selectedLanguageLocale === localeOverride}
onClick={() => { onClick={() => {
setLanguageDialog(LanguageDialog.Confirmation); setLanguageDialog(LanguageDialog.Confirmation);
}} }}
> >
{i18n('icu:Preferences__LanguageModal__Set')} {i18n('icu:Preferences__LanguageModal__Set')}
</Button> </AxoButton.Root>
</> </>
} }
> >
@@ -1210,7 +1209,7 @@ export function Preferences({
} }
right={ right={
<AxoButton.Root <AxoButton.Root
size="medium" size="large"
variant="secondary" variant="secondary"
onClick={() => { onClick={() => {
setSettingsLocation({ setSettingsLocation({
@@ -1254,12 +1253,13 @@ export function Preferences({
} }
right={ right={
<div className="Preferences__right-button"> <div className="Preferences__right-button">
<Button <AxoButton.Root
aria-label={ variant="secondary"
nowSyncing ? i18n('icu:syncing') : i18n('icu:syncNow') size="large"
}
aria-live="polite"
disabled={nowSyncing} disabled={nowSyncing}
experimentalSpinner={
nowSyncing ? { 'aria-label': i18n('icu:syncing') } : null
}
onClick={async () => { onClick={async () => {
setShowSyncFailed(false); setShowSyncFailed(false);
setNowSyncing(true); setNowSyncing(true);
@@ -1272,14 +1272,9 @@ export function Preferences({
setNowSyncing(false); setNowSyncing(false);
} }
}} }}
variant={ButtonVariant.SecondaryAffirmative}
> >
{nowSyncing ? ( {i18n('icu:syncNow')}
<Spinner svgSize="small" /> </AxoButton.Root>
) : (
i18n('icu:syncNow')
)}
</Button>
</div> </div>
} }
/> />
@@ -1558,11 +1553,9 @@ export function Preferences({
</> </>
} }
right={ right={
<Button <AxoButton.Root
testId="OnboardNotificationProfiles" variant="secondary"
aria-label={i18n('icu:NotificationProfiles--setup')} size="large"
aria-live="polite"
variant={ButtonVariant.SecondaryAffirmative}
onClick={() => onClick={() =>
setSettingsLocation({ setSettingsLocation({
page: SettingsPage.NotificationProfilesHome, page: SettingsPage.NotificationProfilesHome,
@@ -1570,7 +1563,7 @@ export function Preferences({
} }
> >
{i18n('icu:NotificationProfiles--setup')} {i18n('icu:NotificationProfiles--setup')}
</Button> </AxoButton.Root>
} }
/> />
</SettingsRow> </SettingsRow>
@@ -1610,12 +1603,13 @@ export function Preferences({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant="secondary"
size="large"
onClick={() => setSettingsLocation({ page: SettingsPage.PNP })} onClick={() => setSettingsLocation({ page: SettingsPage.PNP })}
variant={ButtonVariant.Secondary}
> >
{i18n('icu:Preferences__pnp__row--button')} {i18n('icu:Preferences__pnp__row--button')}
</Button> </AxoButton.Root>
</div> </div>
</FlowingControl> </FlowingControl>
</SettingsRow> </SettingsRow>
@@ -1767,20 +1761,21 @@ export function Preferences({
)} )}
> >
{hasStoriesDisabled ? ( {hasStoriesDisabled ? (
<Button <AxoButton.Root
onClick={() => onHasStoriesDisabledChanged(false)} onClick={() => onHasStoriesDisabledChanged(false)}
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
> >
{i18n('icu:Preferences__turn-stories-on')} {i18n('icu:Preferences__turn-stories-on')}
</Button> </AxoButton.Root>
) : ( ) : (
<Button <AxoButton.Root
className="Preferences__stories-off"
onClick={() => setConfirmStoriesOff(true)} onClick={() => setConfirmStoriesOff(true)}
variant={ButtonVariant.SecondaryDestructive} variant="subtle-destructive"
size="large"
> >
{i18n('icu:Preferences__turn-stories-off')} {i18n('icu:Preferences__turn-stories-off')}
</Button> </AxoButton.Root>
)} )}
</div> </div>
</FlowingControl> </FlowingControl>
@@ -1807,12 +1802,13 @@ export function Preferences({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant="subtle-destructive"
size="large"
onClick={() => setConfirmDelete(true)} onClick={() => setConfirmDelete(true)}
variant={ButtonVariant.SecondaryDestructive}
> >
{i18n('icu:clearDataButton')} {i18n('icu:clearDataButton')}
</Button> </AxoButton.Root>
</div> </div>
</FlowingControl> </FlowingControl>
</SettingsRow> </SettingsRow>

View File

@@ -16,7 +16,7 @@ import {
LightIconLabel, LightIconLabel,
SettingsRow, SettingsRow,
} from './PreferencesUtil.dom.js'; } from './PreferencesUtil.dom.js';
import { Button, ButtonVariant } from './Button.dom.js'; import { ButtonVariant } from './Button.dom.js';
import type { SettingsLocation } from '../types/Nav.std.js'; import type { SettingsLocation } from '../types/Nav.std.js';
import { SettingsPage } from '../types/Nav.std.js'; import { SettingsPage } from '../types/Nav.std.js';
import { I18n } from './I18n.dom.js'; import { I18n } from './I18n.dom.js';
@@ -27,6 +27,7 @@ import type {
PromptOSAuthResultType, PromptOSAuthResultType,
} from '../util/os/promptOSAuthMain.main.js'; } from '../util/os/promptOSAuthMain.main.js';
import { ConfirmationDialog } from './ConfirmationDialog.dom.js'; import { ConfirmationDialog } from './ConfirmationDialog.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
import { BackupLevel } from '../services/backups/types.std.js'; import { BackupLevel } from '../services/backups/types.std.js';
import { import {
BackupsDetailsPage, BackupsDetailsPage,
@@ -230,14 +231,15 @@ export function PreferencesBackups({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant="secondary"
size="large"
onClick={() => onClick={() =>
setSettingsLocation({ page: SettingsPage.BackupsDetails }) setSettingsLocation({ page: SettingsPage.BackupsDetails })
} }
variant={ButtonVariant.Secondary}
> >
{i18n('icu:Preferences__button--manage')} {i18n('icu:Preferences__button--manage')}
</Button> </AxoButton.Root>
</div> </div>
</FlowingControl> </FlowingControl>
</SettingsRow> </SettingsRow>
@@ -273,8 +275,9 @@ export function PreferencesBackups({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
className="Preferences--BackupsAuthButton" variant="secondary"
size="large"
disabled={isAuthPending} disabled={isAuthPending}
onClick={async () => { onClick={async () => {
setAuthError(undefined); setAuthError(undefined);
@@ -294,12 +297,11 @@ export function PreferencesBackups({
setSettingsLocation({ page: SettingsPage.LocalBackups }); setSettingsLocation({ page: SettingsPage.LocalBackups });
}} }}
variant={ButtonVariant.Secondary}
> >
{isLocalBackupsSetup {isLocalBackupsSetup
? i18n('icu:Preferences__button--manage') ? i18n('icu:Preferences__button--manage')
: i18n('icu:Preferences__button--set-up')} : i18n('icu:Preferences__button--set-up')}
</Button> </AxoButton.Root>
</div> </div>
</FlowingControl> </FlowingControl>
</SettingsRow> </SettingsRow>

View File

@@ -13,7 +13,6 @@ import React, {
import classNames from 'classnames'; import classNames from 'classnames';
import type { LocalizerType } from '../types/Util.std.js'; import type { LocalizerType } from '../types/Util.std.js';
import { useConfirmDiscard } from '../hooks/useConfirmDiscard.dom.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.dom.js';
import { Button, ButtonVariant } from './Button.dom.js';
import { import {
donationStateSchema, donationStateSchema,
ONE_TIME_DONATION_CONFIG_ID, ONE_TIME_DONATION_CONFIG_ID,
@@ -70,6 +69,7 @@ import { DonationsOfflineTooltip } from './conversation/DonationsOfflineTooltip.
import { DonateInputAmount } from './preferences/donations/DonateInputAmount.dom.js'; import { DonateInputAmount } from './preferences/donations/DonateInputAmount.dom.js';
import { Tooltip, TooltipPlacement } from './Tooltip.dom.js'; import { Tooltip, TooltipPlacement } from './Tooltip.dom.js';
import { offsetDistanceModifier } from '../util/popperUtil.std.js'; import { offsetDistanceModifier } from '../util/popperUtil.std.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
const SUPPORT_URL = 'https://support.signal.org/hc/requests/new?desktop'; const SUPPORT_URL = 'https://support.signal.org/hc/requests/new?desktop';
@@ -516,14 +516,14 @@ function AmountPicker({
} }
const continueButton = ( const continueButton = (
<Button <AxoButton.Root
className="PreferencesDonations__PrimaryButton" variant={isOnline ? 'primary' : 'secondary'}
size="large"
disabled={!isContinueEnabled} disabled={!isContinueEnabled}
onClick={handleContinueClicked} onClick={handleContinueClicked}
variant={isOnline ? ButtonVariant.Primary : ButtonVariant.Secondary}
> >
{i18n('icu:DonateFlow__continue')} {i18n('icu:DonateFlow__continue')}
</Button> </AxoButton.Root>
); );
let continueButtonWithTooltip: JSX.Element | undefined; let continueButtonWithTooltip: JSX.Element | undefined;
@@ -759,16 +759,16 @@ function CardForm({
}, [handleDonateClicked, isDonateDisabled]); }, [handleDonateClicked, isDonateDisabled]);
const donateButton = ( const donateButton = (
<Button <AxoButton.Root
className="PreferencesDonations__PrimaryButton"
disabled={isDonateDisabled} disabled={isDonateDisabled}
onClick={handleDonateClicked} onClick={handleDonateClicked}
variant={isOnline ? ButtonVariant.Primary : ButtonVariant.Secondary} variant={isOnline ? 'primary' : 'secondary'}
size="large"
> >
{i18n('icu:PreferencesDonations__donate-button-with-amount', { {i18n('icu:PreferencesDonations__donate-button-with-amount', {
formattedCurrencyAmount, formattedCurrencyAmount,
})} })}
</Button> </AxoButton.Root>
); );
return ( return (

View File

@@ -55,6 +55,8 @@ import type { AvatarUpdateOptionsType } from '../types/Avatar.std.js';
import { drop } from '../util/drop.std.js'; import { drop } from '../util/drop.std.js';
import { DonationsOfflineTooltip } from './conversation/DonationsOfflineTooltip.dom.js'; import { DonationsOfflineTooltip } from './conversation/DonationsOfflineTooltip.dom.js';
import { getInProgressDonation } from '../util/donations.dom.js'; import { getInProgressDonation } from '../util/donations.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
import { tw } from '../axo/tw.dom.js';
const { groupBy, sortBy } = lodash; const { groupBy, sortBy } = lodash;
@@ -234,15 +236,16 @@ function DonationsHome({
const hasReceipts = donationReceipts.length > 0; const hasReceipts = donationReceipts.length > 0;
const donateButton = ( const donateButton = (
<Button <span className={tw('mb-8')}>
className="PreferencesDonations__PrimaryButton PreferencesDonations__donate-button" <AxoButton.Root
disabled={!isOnline} variant={isOnline ? 'primary' : 'secondary'}
variant={isOnline ? ButtonVariant.Primary : ButtonVariant.Secondary} size="medium"
size={ButtonSize.Medium} disabled={!isOnline}
onClick={handleDonateButtonClicked} onClick={handleDonateButtonClicked}
> >
{i18n('icu:PreferencesDonations__donate-button')} {i18n('icu:PreferencesDonations__donate-button')}
</Button> </AxoButton.Root>
</span>
); );
return ( return (

View File

@@ -12,8 +12,6 @@ import { formatFileSize } from '../util/formatFileSize.std.js';
import { SECOND } from '../util/durations/index.std.js'; import { SECOND } from '../util/durations/index.std.js';
import type { ValidationResultType as BackupValidationResultType } from '../services/backups/index.preload.js'; import type { ValidationResultType as BackupValidationResultType } from '../services/backups/index.preload.js';
import { SettingsRow, FlowingSettingsControl } from './PreferencesUtil.dom.js'; import { SettingsRow, FlowingSettingsControl } from './PreferencesUtil.dom.js';
import { Button, ButtonVariant } from './Button.dom.js';
import { Spinner } from './Spinner.dom.js';
import type { MessageCountBySchemaVersionType } from '../sql/Interface.std.js'; import type { MessageCountBySchemaVersionType } from '../sql/Interface.std.js';
import type { MessageAttributesType } from '../model-types.d.ts'; import type { MessageAttributesType } from '../model-types.d.ts';
import type { DonationReceipt } from '../types/Donations.std.js'; import type { DonationReceipt } from '../types/Donations.std.js';
@@ -21,6 +19,7 @@ import { createLogger } from '../logging/log.std.js';
import { isStagingServer } from '../util/isStagingServer.dom.js'; import { isStagingServer } from '../util/isStagingServer.dom.js';
import { getHumanDonationAmount } from '../util/currency.dom.js'; import { getHumanDonationAmount } from '../util/currency.dom.js';
import { AutoSizeTextArea } from './AutoSizeTextArea.dom.js'; import { AutoSizeTextArea } from './AutoSizeTextArea.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
const log = createLogger('PreferencesInternal'); const log = createLogger('PreferencesInternal');
@@ -240,17 +239,19 @@ export function PreferencesInternal({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
onClick={validateBackup} onClick={validateBackup}
disabled={isValidationPending} disabled={isValidationPending}
experimentalSpinner={
isValidationPending
? { 'aria-label': i18n('icu:loading') }
: null
}
> >
{isValidationPending ? ( {i18n('icu:Preferences__internal__validate-backup')}
<Spinner size="22px" svgSize="small" /> </AxoButton.Root>
) : (
i18n('icu:Preferences__internal__validate-backup')
)}
</Button>
</div> </div>
</FlowingSettingsControl> </FlowingSettingsControl>
@@ -274,17 +275,17 @@ export function PreferencesInternal({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
onClick={exportLocalBackup} onClick={exportLocalBackup}
disabled={isExportPending} disabled={isExportPending}
experimentalSpinner={
isExportPending ? { 'aria-label': i18n('icu:loading') } : null
}
> >
{isExportPending ? ( {i18n('icu:Preferences__internal__export-local-backup')}
<Spinner size="22px" svgSize="small" /> </AxoButton.Root>
) : (
i18n('icu:Preferences__internal__export-local-backup')
)}
</Button>
</div> </div>
</FlowingSettingsControl> </FlowingSettingsControl>
@@ -306,8 +307,9 @@ export function PreferencesInternal({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
onClick={async () => { onClick={async () => {
setMessageCountBySchemaVersion( setMessageCountBySchemaVersion(
await getMessageCountBySchemaVersion() await getMessageCountBySchemaVersion()
@@ -317,7 +319,7 @@ export function PreferencesInternal({
disabled={isExportPending} disabled={isExportPending}
> >
Fetch data Fetch data
</Button> </AxoButton.Root>
</div> </div>
</FlowingSettingsControl> </FlowingSettingsControl>
@@ -400,12 +402,13 @@ export function PreferencesInternal({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
onClick={handleAddTestReceipt} onClick={handleAddTestReceipt}
> >
Add Test Receipt Add Test Receipt
</Button> </AxoButton.Root>
</div> </div>
</FlowingSettingsControl> </FlowingSettingsControl>
@@ -450,17 +453,19 @@ export function PreferencesInternal({
{receipt.id.substring(0, 8)}... {receipt.id.substring(0, 8)}...
</td> </td>
<td style={{ padding: '8px' }}> <td style={{ padding: '8px' }}>
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} variant="secondary"
size="large"
onClick={() => handleGenerateReceipt(receipt)} onClick={() => handleGenerateReceipt(receipt)}
disabled={isGeneratingReceipt} disabled={isGeneratingReceipt}
experimentalSpinner={
isGeneratingReceipt
? { 'aria-label': i18n('icu:loading') }
: null
}
> >
{isGeneratingReceipt ? ( Download
<Spinner size="16px" svgSize="small" /> </AxoButton.Root>
) : (
'Download'
)}
</Button>
</td> </td>
</tr> </tr>
))} ))}
@@ -486,12 +491,13 @@ export function PreferencesInternal({
placeholder="SELECT * FROM items" placeholder="SELECT * FROM items"
moduleClassName="Preferences__ReadonlySqlPlayground__Textarea" moduleClassName="Preferences__ReadonlySqlPlayground__Textarea"
/> />
<Button <AxoButton.Root
variant={ButtonVariant.Destructive} variant="destructive"
size="large"
onClick={handleReadOnlySqlInputSubmit} onClick={handleReadOnlySqlInputSubmit}
> >
Run Query Run Query
</Button> </AxoButton.Root>
{readOnlySqlResults != null && ( {readOnlySqlResults != null && (
<AutoSizeTextArea <AutoSizeTextArea
i18n={i18n} i18n={i18n}

View File

@@ -17,7 +17,7 @@ import {
FlowingSettingsControl as FlowingControl, FlowingSettingsControl as FlowingControl,
SettingsRow, SettingsRow,
} from './PreferencesUtil.dom.js'; } from './PreferencesUtil.dom.js';
import { Button, ButtonSize, ButtonVariant } from './Button.dom.js'; import { ButtonVariant } from './Button.dom.js';
import { import {
getOSAuthErrorString, getOSAuthErrorString,
SIGNAL_BACKUPS_LEARN_MORE_URL, SIGNAL_BACKUPS_LEARN_MORE_URL,
@@ -34,6 +34,7 @@ import type {
PromptOSAuthResultType, PromptOSAuthResultType,
} from '../util/os/promptOSAuthMain.main.js'; } from '../util/os/promptOSAuthMain.main.js';
import { ConfirmationDialog } from './ConfirmationDialog.dom.js'; import { ConfirmationDialog } from './ConfirmationDialog.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
const { noop } = lodash; const { noop } = lodash;
@@ -129,12 +130,13 @@ export function PreferencesLocalBackups({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
variant="secondary"
size="large"
onClick={pickLocalBackupFolder} onClick={pickLocalBackupFolder}
variant={ButtonVariant.Secondary}
> >
{i18n('icu:Preferences__local-backups-folder__change')} {i18n('icu:Preferences__local-backups-folder__change')}
</Button> </AxoButton.Root>
</div> </div>
</FlowingControl> </FlowingControl>
<FlowingControl> <FlowingControl>
@@ -153,9 +155,13 @@ export function PreferencesLocalBackups({
'Preferences__one-third-flow--align-right' 'Preferences__one-third-flow--align-right'
)} )}
> >
<Button <AxoButton.Root
className="Preferences--BackupsAuthButton" variant="secondary"
size="large"
disabled={isAuthPending} disabled={isAuthPending}
experimentalSpinner={
isAuthPending ? { 'aria-label': i18n('icu:loading') } : null
}
onClick={async () => { onClick={async () => {
setAuthError(undefined); setAuthError(undefined);
@@ -173,10 +179,9 @@ export function PreferencesLocalBackups({
setIsAuthPending(false); setIsAuthPending(false);
} }
}} }}
variant={ButtonVariant.Secondary}
> >
{i18n('icu:Preferences__view-key')} {i18n('icu:Preferences__view-key')}
</Button> </AxoButton.Root>
</div> </div>
</FlowingControl> </FlowingControl>
</SettingsRow> </SettingsRow>
@@ -226,9 +231,13 @@ function LocalBackupsSetupFolderPicker({
<div className="Preferences--LocalBackupsSetupScreenBody Preferences--LocalBackupsSetupScreenBody--folder"> <div className="Preferences--LocalBackupsSetupScreenBody Preferences--LocalBackupsSetupScreenBody--folder">
{i18n('icu:Preferences--local-backups-setup-folder-description')} {i18n('icu:Preferences--local-backups-setup-folder-description')}
</div> </div>
<Button onClick={pickLocalBackupFolder} variant={ButtonVariant.Primary}> <AxoButton.Root
variant="primary"
size="large"
onClick={pickLocalBackupFolder}
>
{i18n('icu:Preferences__button--choose-folder')} {i18n('icu:Preferences__button--choose-folder')}
</Button> </AxoButton.Root>
</div> </div>
</div> </div>
); );
@@ -295,23 +304,23 @@ function LocalBackupsBackupKeyViewer({
); );
if (step === 'view') { if (step === 'view') {
footerRight = ( footerRight = (
<Button <AxoButton.Root
className="Preferences--LocalBackupsSetupScreenFooterButton" variant="primary"
size="large"
onClick={() => setStep('confirm')} onClick={() => setStep('confirm')}
variant={ButtonVariant.Primary}
> >
{i18n('icu:Preferences--local-backups-setup-next')} {i18n('icu:Preferences--local-backups-setup-next')}
</Button> </AxoButton.Root>
); );
} else { } else {
footerRight = ( footerRight = (
<Button <AxoButton.Root
className="Preferences--LocalBackupsSetupScreenFooterButton" variant="primary"
size="large"
onClick={onBackupKeyViewed} onClick={onBackupKeyViewed}
variant={ButtonVariant.Primary}
> >
{i18n('icu:Preferences--local-backups-view-backup-key-done')} {i18n('icu:Preferences--local-backups-view-backup-key-done')}
</Button> </AxoButton.Root>
); );
} }
} else { } else {
@@ -320,23 +329,23 @@ function LocalBackupsBackupKeyViewer({
'icu:Preferences--local-backups-confirm-backup-key-description' 'icu:Preferences--local-backups-confirm-backup-key-description'
); );
footerLeft = ( footerLeft = (
<button <AxoButton.Root
className="Preferences--LocalBackupsSetupScreenFooterSeeKeyButton" variant="borderless-primary"
size="large"
onClick={() => setStep('view')} onClick={() => setStep('view')}
type="button"
> >
{i18n('icu:Preferences--local-backups-see-backup-key-again')} {i18n('icu:Preferences--local-backups-see-backup-key-again')}
</button> </AxoButton.Root>
); );
footerRight = ( footerRight = (
<Button <AxoButton.Root
className="Preferences--LocalBackupsSetupScreenFooterButton" variant="primary"
size="large"
disabled={!isBackupKeyConfirmed} disabled={!isBackupKeyConfirmed}
onClick={() => setStep('caution')} onClick={() => setStep('caution')}
variant={ButtonVariant.Primary}
> >
{i18n('icu:Preferences--local-backups-setup-next')} {i18n('icu:Preferences--local-backups-setup-next')}
</Button> </AxoButton.Root>
); );
} }
@@ -348,14 +357,15 @@ function LocalBackupsBackupKeyViewer({
modalName="CallingAdhocCallInfo.UnknownContactInfo" modalName="CallingAdhocCallInfo.UnknownContactInfo"
moduleClassName="Preferences--LocalBackupsConfirmKeyModal" moduleClassName="Preferences--LocalBackupsConfirmKeyModal"
modalFooter={ modalFooter={
<Button <AxoButton.Root
className="Preferences--LocalBackupsConfirmKeyModalButton" variant="primary"
size="large"
onClick={onBackupKeyViewed} onClick={onBackupKeyViewed}
> >
{i18n( {i18n(
'icu:Preferences__local-backups-confirm-key-modal-continue' 'icu:Preferences__local-backups-confirm-key-modal-continue'
)} )}
</Button> </AxoButton.Root>
} }
onClose={() => setStep('confirm')} onClose={() => setStep('confirm')}
padded={false} padded={false}
@@ -391,14 +401,14 @@ function LocalBackupsBackupKeyViewer({
</div> </div>
{isStepViewOrReference && ( {isStepViewOrReference && (
<div className="Preferences--LocalBackupsSetupScreenPaneContent"> <div className="Preferences--LocalBackupsSetupScreenPaneContent">
<Button <AxoButton.Root
className="Preferences--LocalBackupsSetupScreenCopyButton" variant="secondary"
size="small"
symbol="copy"
onClick={onCopyBackupKey} onClick={onCopyBackupKey}
size={ButtonSize.Small}
variant={ButtonVariant.Secondary}
> >
{i18n('icu:Preferences__local-backups-copy-key')} {i18n('icu:Preferences__local-backups-copy-key')}
</Button> </AxoButton.Root>
</div> </div>
)} )}
</div> </div>

View File

@@ -15,7 +15,7 @@ import type { MutableRefObject } from 'react';
import { AvatarColors } from '../types/Colors.std.js'; import { AvatarColors } from '../types/Colors.std.js';
import { AvatarEditor } from './AvatarEditor.dom.js'; import { AvatarEditor } from './AvatarEditor.dom.js';
import { AvatarPreview } from './AvatarPreview.dom.js'; import { AvatarPreview } from './AvatarPreview.dom.js';
import { Button, ButtonVariant } from './Button.dom.js'; import { ButtonVariant } from './Button.dom.js';
import { Input } from './Input.dom.js'; import { Input } from './Input.dom.js';
import { PanelRow } from './conversation/conversation-details/PanelRow.dom.js'; import { PanelRow } from './conversation/conversation-details/PanelRow.dom.js';
import { UsernameEditState } from '../state/ducks/usernameEnums.std.js'; import { UsernameEditState } from '../state/ducks/usernameEnums.std.js';
@@ -68,6 +68,7 @@ import type { ShowToastAction } from '../state/ducks/toast.preload.js';
import type { EmojiParentKey, EmojiVariantKey } from './fun/data/emojis.std.js'; import type { EmojiParentKey, EmojiVariantKey } from './fun/data/emojis.std.js';
import type { FunEmojiSelection } from './fun/panels/FunPanelEmojis.dom.js'; import type { FunEmojiSelection } from './fun/panels/FunPanelEmojis.dom.js';
import { useConfirmDiscard } from '../hooks/useConfirmDiscard.dom.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
type ProfileEditorData = { type ProfileEditorData = {
firstName: string; firstName: string;
@@ -407,10 +408,12 @@ export function ProfileEditor({
value={stagedProfile.familyName} value={stagedProfile.familyName}
/> />
<div className="ProfileEditor__button-footer"> <div className="ProfileEditor__button-footer">
<Button onClick={handleBack} variant={ButtonVariant.Secondary}> <AxoButton.Root variant="secondary" size="large" onClick={handleBack}>
{i18n('icu:cancel')} {i18n('icu:cancel')}
</Button> </AxoButton.Root>
<Button <AxoButton.Root
variant="primary"
size="large"
disabled={shouldDisableSave} disabled={shouldDisableSave}
onClick={() => { onClick={() => {
if (!stagedProfile.firstName) { if (!stagedProfile.firstName) {
@@ -428,7 +431,7 @@ export function ProfileEditor({
}} }}
> >
{i18n('icu:save')} {i18n('icu:save')}
</Button> </AxoButton.Root>
</div> </div>
</> </>
); );
@@ -513,10 +516,12 @@ export function ProfileEditor({
})} })}
<div className="ProfileEditor__button-footer"> <div className="ProfileEditor__button-footer">
<Button onClick={handleBack} variant={ButtonVariant.Secondary}> <AxoButton.Root variant="secondary" size="large" onClick={handleBack}>
{i18n('icu:cancel')} {i18n('icu:cancel')}
</Button> </AxoButton.Root>
<Button <AxoButton.Root
variant="primary"
size="large"
disabled={shouldDisableSave} disabled={shouldDisableSave}
onClick={() => { onClick={() => {
setFullBio({ setFullBio({
@@ -531,7 +536,7 @@ export function ProfileEditor({
}} }}
> >
{i18n('icu:save')} {i18n('icu:save')}
</Button> </AxoButton.Root>
</div> </div>
</> </>
); );
@@ -714,15 +719,15 @@ export function ProfileEditor({
}} }}
/> />
<div className="ProfileEditor__EditPhotoContainer"> <div className="ProfileEditor__EditPhotoContainer">
<Button <AxoButton.Root
onClick={() => { onClick={() => {
setEditState(ProfileEditorPage.BetterAvatar); setEditState(ProfileEditorPage.BetterAvatar);
}} }}
variant={ButtonVariant.Secondary} variant="secondary"
className="ProfileEditor__EditPhoto" size="small"
> >
{i18n('icu:ProfileEditor--edit-photo')} {i18n('icu:ProfileEditor--edit-photo')}
</Button> </AxoButton.Root>
</div> </div>
<PanelRow <PanelRow
className="ProfileEditor__row" className="ProfileEditor__row"

View File

@@ -43,6 +43,26 @@ const SpinnerVariants = {
bg: tw('stroke-fill-secondary'), bg: tw('stroke-fill-secondary'),
fg: tw('stroke-border-selected'), fg: tw('stroke-border-selected'),
}, },
'axo-button-spinner-secondary': {
bg: tw('stroke-none'),
fg: tw('stroke-label-primary'),
},
'axo-button-spinner-on-color': {
bg: tw('stroke-none'),
fg: tw('stroke-label-primary-on-color'),
},
'axo-button-spinner-primary': {
bg: tw('stroke-none'),
fg: tw('stroke-color-label-primary'),
},
'axo-button-spinner-affirmative': {
bg: tw('stroke-none'),
fg: tw('stroke-color-label-affirmative'),
},
'axo-button-spinner-destructive': {
bg: tw('stroke-none'),
fg: tw('stroke-color-label-destructive'),
},
} as const satisfies Record<string, SpinnerVariantStyles>; } as const satisfies Record<string, SpinnerVariantStyles>;
export type SpinnerVariant = keyof typeof SpinnerVariants; export type SpinnerVariant = keyof typeof SpinnerVariants;
@@ -81,6 +101,7 @@ export function SpinnerV2({
return ( return (
<svg <svg
className={tw('fill-none')} className={tw('fill-none')}
aria-label={ariaLabel}
width={sizeInPixels} width={sizeInPixels}
height={sizeInPixels} height={sizeInPixels}
> >

View File

@@ -26,7 +26,6 @@ import {
} from '../state/ducks/usernameEnums.std.js'; } from '../state/ducks/usernameEnums.std.js';
import type { ReserveUsernameOptionsType } from '../state/ducks/username.preload.js'; import type { ReserveUsernameOptionsType } from '../state/ducks/username.preload.js';
import type { ShowToastAction } from '../state/ducks/toast.preload.js'; import type { ShowToastAction } from '../state/ducks/toast.preload.js';
import { AutoSizeInput } from './AutoSizeInput.dom.js'; import { AutoSizeInput } from './AutoSizeInput.dom.js';
import { ConfirmationDialog } from './ConfirmationDialog.dom.js'; import { ConfirmationDialog } from './ConfirmationDialog.dom.js';
import { Input } from './Input.dom.js'; import { Input } from './Input.dom.js';
@@ -34,6 +33,7 @@ import { Spinner } from './Spinner.dom.js';
import { Modal } from './Modal.dom.js'; import { Modal } from './Modal.dom.js';
import { Button, ButtonVariant } from './Button.dom.js'; import { Button, ButtonVariant } from './Button.dom.js';
import { useConfirmDiscard } from '../hooks/useConfirmDiscard.dom.js'; import { useConfirmDiscard } from '../hooks/useConfirmDiscard.dom.js';
import { AxoButton } from '../axo/AxoButton.dom.js';
const { noop } = lodash; const { noop } = lodash;
@@ -382,20 +382,25 @@ export function UsernameEditor({
</button> </button>
</div> </div>
<div className="UsernameEditor__button-footer"> <div className="UsernameEditor__button-footer">
<Button <AxoButton.Root
variant="secondary"
size="large"
disabled={isConfirming} disabled={isConfirming}
onClick={onCancel} onClick={onCancel}
variant={ButtonVariant.Secondary}
> >
{i18n('icu:cancel')} {i18n('icu:cancel')}
</Button> </AxoButton.Root>
<Button disabled={!canSave} onClick={onSave}> <AxoButton.Root
{isConfirming ? ( variant="primary"
<Spinner size="20px" svgSize="small" direction="on-avatar" /> size="large"
) : ( disabled={!canSave}
i18n('icu:save') onClick={onSave}
)} experimentalSpinner={
</Button> isConfirming ? { 'aria-label': i18n('icu:loading') } : null
}
>
{i18n('icu:save')}
</AxoButton.Root>
</div> </div>
{confirmDiscardModal} {confirmDiscardModal}

View File

@@ -8,7 +8,6 @@ import type { PreferredBadgeSelectorType } from '../../../state/selectors/badges
import type { LocalizerType } from '../../../types/I18N.std.js'; import type { LocalizerType } from '../../../types/I18N.std.js';
import type { ThemeType } from '../../../types/Util.std.js'; import type { ThemeType } from '../../../types/Util.std.js';
import { Input } from '../../Input.dom.js'; import { Input } from '../../Input.dom.js';
import { Button, ButtonVariant } from '../../Button.dom.js';
import { ConfirmationDialog } from '../../ConfirmationDialog.dom.js'; import { ConfirmationDialog } from '../../ConfirmationDialog.dom.js';
import type { ChatFolderSelection } from '../PreferencesSelectChatsDialog.dom.js'; import type { ChatFolderSelection } from '../PreferencesSelectChatsDialog.dom.js';
import { SettingsControl, SettingsRow } from '../../PreferencesUtil.dom.js'; import { SettingsControl, SettingsRow } from '../../PreferencesUtil.dom.js';
@@ -47,6 +46,7 @@ import {
ItemContent, ItemContent,
ItemTitle, ItemTitle,
} from './PreferencesChatFolderItems.dom.js'; } from './PreferencesChatFolderItems.dom.js';
import { AxoButton } from '../../../axo/AxoButton.dom.js';
export type PreferencesEditChatFolderPageProps = Readonly<{ export type PreferencesEditChatFolderPageProps = Readonly<{
i18n: LocalizerType; i18n: LocalizerType;
@@ -550,19 +550,21 @@ export function PreferencesEditChatFolderPage(
title={i18n('icu:Preferences__EditChatFolderPage__Title')} title={i18n('icu:Preferences__EditChatFolderPage__Title')}
actions={ actions={
<> <>
<Button <AxoButton.Root
variant={ButtonVariant.Secondary} size="large"
variant="secondary"
onClick={handleDiscardAndBack} onClick={handleDiscardAndBack}
> >
{i18n('icu:Preferences__EditChatFolderPage__CancelButton')} {i18n('icu:Preferences__EditChatFolderPage__CancelButton')}
</Button> </AxoButton.Root>
<Button <AxoButton.Root
variant={ButtonVariant.Primary} size="large"
variant="primary"
onClick={handleSaveChangesAndBack} onClick={handleSaveChangesAndBack}
disabled={!(isChanged && isValid)} disabled={!(isChanged && isValid)}
> >
{i18n('icu:Preferences__EditChatFolderPage__SaveButton')} {i18n('icu:Preferences__EditChatFolderPage__SaveButton')}
</Button> </AxoButton.Root>
</> </>
} }
/> />

View File

@@ -214,7 +214,7 @@ describe('pnp/username', function (this: Mocha.Suite) {
debug('saving username'); debug('saving username');
let state = await phone.expectStorageState('consistency check'); let state = await phone.expectStorageState('consistency check');
await profileEditor.locator('.module-Button >> "Save"').click(); await profileEditor.getByRole('button', { name: 'Save' }).click();
debug('checking the username is saved'); debug('checking the username is saved');
{ {

View File

@@ -72,7 +72,7 @@ describe('storage service/notification profiles', function (this: Mocha.Suite) {
const profileName = 'NewProfile'; const profileName = 'NewProfile';
debug('Starting Notification Profiles onboarding'); debug('Starting Notification Profiles onboarding');
await window.getByTestId('OnboardNotificationProfiles').click(); await window.getByRole('button', { name: 'Set up' }).click();
debug('Dismiss onboarding dialog'); debug('Dismiss onboarding dialog');
await window.getByRole('button', { name: 'Continue' }).click(); await window.getByRole('button', { name: 'Continue' }).click();
@@ -207,7 +207,7 @@ describe('storage service/notification profiles', function (this: Mocha.Suite) {
await window.getByRole('button', { name: 'Notifications' }).click(); await window.getByRole('button', { name: 'Notifications' }).click();
debug('Open Notification Profiles list page'); debug('Open Notification Profiles list page');
await window.getByTestId('OnboardNotificationProfiles').click(); await window.getByRole('button', { name: 'Set up' }).click();
debug('Dismiss onboarding dialog'); debug('Dismiss onboarding dialog');
await window.getByRole('button', { name: 'Continue' }).click(); await window.getByRole('button', { name: 'Continue' }).click();