Init AxoSwitch/AxoCheckbox & forced-colors mode

This commit is contained in:
Jamie Kyle
2025-09-10 13:25:46 -07:00
committed by GitHub
parent 53d1650844
commit 58f2dd94d2
27 changed files with 622 additions and 290 deletions

View File

@@ -254,6 +254,43 @@ const typescriptRules = {
'import/no-cycle': 'off',
};
const TAILWIND_REPLACEMENTS = [
// inset
{ pattern: 'left-*', fix: 'start-*' },
{ pattern: 'right-*', fix: 'end-*' },
// margin
{ pattern: 'ml-*', fix: 'ms-*' },
{ pattern: 'mr-*', fix: 'me-*' },
// padding
{ pattern: 'pl-*', fix: 'ps-*' },
{ pattern: 'pr-*', fix: 'pe-*' },
// border
{ pattern: 'border-l-*', fix: 'border-s-*' },
{ pattern: 'border-r-*', fix: 'border-e-*' },
// border-radius
{ pattern: 'rounded-l', fix: 'rounded-s' },
{ pattern: 'rounded-r', fix: 'rounded-e' },
{ pattern: 'rounded-tl', fix: 'rounded-ss' },
{ pattern: 'rounded-tr', fix: 'rounded-se' },
{ pattern: 'rounded-bl', fix: 'rounded-es' },
{ pattern: 'rounded-br', fix: 'rounded-ee' },
{ pattern: 'rounded-l-*', fix: 'rounded-s-*' },
{ pattern: 'rounded-r-*', fix: 'rounded-e-*' },
{ pattern: 'rounded-tl-*', fix: 'rounded-ss-*' },
{ pattern: 'rounded-tr-*', fix: 'rounded-se-*' },
{ pattern: 'rounded-bl-*', fix: 'rounded-es-*' },
{ pattern: 'rounded-br-*', fix: 'rounded-ee-*' },
// text-align
{ pattern: 'text-left', fix: 'text-start' },
{ pattern: 'text-right', fix: 'text-end' },
// float
{ pattern: 'float-left', fix: 'float-start' },
{ pattern: 'float-right', fix: 'float-end' },
// clear
{ pattern: 'clear-left', fix: 'clear-start' },
{ pattern: 'clear-right', fix: 'clear-end' },
];
module.exports = {
root: true,
settings: {
@@ -377,6 +414,15 @@ module.exports = {
pattern: '^\\*+:.*', // ex: "*:mx-0",
message: 'No child variants',
},
...TAILWIND_REPLACEMENTS.map(item => {
const pattern = item.pattern.replace('*', '(.*)');
const fix = item.fix.replace('*', '$2');
return {
message: `Use logical property ${item.fix} instead of ${item.pattern}`,
pattern: `^(.*:)?${pattern}$`,
fix: `$1${fix}`,
};
}),
],
},
],

View File

@@ -3,17 +3,11 @@
/** @type {import("prettier").Config} */
module.exports = {
plugins: ['prettier-plugin-tailwindcss'],
singleQuote: true,
arrowParens: 'avoid',
trailingComma: 'es5',
overrides: [
{
files: ['./ts/axo/**.tsx'],
plugins: ['prettier-plugin-tailwindcss'],
options: {
tailwindStylesheet: './stylesheets/tailwind-config.css',
tailwindFunctions: ['tw'],
},
},
],
tailwindAttributes: [],
};

View File

@@ -17,6 +17,7 @@ import { HourCyclePreference } from '../ts/types/I18N';
import { Provider } from 'react-redux';
import { Store, combineReducers, createStore } from 'redux';
import { Globals } from '@react-spring/web';
import { AxoProvider } from '../ts/axo/AxoProvider';
import { StateType } from '../ts/state/reducer';
import {
ScrollerLockContext,
@@ -254,8 +255,17 @@ function withFunProvider(Story, context) {
);
}
function withAxoProvider(Story, context) {
return (
<AxoProvider dir={context.globals.direction ?? 'ltr'}>
<Story {...context} />
</AxoProvider>
);
}
export const decorators = [
withStrictMode,
withAxoProvider,
withGlobalTypesProvider,
withMockStoreProvider,
withScrollLockProvider,

View File

@@ -6,9 +6,9 @@
*/
@custom-variant dark (&:where(.dark-theme, .dark-theme *));
@custom-variant hovered (&:hover:not(:disabled));
@custom-variant pressed (&:active:not(:disabled));
@custom-variant focused (.keyboard-mode &:focus);
@custom-variant hovered (&:where(:hover:not(:disabled)));
@custom-variant pressed (&:where(:active:not(:disabled)));
@custom-variant focused (:where(.keyboard-mode) &:where(:focus));
/**
* Color
@@ -325,6 +325,9 @@
/* box-shadow: inset */
--inset-shadow-*: initial; /* reset defaults */
--inset-shadow-on-color:
inset 0 0.5px 1px 0 --alpha(#000 / 12%);
/* filter: drop-shadow() */
--drop-shadow-*: initial; /* reset defaults */
--drop-shadow-elevation-0: var(--shadow-elevation-0);

View File

@@ -11,7 +11,8 @@ const Namespace = 'AxoButton';
const baseAxoButtonStyles = tw(
'flex items-center-safe justify-center-safe gap-1 truncate 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'
);
const AxoButtonTypes = {

View File

@@ -0,0 +1,40 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useState } from 'react';
import type { Meta } from '@storybook/react';
import { AxoCheckbox } from './AxoCheckbox';
import { tw } from './tw';
export default {
title: 'Axo/AxoCheckbox',
} satisfies Meta;
function Template(props: {
label: string;
defaultChecked: boolean;
disabled?: boolean;
}): JSX.Element {
const [checked, setChecked] = useState(props.defaultChecked);
return (
<label className={tw('my-2 flex items-center gap-2')}>
<AxoCheckbox
checked={checked}
onCheckedChange={setChecked}
disabled={props.disabled}
/>
{props.label}
</label>
);
}
export function Basic(): JSX.Element {
return (
<>
<h1 className={tw('type-title-large')}>AxoCheckbox</h1>
<Template label="Unchecked" defaultChecked={false} />
<Template label="Checked" defaultChecked />
<Template label="Unchecked+Disabled" defaultChecked={false} disabled />
<Template label="Checked+Disabled" defaultChecked disabled />
</>
);
}

57
ts/axo/AxoCheckbox.tsx Normal file
View File

@@ -0,0 +1,57 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { memo } from 'react';
import { Checkbox } from 'radix-ui';
import { AxoSymbol } from './AxoSymbol';
import { tw } from './tw';
const Namespace = 'AxoCheckbox';
type AxoCheckboxProps = Readonly<{
id?: string;
checked: boolean;
onCheckedChange: (nextChecked: boolean) => void;
disabled?: boolean;
required?: boolean;
}>;
// eslint-disable-next-line import/export
export const AxoCheckbox = memo((props: AxoCheckboxProps) => {
return (
<Checkbox.Root
id={props.id}
checked={props.checked}
onCheckedChange={props.onCheckedChange}
disabled={props.disabled}
required={props.required}
className={tw(
'flex size-5 items-center justify-center rounded-full',
'border border-border-primary inset-shadow-on-color',
'data-[state=unchecked]:bg-fill-primary',
'data-[state=unchecked]:pressed:bg-fill-primary-pressed',
'data-[state=checked]:bg-color-fill-primary',
'data-[state=checked]:pressed:bg-color-fill-primary-pressed',
'data-[disabled]:border-border-secondary',
'outline-0 outline-border-focused focused:outline-[2.5px]',
'overflow-hidden'
)}
>
<Checkbox.Indicator
className={tw(
'data-[state=checked]:text-label-primary-on-color',
'data-[state=checked]:data-[disabled]:text-label-disabled-on-color'
)}
>
<AxoSymbol.Icon symbol="check" size={14} label={null} />
</Checkbox.Indicator>
</Checkbox.Root>
);
});
AxoCheckbox.displayName = `${Namespace}`;
// eslint-disable-next-line max-len
// eslint-disable-next-line @typescript-eslint/no-namespace, @typescript-eslint/no-redeclare, import/export
export namespace AxoCheckbox {
export type Props = AxoCheckboxProps;
}

View File

@@ -217,7 +217,7 @@ export namespace AxoContextMenu {
</AxoBaseMenu.ItemLeadingSlot>
<AxoBaseMenu.ItemContentSlot>
{props.symbol && (
<span className={tw('mr-2')}>
<span className={tw('me-2')}>
<AxoBaseMenu.ItemSymbol symbol={props.symbol} />
</span>
)}
@@ -352,7 +352,7 @@ export namespace AxoContextMenu {
)}
<AxoBaseMenu.ItemContentSlot>
<AxoBaseMenu.ItemText>{props.children}</AxoBaseMenu.ItemText>
<span className={tw('ml-auto')}>
<span className={tw('ms-auto')}>
<AxoSymbol.Icon size={14} symbol="chevron-[end]" label={null} />
</span>
</AxoBaseMenu.ItemContentSlot>

View File

@@ -231,7 +231,7 @@ export namespace AxoDropdownMenu {
</AxoBaseMenu.ItemLeadingSlot>
<AxoBaseMenu.ItemContentSlot>
{props.symbol && (
<span className={tw('mr-2')}>
<span className={tw('me-2')}>
<AxoBaseMenu.ItemSymbol symbol={props.symbol} />
</span>
)}
@@ -366,7 +366,7 @@ export namespace AxoDropdownMenu {
)}
<AxoBaseMenu.ItemContentSlot>
<AxoBaseMenu.ItemText>{props.children}</AxoBaseMenu.ItemText>
<span className={tw('ml-auto')}>
<span className={tw('ms-auto')}>
<AxoSymbol.Icon size={14} symbol="chevron-[end]" label={null} />
</span>
</AxoBaseMenu.ItemContentSlot>

18
ts/axo/AxoProvider.tsx Normal file
View File

@@ -0,0 +1,18 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { FC, ReactNode } from 'react';
import React, { memo } from 'react';
import { Direction } from 'radix-ui';
type AxoProviderProps = Readonly<{
dir: 'ltr' | 'rtl';
children: ReactNode;
}>;
export const AxoProvider: FC<AxoProviderProps> = memo(props => {
return (
<Direction.Provider dir={props.dir}>{props.children}</Direction.Provider>
);
});
AxoProvider.displayName = 'AxoProvider';

View File

@@ -82,7 +82,8 @@ export namespace AxoSelect {
'flex',
'rounded-full py-[5px] ps-3 pe-2.5 type-body-medium text-label-primary',
'disabled:text-label-disabled',
'outline-0 outline-border-focused focused:outline-[2.5px]'
'outline-0 outline-border-focused focused:outline-[2.5px]',
'forced-colors:border'
);
const TriggerVariants = {
@@ -137,7 +138,7 @@ export namespace AxoSelect {
{props.children}
</Select.Value>
</AxoBaseMenu.ItemText>
<Select.Icon className={tw('ml-2')}>
<Select.Icon className={tw('ms-2')}>
<AxoSymbol.Icon symbol="chevron-down" size={14} label={null} />
</Select.Icon>
</Select.Trigger>

View File

@@ -0,0 +1,40 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { useState } from 'react';
import type { Meta } from '@storybook/react';
import { AxoSwitch } from './AxoSwitch';
import { tw } from './tw';
export default {
title: 'Axo/AxoSwitch',
} satisfies Meta;
function Template(props: {
label: string;
defaultChecked: boolean;
disabled?: boolean;
}): JSX.Element {
const [checked, setChecked] = useState(props.defaultChecked);
return (
<label className={tw('my-2 flex items-center gap-2')}>
<AxoSwitch
checked={checked}
onCheckedChange={setChecked}
disabled={props.disabled}
/>
{props.label}
</label>
);
}
export function Basic(): JSX.Element {
return (
<>
<h1 className={tw('type-title-large')}>AxoSwitch</h1>
<Template label="Unchecked" defaultChecked={false} />
<Template label="Checked" defaultChecked />
<Template label="UncheckedDisabled" defaultChecked={false} disabled />
<Template label="CheckedDisabled" defaultChecked disabled />
</>
);
}

83
ts/axo/AxoSwitch.tsx Normal file
View File

@@ -0,0 +1,83 @@
// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import React, { memo } from 'react';
import { Switch } from 'radix-ui';
import { tw } from './tw';
import { AxoSymbol } from './AxoSymbol';
const Namespace = 'AxoSwitch';
type AxoSwitchProps = Readonly<{
checked: boolean;
onCheckedChange: (nextChecked: boolean) => void;
disabled?: boolean;
required?: boolean;
}>;
// eslint-disable-next-line import/export
export const AxoSwitch = memo((props: AxoSwitchProps) => {
return (
<Switch.Root
checked={props.checked}
onCheckedChange={props.onCheckedChange}
disabled={props.disabled}
required={props.required}
className={tw(
'group relative z-0 flex h-[18px] w-8 items-center rounded-full',
'border border-border-secondary inset-shadow-on-color',
'bg-fill-secondary',
'data-[disabled]:bg-fill-primary',
'pressed:bg-fill-secondary-pressed',
'outline-0 outline-border-focused focused:outline-[2.5px]',
'overflow-hidden'
)}
>
<span
className={tw(
'absolute top-0 bottom-0',
'w-5.5 rounded-s-full',
'group-data-[disabled]:w-7.5 group-data-[disabled]:rounded-full',
'opacity-0 group-data-[state=checked]:opacity-100',
'-translate-x-3.5 group-data-[state=checked]:translate-x-0 rtl:translate-x-3.5',
'bg-color-fill-primary group-pressed:bg-color-fill-primary-pressed',
'transition-all duration-200 ease-out-cubic',
'forced-colors:bg-[AccentColor]',
'forced-colors:group-data-[disabled]:bg-[GrayText]'
)}
/>
<span
className={tw(
'invisible forced-colors:visible',
'absolute start-0.5 z-0 text-[12px]',
'forced-color-adjust-none',
'forced-colors:text-[AccentColorText]'
)}
>
<AxoSymbol.InlineGlyph symbol="check" label={null} />
</span>
<Switch.Thumb
className={tw(
'z-10 block size-4 rounded-full',
// eslint-disable-next-line better-tailwindcss/no-restricted-classes
'shadow-[#000]/12',
'shadow-[0.5px_0_0.5px_0.5px,-0.5px_0_0.5px_0.5px]',
'bg-label-primary-on-color',
'data-[disabled]:bg-label-disabled-on-color',
'transition-all duration-200 ease-out-cubic',
'data-[state=checked]:translate-x-3.5',
'rtl:data-[state=checked]:-translate-x-3.5',
'forced-colors:border',
'forced-colors:data-[disabled]:bg-[ButtonFace]'
)}
/>
</Switch.Root>
);
});
AxoSwitch.displayName = `${Namespace}`;
// eslint-disable-next-line max-len
// eslint-disable-next-line @typescript-eslint/no-namespace, @typescript-eslint/no-redeclare, import/export
export namespace AxoSwitch {
export type Props = AxoSwitchProps;
}

View File

@@ -43,12 +43,12 @@ const SymbolInfo = memo(function SymbolInfo(props: {
{variant.title}
</span>
<span className={tw('text-[20px] leading-none')}>
<Direction.DirectionProvider dir={variant.dir}>
<Direction.Provider dir={variant.dir}>
<AxoSymbol.InlineGlyph
symbol={props.symbolName}
label={null}
/>
</Direction.DirectionProvider>
</Direction.Provider>
</span>
<code className={tw('type-caption text-label-secondary')}>
{Array.from(variant.text, char => {

View File

@@ -9,13 +9,16 @@ import { AxoSymbol, type AxoSymbolName } from '../AxoSymbol';
export namespace AxoBaseMenu {
// <Content/SubContent>
const baseContentStyles = tw(
'max-w-[300px] min-w-[200px] p-1.5',
'max-w-[300px] min-w-[200px]',
'select-none',
'rounded-xl bg-elevated-background-tertiary shadow-elevation-3',
'data-[state=closed]:animate-fade-out'
'data-[state=closed]:animate-fade-out',
'forced-colors:border',
'forced-colors:bg-[Canvas]',
'forced-colors:text-[CanvasText]'
);
const baseContentGridStyles = tw('grid grid-cols-[min-content_auto]');
const baseContentGridStyles = tw('grid grid-cols-[min-content_auto] p-1.5');
// <Group/RadioGroup>
const baseGroupStyles = tw('col-span-full grid grid-cols-subgrid');
@@ -34,7 +37,12 @@ export namespace AxoBaseMenu {
'rounded-md type-body-medium',
'outline-0 data-[highlighted]:bg-fill-secondary-pressed',
'data-[disabled]:text-label-disabled',
'outline-0 outline-border-focused focused:outline-[2.5px]'
'outline-0 outline-border-focused focused:outline-[2.5px]',
'forced-colors:text-[CanvasText]',
'forced-colors:data-[highlighted]:bg-[Highlight]',
'forced-colors:data-[highlighted]:text-[HighlightText]',
'forced-colors:data-[disabled]:text-[GrayText]',
'forced-color-adjust-none'
);
/**
@@ -143,7 +151,10 @@ export namespace AxoBaseMenu {
): JSX.Element {
return (
<span
className={tw('ml-auto px-1 type-body-medium text-label-secondary')}
dir="auto"
className={tw(
'ms-auto px-1 type-body-medium text-label-secondary forced-colors:text-[inherit]'
)}
>
{props.keyboardShortcut}
</span>
@@ -332,7 +343,9 @@ export namespace AxoBaseMenu {
export const menuSubTriggerStyles = tw(
navigableItemStyles,
'data-[state=open]:not-data-[highlighted]:bg-fill-secondary'
'data-[state=open]:not-data-[highlighted]:bg-fill-secondary',
'forced-colors:data-[state=open]:not-data-[highlighted]:bg-[Highlight]',
'forced-colors:data-[state=open]:not-data-[highlighted]:text-[HighlightText]'
);
/**

View File

@@ -209,10 +209,7 @@ function TypingBubbleGroupAvatars({
<div className="module-message__author-avatar-container module-message__author-avatar-container--typing">
<div className="module-message__typing-avatar-spacer" />
{typingContactsOverflowCount > 0 && (
<div
className="module-message__typing-avatar module-message__typing-avatar--overflow-count
"
>
<div className="module-message__typing-avatar module-message__typing-avatar--overflow-count">
<div
aria-label={i18n('icu:TypingBubble__avatar--overflow-count', {
count: typingContactsOverflowCount,

View File

@@ -9,6 +9,7 @@ import { Emojify } from '../../components/conversation/Emojify';
import { normalizeAci } from '../../util/normalizeAci';
import type { MentionBlotValue } from '../util';
import { FunEmojiLocalizationProvider } from '../../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../../axo/AxoProvider';
export class MentionBlot extends EmbedBlot {
static override blotName = 'mention';
@@ -48,6 +49,7 @@ export class MentionBlot extends EmbedBlot {
createRoot(mentionSpan).render(
<StrictMode>
<AxoProvider dir={window.i18n.getLocaleDirection()}>
<FunEmojiLocalizationProvider i18n={window.i18n}>
<span className="module-composition-input__at-mention">
<bdi>
@@ -56,6 +58,7 @@ export class MentionBlot extends EmbedBlot {
</bdi>
</span>
</FunEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);

View File

@@ -8,15 +8,18 @@ import { ClearingData } from '../components/ClearingData';
import { strictAssert } from '../util/assert';
import { deleteAllData } from './deleteAllData';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../axo/AxoProvider';
export function renderClearingDataView(): void {
const appContainer = document.getElementById('app-container');
strictAssert(appContainer != null, 'No #app-container');
createRoot(appContainer).render(
<StrictMode>
<AxoProvider dir={window.i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<ClearingData deleteAllData={deleteAllData} i18n={window.i18n} />
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);
}

View File

@@ -88,6 +88,7 @@ import { SmartPreferencesChatFoldersPage } from './PreferencesChatFoldersPage';
import type { SmartPreferencesEditChatFolderPageProps } from './PreferencesEditChatFolderPage';
import { SmartPreferencesEditChatFolderPage } from './PreferencesEditChatFolderPage';
import { isProduction } from '../../util/version';
import { AxoProvider } from '../../axo/AxoProvider';
const DEFAULT_NOTIFICATION_SETTING = 'message';
@@ -740,6 +741,7 @@ export function SmartPreferences(): JSX.Element | null {
return (
<StrictMode>
<AxoProvider dir={i18n.getLocaleDirection()}>
<Preferences
accountEntropyPool={accountEntropyPool}
addCustomColor={addCustomColor}
@@ -750,7 +752,9 @@ export function SmartPreferences(): JSX.Element | null {
availableSpeakers={availableSpeakers}
backupFeatureEnabled={backupFeatureEnabled}
backupKeyViewed={backupKeyViewed}
backupSubscriptionStatus={backupSubscriptionStatus ?? { status: 'off' }}
backupSubscriptionStatus={
backupSubscriptionStatus ?? { status: 'off' }
}
backupMediaDownloadStatus={{
completedBytes: backupMediaDownloadCompletedBytes ?? 0,
totalBytes: backupMediaDownloadTotalBytes ?? 0,
@@ -913,6 +917,7 @@ export function SmartPreferences(): JSX.Element | null {
__dangerouslyRunAbitraryReadOnlySqlQuery
}
/>
</AxoProvider>
</StrictMode>
);
}

View File

@@ -10,6 +10,7 @@ import { ProgressModal } from '../components/ProgressModal';
import { clearTimeoutIfNecessary } from './clearTimeoutIfNecessary';
import { sleep } from './sleep';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../axo/AxoProvider';
const log = createLogger('longRunningTaskWrapper');
@@ -37,9 +38,11 @@ export async function longRunningTaskWrapper<T>({
progressRoot = createRoot(progressNode);
progressRoot.render(
<StrictMode>
<AxoProvider dir={window.i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<ProgressModal i18n={window.i18n} />
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);
spinnerStart = Date.now();

View File

@@ -5,6 +5,7 @@ import React, { StrictMode } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { ConfirmationDialog } from '../components/ConfirmationDialog';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../axo/AxoProvider';
type ConfirmationDialogViewProps = {
onTopOfEverything?: boolean;
@@ -57,6 +58,7 @@ export function showConfirmationDialog(
confirmationDialogRoot = createRoot(confirmationDialogViewNode);
confirmationDialogRoot.render(
<StrictMode>
<AxoProvider dir={window.i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<ConfirmationDialog
dialogName={options.dialogName}
@@ -88,6 +90,7 @@ export function showConfirmationDialog(
{options.description}
</ConfirmationDialog>
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);
}

View File

@@ -8,6 +8,7 @@ import { About } from '../../components/About';
import { i18n } from '../sandboxedInit';
import { strictAssert } from '../../util/assert';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../../axo/AxoProvider';
const { AboutWindowProps } = window.Signal;
@@ -18,6 +19,7 @@ strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<AxoProvider dir={i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<About
closeAbout={() => window.SignalContext.executeMenuRole('close')}
@@ -28,5 +30,6 @@ createRoot(app).render(
version={window.SignalContext.getVersion()}
/>
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);

View File

@@ -7,6 +7,7 @@ import { DebugLogWindow } from '../../components/DebugLogWindow';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../../components/fun/FunEmojiLocalizationProvider';
import { i18n } from '../sandboxedInit';
import { strictAssert } from '../../util/assert';
import { AxoProvider } from '../../axo/AxoProvider';
const { DebugLogWindowProps } = window.Signal;
@@ -17,6 +18,7 @@ strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<AxoProvider dir={i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<DebugLogWindow
closeWindow={() => window.SignalContext.executeMenuRole('close')}
@@ -26,5 +28,6 @@ createRoot(app).render(
uploadLogs={DebugLogWindowProps.uploadLogs}
/>
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);

View File

@@ -8,6 +8,7 @@ import { PermissionsPopup } from '../../components/PermissionsPopup';
import { i18n } from '../sandboxedInit';
import { strictAssert } from '../../util/assert';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../../axo/AxoProvider';
const { PermissionsWindowProps } = window.Signal;
@@ -31,6 +32,7 @@ strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<AxoProvider dir={i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<PermissionsPopup
i18n={i18n}
@@ -39,5 +41,6 @@ createRoot(app).render(
onClose={PermissionsWindowProps.onClose}
/>
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);

View File

@@ -10,6 +10,7 @@ import { strictAssert } from '../../util/assert';
import { drop } from '../../util/drop';
import { parseEnvironment, setEnvironment } from '../../environment';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../../components/fun/FunEmojiLocalizationProvider';
import { AxoProvider } from '../../axo/AxoProvider';
const { ScreenShareWindowProps } = window.Signal;
@@ -33,6 +34,7 @@ function render() {
createRoot(app).render(
<StrictMode>
<AxoProvider dir={i18n.getLocaleDirection()}>
<FunDefaultEnglishEmojiLocalizationProvider>
<div className="App dark-theme">
<CallingScreenSharingController
@@ -44,6 +46,7 @@ function render() {
/>
</div>
</FunDefaultEnglishEmojiLocalizationProvider>
</AxoProvider>
</StrictMode>
);
}