mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-09-21 17:24:23 +01:00
Rework AxoList/AxoItem CSS layout and component structure
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// Copyright 2026 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { ReactNode, FC } from 'react';
|
||||
import { memo } from 'react';
|
||||
import { tw } from '../tw.dom.tsx';
|
||||
import { AxoSymbol } from '../AxoSymbol.dom.tsx';
|
||||
|
||||
export namespace Story {
|
||||
/**
|
||||
* <Story.Hint>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type HintProps = Readonly<{
|
||||
children?: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Hint: FC<HintProps> = memo(props => {
|
||||
return (
|
||||
<p className={tw('type-caption text-secondary')}>{props.children}</p>
|
||||
);
|
||||
});
|
||||
|
||||
Hint.displayName = 'Story.Hint';
|
||||
|
||||
/**
|
||||
* <Story.Callout>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type CalloutProps = Readonly<{
|
||||
children?: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Callout: FC<HintProps> = memo(props => {
|
||||
return (
|
||||
<div
|
||||
className={tw(
|
||||
'my-2 flex gap-2 p-2',
|
||||
'bg-warning-tint text-warning',
|
||||
'border border-dashed',
|
||||
'type-caption font-medium',
|
||||
'font-mono'
|
||||
)}
|
||||
>
|
||||
<AxoSymbol.InlineGlyph symbol="error-circle-fill" label={null} />
|
||||
<div className={tw('flex-1')}>{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Callout.displayName = 'Story.Callout';
|
||||
|
||||
/**
|
||||
* <Story.Legend>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type LegendProps = Readonly<{
|
||||
label: string;
|
||||
children?: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Legend: FC<LegendProps> = memo(props => {
|
||||
return (
|
||||
<fieldset className={tw('my-2 border border-dashed border-selected p-2')}>
|
||||
<legend className={tw('px-2 font-mono type-caption text-accent')}>
|
||||
{props.label}
|
||||
</legend>
|
||||
{props.children}
|
||||
</fieldset>
|
||||
);
|
||||
});
|
||||
|
||||
Legend.displayName = 'Story.Legend';
|
||||
}
|
||||
@@ -25,3 +25,4 @@
|
||||
@import './AxoDragRegions.css';
|
||||
@import './AxoScrollArea.css';
|
||||
@import './AxoSelect.css';
|
||||
@import './items/_AxoBaseItem.css';
|
||||
|
||||
@@ -178,7 +178,6 @@ export function ItemActions(): ReactNode {
|
||||
<AxoContactList.Item
|
||||
avatar={<LegacyAvatar title="Adrian" />}
|
||||
title="Adrian"
|
||||
value="Admin"
|
||||
onClick={action('onClick')}
|
||||
accessory={
|
||||
<AxoContactList.ItemAction variant="subtle-secondary">
|
||||
@@ -235,7 +234,6 @@ export function ItemIconActions(): ReactNode {
|
||||
<AxoContactList.Item
|
||||
avatar={<LegacyAvatar title="Adrian" />}
|
||||
title="Adrian"
|
||||
value="Admin"
|
||||
onClick={action('onClick')}
|
||||
accessory={
|
||||
<AxoContactList.ItemIconAction
|
||||
|
||||
@@ -26,7 +26,7 @@ export namespace AxoContactList {
|
||||
<AxoList.Root>
|
||||
{props.title != null && (
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>{props.title}</AxoList.Title>
|
||||
<AxoList.Label>{props.title}</AxoList.Label>
|
||||
</AxoList.Header>
|
||||
)}
|
||||
<AxoList.Body>
|
||||
@@ -58,11 +58,11 @@ export namespace AxoContactList {
|
||||
return (
|
||||
<AriaList.Item asChild>
|
||||
<AxoBaseItem.Root>
|
||||
<AxoBaseItem.LeadingSlot>{props.avatar}</AxoBaseItem.LeadingSlot>
|
||||
<AxoBaseItem.Leading>{props.avatar}</AxoBaseItem.Leading>
|
||||
<AxoBaseItem.Content>
|
||||
<AxoBaseItem.Body>
|
||||
<AriaList.Label asChild id={id}>
|
||||
<AxoBaseItem.Title>{props.title}</AxoBaseItem.Title>
|
||||
<AxoBaseItem.Label>{props.title}</AxoBaseItem.Label>
|
||||
</AriaList.Label>
|
||||
{props.value != null && (
|
||||
<AriaList.Label asChild>
|
||||
@@ -82,10 +82,10 @@ export namespace AxoContactList {
|
||||
onClick={props.onClick}
|
||||
/>
|
||||
)}
|
||||
{props.accessory != null && (
|
||||
<AxoBaseItem.Accessory>{props.accessory}</AxoBaseItem.Accessory>
|
||||
)}
|
||||
</AxoBaseItem.Body>
|
||||
{props.accessory != null && (
|
||||
<AxoBaseItem.Accessory>{props.accessory}</AxoBaseItem.Accessory>
|
||||
)}
|
||||
</AxoBaseItem.Content>
|
||||
</AxoBaseItem.Root>
|
||||
</AriaList.Item>
|
||||
@@ -173,11 +173,13 @@ export namespace AxoContactList {
|
||||
return (
|
||||
<AriaList.Item asChild>
|
||||
<AxoBaseItem.Root>
|
||||
<AxoBaseItem.IconAvatar size={32} symbol={props.symbol} />
|
||||
<AxoBaseItem.Leading>
|
||||
<AxoBaseItem.IconAvatar size={32} symbol={props.symbol} />
|
||||
</AxoBaseItem.Leading>
|
||||
<AxoBaseItem.Content>
|
||||
<AxoBaseItem.Body>
|
||||
<AriaList.Label asChild id={id}>
|
||||
<AxoBaseItem.Title>{props.title}</AxoBaseItem.Title>
|
||||
<AxoBaseItem.Label>{props.title}</AxoBaseItem.Label>
|
||||
</AriaList.Label>
|
||||
{props.onClick != null && (
|
||||
<AxoBaseItem.HiddenTrigger
|
||||
@@ -210,9 +212,9 @@ export namespace AxoContactList {
|
||||
<AxoBaseItem.Content>
|
||||
<AxoBaseItem.Body>
|
||||
<AriaList.Label asChild>
|
||||
<AxoBaseItem.Title truncate>
|
||||
<AxoBaseItem.Label truncate>
|
||||
<span className={tw('text-secondary')}>{props.title}</span>
|
||||
</AxoBaseItem.Title>
|
||||
</AxoBaseItem.Label>
|
||||
</AriaList.Label>
|
||||
</AxoBaseItem.Body>
|
||||
</AxoBaseItem.Content>
|
||||
|
||||
@@ -27,7 +27,7 @@ export namespace AxoFieldList {
|
||||
<AxoList.Root>
|
||||
{props.title != null && (
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>{props.title}</AxoList.Title>
|
||||
<AxoList.Label>{props.title}</AxoList.Label>
|
||||
{/* We probably don't ever want to show a description without a title */}
|
||||
{props.description != null && (
|
||||
<AxoList.Description>{props.description}</AxoList.Description>
|
||||
@@ -37,7 +37,7 @@ export namespace AxoFieldList {
|
||||
<AxoList.Body>{props.children}</AxoList.Body>
|
||||
{props.help != null && (
|
||||
<AxoList.Footer>
|
||||
<AxoList.Help>{props.help}</AxoList.Help>
|
||||
<AxoList.FooterDescription>{props.help}</AxoList.FooterDescription>
|
||||
</AxoList.Footer>
|
||||
)}
|
||||
</AxoList.Root>
|
||||
|
||||
@@ -9,19 +9,32 @@ import { tw } from '../tw.dom.tsx';
|
||||
import { AxoSwitch } from '../AxoSwitch.dom.tsx';
|
||||
import { AxoSelect } from '../AxoSelect.dom.tsx';
|
||||
import { AxoDropdownMenu } from '../AxoDropdownMenu.dom.tsx';
|
||||
import { Story } from '../_storybook-helpers/Story.dom.tsx';
|
||||
|
||||
export default {
|
||||
title: 'Axo/Items/AxoItem',
|
||||
} satisfies Meta;
|
||||
|
||||
export function Title(): ReactNode {
|
||||
const LONG_TEXT = (
|
||||
<>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Ipsa magni rerum
|
||||
consequatur vero enim, laborum ullam voluptate expedita tempora amet natus
|
||||
nisi praesentium alias earum accusantium ex doloribus et quidem.
|
||||
</>
|
||||
);
|
||||
|
||||
const LONG_LABEL = <>Very long label: {LONG_TEXT}</>;
|
||||
const LONG_VALUE = <>Very long value: {LONG_TEXT}</>;
|
||||
const LONG_DESCRIPTION = <>Very long description: {LONG_TEXT}</>;
|
||||
|
||||
export function Label(): ReactNode {
|
||||
return (
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -33,7 +46,7 @@ export function Title(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -45,7 +58,7 @@ export function Title(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Yet another title</AxoItem.Title>
|
||||
<AxoItem.Label>{LONG_LABEL}</AxoItem.Label>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -65,7 +78,7 @@ export function Description(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.Description>Description of the item</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
@@ -78,7 +91,7 @@ export function Description(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
@@ -93,10 +106,8 @@ export function Description(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Yet another title</AxoItem.Title>
|
||||
<AxoItem.Description>
|
||||
Description that explains what this means
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Yet another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -114,10 +125,12 @@ export function Icon(): ReactNode {
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -127,13 +140,13 @@ export function Icon(): ReactNode {
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="appearance" />
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol="appearance" />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -145,7 +158,7 @@ export function Icon(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Item without icon</AxoItem.Title>
|
||||
<AxoItem.Label>Item without icon</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
Notice it stays aligned with the other items
|
||||
</AxoItem.Description>
|
||||
@@ -161,6 +174,71 @@ export function Icon(): ReactNode {
|
||||
);
|
||||
}
|
||||
|
||||
function IconAvatarTemplate(props: { size: AxoItem.IconAvatarSize }) {
|
||||
return (
|
||||
<Story.Legend label={`size=${props.size}`}>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.IconAvatar symbol="settings" size={props.size} />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.IconAvatar symbol="appearance" size={props.size} />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Label>Item without icon avatar</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
Notice it stays aligned with the other items
|
||||
</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
</Story.Legend>
|
||||
);
|
||||
}
|
||||
|
||||
export function IconAvatar(): ReactNode {
|
||||
return (
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
<IconAvatarTemplate size={32} />
|
||||
<IconAvatarTemplate size={36} />
|
||||
<IconAvatarTemplate size={38} />
|
||||
<IconAvatarTemplate size={48} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function Value(): ReactNode {
|
||||
return (
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
@@ -168,7 +246,7 @@ export function Value(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.Value>+1 555 555-5555</AxoItem.Value>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
@@ -181,11 +259,9 @@ export function Value(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Value>Jamie-MacBook-Pro.local</AxoItem.Value>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
@@ -197,7 +273,7 @@ export function Value(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Yet another title</AxoItem.Title>
|
||||
<AxoItem.Label>Yet another label</AxoItem.Label>
|
||||
<AxoItem.Value>System Language</AxoItem.Value>
|
||||
<AxoItem.Description>
|
||||
Description that explains what this means
|
||||
@@ -210,6 +286,11 @@ export function Value(): ReactNode {
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
|
||||
<Story.Callout>
|
||||
<strong>Note:</strong> If you have a value, you cannot have any other
|
||||
type of accessory.
|
||||
</Story.Callout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -219,54 +300,60 @@ export function Arrow(): ReactNode {
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Trailing>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="appearance" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Value>Jamie-MacBook-Pro.local</AxoItem.Value>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Yet another title</AxoItem.Title>
|
||||
<AxoItem.Value>System Language</AxoItem.Value>
|
||||
<AxoItem.Description>
|
||||
Description that explains what this means
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.Value>Item value</AxoItem.Value>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Trailing>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Label>Item without arrow</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
|
||||
<Story.Callout>
|
||||
<strong>Note:</strong> Arrows should only be used when the item is
|
||||
clickable and needs an extra hint.
|
||||
</Story.Callout>
|
||||
|
||||
<Story.Callout>
|
||||
<strong>Note:</strong> Arrows should not be used with any accessories
|
||||
except for values.
|
||||
</Story.Callout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -278,42 +365,56 @@ export function Action(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action variant="subtle-secondary">
|
||||
Action
|
||||
</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action variant="subtle-secondary">Action</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.Description>Description of the item</AxoItem.Description>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action variant="subtle-secondary">
|
||||
Action
|
||||
</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action variant="subtle-secondary">Action</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action
|
||||
symbol="phone-fill"
|
||||
variant="strong-affirmative"
|
||||
>
|
||||
Join
|
||||
</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action symbol="phone-fill" variant="strong-affirmative">
|
||||
Join
|
||||
</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
|
||||
<Story.Callout>
|
||||
<strong>Note:</strong> There should only be one text action at a time,
|
||||
if you need more than one action you can use an icon action or menu.
|
||||
</Story.Callout>
|
||||
|
||||
<Story.Callout>
|
||||
<strong>Note:</strong> Items with actions should not be clickable
|
||||
</Story.Callout>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -359,40 +460,36 @@ export function IconActions(): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Trailing>
|
||||
<DownloadIconAction />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Trailing>
|
||||
<MoreIconActionWithMenu />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Yet another title</AxoItem.Title>
|
||||
<AxoItem.Description>
|
||||
Description that explains what this means
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Yet another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Trailing>
|
||||
<DownloadIconAction />
|
||||
<MoreIconActionWithMenu />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
@@ -425,55 +522,53 @@ function Select() {
|
||||
);
|
||||
}
|
||||
|
||||
export function Accessories(): ReactNode {
|
||||
export function OtherAccessories(): ReactNode {
|
||||
return (
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Trailing>
|
||||
<Switch />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Accessory>
|
||||
<Select />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<Select />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title of item</AxoItem.Title>
|
||||
<AxoItem.Label>Label of item</AxoItem.Label>
|
||||
<AxoItem.Description>Description of the item</AxoItem.Description>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Trailing>
|
||||
<Switch />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Another title</AxoItem.Title>
|
||||
<AxoItem.Description>
|
||||
Description with more detail about the item
|
||||
</AxoItem.Description>
|
||||
<AxoItem.Label>Another label</AxoItem.Label>
|
||||
<AxoItem.Description>{LONG_DESCRIPTION}</AxoItem.Description>
|
||||
<AxoItem.Accessory>
|
||||
<Select />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<Select />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
@@ -481,243 +576,117 @@ export function Accessories(): ReactNode {
|
||||
);
|
||||
}
|
||||
|
||||
function Header(props: { children: ReactNode }): ReactNode {
|
||||
return <h2 className={tw('type-title-small')}>{props.children}</h2>;
|
||||
function StressTest(props: {
|
||||
label: ReactNode;
|
||||
value?: ReactNode;
|
||||
description?: ReactNode;
|
||||
}): ReactNode {
|
||||
return (
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Label>{props.label}</AxoItem.Label>
|
||||
{props.value != null && (
|
||||
<AxoItem.Value>{props.value}</AxoItem.Value>
|
||||
)}
|
||||
{props.description != null && (
|
||||
<AxoItem.Description>{props.description}</AxoItem.Description>
|
||||
)}
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Trailing>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
);
|
||||
}
|
||||
|
||||
export function StressTests(): ReactNode {
|
||||
return (
|
||||
<div className={tw('mx-auto max-w-150')}>
|
||||
<Header>Kitchen Sink</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<DownloadIconAction />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<DownloadIconAction />
|
||||
<MoreIconActionWithMenu />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action variant="subtle-secondary">Action</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Action variant="subtle-secondary">Action</AxoItem.Action>
|
||||
<AxoItem.Action variant="subtle-secondary">Action</AxoItem.Action>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<Switch />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="settings" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
label="Trigger"
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<Select />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<Story.Callout>These should all fit in their normal place.</Story.Callout>
|
||||
|
||||
<Header>Long Title: Title should be clamped to two lines</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio
|
||||
pariatur ipsum non officia laboriosam amet omnis autem
|
||||
architecto, expedita dolores officiis laborum iste cum porro,
|
||||
fugiat sapiente sequi dolor. Excepturi.
|
||||
</AxoItem.Title>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<Story.Legend label="Baseline">
|
||||
<StressTest label="Label" />
|
||||
<StressTest label="Label" value="Value" />
|
||||
<StressTest label="Label" description="Description" />
|
||||
<StressTest label="Label" value="Value" description="Description" />
|
||||
</Story.Legend>
|
||||
|
||||
<Header>Long Title: Value should be forced to the next line</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio
|
||||
pariatur ipsum non officia laboriosam amet omnis autem
|
||||
architecto, expedita dolores officiis laborum iste cum porro,
|
||||
fugiat sapiente sequi dolor. Excepturi.
|
||||
</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<Story.Legend label="Long label">
|
||||
<Story.Callout>
|
||||
These should all break into a stacked layout.
|
||||
</Story.Callout>
|
||||
|
||||
<Header>
|
||||
Long Title: Wrapped value should be on separate line from description
|
||||
</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio
|
||||
pariatur ipsum non officia laboriosam amet omnis autem
|
||||
architecto, expedita dolores officiis laborum iste cum porro,
|
||||
fugiat sapiente sequi dolor. Excepturi.
|
||||
</AxoItem.Title>
|
||||
<AxoItem.Value>Value</AxoItem.Value>
|
||||
<AxoItem.Description>Description</AxoItem.Description>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<StressTest label={LONG_LABEL} />
|
||||
<StressTest label={LONG_LABEL} value="Value" />
|
||||
<StressTest label={LONG_LABEL} description="Description" />
|
||||
<StressTest
|
||||
label={LONG_LABEL}
|
||||
value="Value"
|
||||
description="Description"
|
||||
/>
|
||||
</Story.Legend>
|
||||
|
||||
<Header>
|
||||
Long Title: Actions and arrow should stay on the same line
|
||||
</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio
|
||||
pariatur ipsum non officia laboriosam amet omnis autem
|
||||
architecto, expedita dolores officiis laborum iste cum porro,
|
||||
fugiat sapiente sequi dolor. Excepturi.
|
||||
</AxoItem.Title>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<DownloadIconAction />
|
||||
<MoreIconActionWithMenu />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<Story.Legend label="Long value">
|
||||
<Story.Callout>
|
||||
These should all break into a stacked layout.
|
||||
</Story.Callout>
|
||||
|
||||
<Header>Long Value: Value should be forced to next line</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio
|
||||
pariatur ipsum non officia laboriosam amet omnis autem
|
||||
architecto, expedita dolores officiis laborum iste cum porro,
|
||||
fugiat sapiente sequi dolor. Excepturi.
|
||||
</AxoItem.Value>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<StressTest label="Label" value={LONG_VALUE} />
|
||||
<StressTest
|
||||
label="Label"
|
||||
value={LONG_VALUE}
|
||||
description="Description"
|
||||
/>
|
||||
</Story.Legend>
|
||||
|
||||
<Header>
|
||||
Long Value: Actions and arrow should stay on the same line
|
||||
</Header>
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Title</AxoItem.Title>
|
||||
<AxoItem.Value>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio
|
||||
pariatur ipsum non officia laboriosam amet omnis autem
|
||||
architecto, expedita dolores officiis laborum iste cum porro,
|
||||
fugiat sapiente sequi dolor. Excepturi.
|
||||
</AxoItem.Value>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<DownloadIconAction />
|
||||
<MoreIconActionWithMenu />
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Root>
|
||||
</AxoItem.Group>
|
||||
<Story.Legend label="Long description">
|
||||
<Story.Callout>
|
||||
Long descriptions should <em>not</em> break into a stacked layout.
|
||||
</Story.Callout>
|
||||
|
||||
<StressTest label="Label" description={LONG_DESCRIPTION} />
|
||||
<StressTest
|
||||
label="Label"
|
||||
value="Value"
|
||||
description={LONG_DESCRIPTION}
|
||||
/>
|
||||
</Story.Legend>
|
||||
|
||||
<Story.Legend label="Long label + value">
|
||||
<Story.Callout>
|
||||
These should all break into a stacked layout.
|
||||
</Story.Callout>
|
||||
|
||||
<StressTest label={LONG_LABEL} value={LONG_VALUE} />
|
||||
<StressTest
|
||||
label={LONG_LABEL}
|
||||
value={LONG_VALUE}
|
||||
description="Description"
|
||||
/>
|
||||
</Story.Legend>
|
||||
|
||||
<Story.Legend label="Long everything">
|
||||
<Story.Callout>
|
||||
These should all break into a stacked layout.
|
||||
</Story.Callout>
|
||||
|
||||
<StressTest
|
||||
label={LONG_LABEL}
|
||||
value={LONG_VALUE}
|
||||
description={LONG_DESCRIPTION}
|
||||
/>
|
||||
</Story.Legend>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,24 +13,28 @@ import { AriaList } from '../aria/AriaList.dom.tsx';
|
||||
* ```tsx
|
||||
* <AxoItem.Group>
|
||||
* <AxoItem.Root>
|
||||
* <AxoItem.Icon />
|
||||
* <AxoItem.Leading>
|
||||
* <AxoItem.Icon />
|
||||
* </AxoItem.Leading>
|
||||
* <AxoItem.Content>
|
||||
* <AxoItem.Body>
|
||||
* <AxoItem.Title />
|
||||
* <AxoItem.Value />
|
||||
* <AxoItem.Label />
|
||||
* <AxoItem.Value/>
|
||||
* <AxoItem.Description />
|
||||
* <AxoItem.HiddenTrigger />
|
||||
* <AxoItem.Accessory>
|
||||
* <AxoItem.Action />
|
||||
* <AxoItem.IconAction />
|
||||
* <AxoSelect.Root />
|
||||
* <AxoSwitch.Root />
|
||||
* </AxoItem.Accessory>
|
||||
* </AxoItem.Body>
|
||||
* <AxoItem.Accessory>
|
||||
* <AxoItem.Action />
|
||||
* <AxoItem.IconAction />
|
||||
* <AxoSelect.Root />
|
||||
* <AxoSwitch.Root />
|
||||
* </AxoItem.Accessory>
|
||||
* <AxoItem.Trailing>
|
||||
* <AxoItem.Arrow />
|
||||
* </AxoItem.Trailing>
|
||||
* </AxoItem.Content>
|
||||
* <AxoItem.Arrow />
|
||||
* </AxoItem.Root>
|
||||
* </AxoItem.Layout>
|
||||
* </AxoItem.Group>
|
||||
* ```
|
||||
*/
|
||||
export namespace AxoItem {
|
||||
@@ -73,6 +77,21 @@ export namespace AxoItem {
|
||||
|
||||
Root.displayName = 'AxoItem.Root';
|
||||
|
||||
/**
|
||||
* <AxoItem.Leading>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type LeadingProps = Readonly<{
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Leading: FC<LeadingProps> = memo(props => {
|
||||
return <AxoBaseItem.Leading>{props.children}</AxoBaseItem.Leading>;
|
||||
});
|
||||
|
||||
Leading.displayName = 'AxoItem.Leading';
|
||||
|
||||
/**
|
||||
* <AxoItem.Icon>
|
||||
* --------------------------------------------------------------------------
|
||||
@@ -88,6 +107,24 @@ export namespace AxoItem {
|
||||
|
||||
Icon.displayName = 'AxoItem.Icon';
|
||||
|
||||
/**
|
||||
* <AxoItem.IconAvatar>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type IconAvatarSize = AxoBaseItem.IconAvatarSize;
|
||||
|
||||
export type IconAvatarProps = Readonly<{
|
||||
size: IconAvatarSize;
|
||||
symbol: AxoSymbol.Name;
|
||||
}>;
|
||||
|
||||
export const IconAvatar: FC<IconAvatarProps> = memo(props => {
|
||||
return <AxoBaseItem.IconAvatar size={props.size} symbol={props.symbol} />;
|
||||
});
|
||||
|
||||
IconAvatar.displayName = 'AxoItem.IconAvatar';
|
||||
|
||||
/**
|
||||
* <AxoItem.Content>
|
||||
* --------------------------------------------------------------------------
|
||||
@@ -119,24 +156,24 @@ export namespace AxoItem {
|
||||
Body.displayName = 'AxoItem.Body';
|
||||
|
||||
/**
|
||||
* <AxoItem.Title>
|
||||
* <AxoItem.Label>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type TitleProps = Readonly<{
|
||||
export type LabelProps = Readonly<{
|
||||
id?: string;
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Title: FC<TitleProps> = memo(props => {
|
||||
export const Label: FC<LabelProps> = memo(props => {
|
||||
return (
|
||||
<AriaList.Label asChild id={props.id}>
|
||||
<AxoBaseItem.Title>{props.children}</AxoBaseItem.Title>
|
||||
<AxoBaseItem.Label>{props.children}</AxoBaseItem.Label>
|
||||
</AriaList.Label>
|
||||
);
|
||||
});
|
||||
|
||||
Title.displayName = 'AxoItem.Title';
|
||||
Label.displayName = 'AxoItem.Label';
|
||||
|
||||
/**
|
||||
* <AxoItem.Value>
|
||||
@@ -286,6 +323,21 @@ export namespace AxoItem {
|
||||
|
||||
IconAction.displayName = 'AxoItem.IconAction';
|
||||
|
||||
/**
|
||||
* <AxoItem.Trailing>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type TrailingProps = Readonly<{
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Trailing: FC<TrailingProps> = memo(props => {
|
||||
return <AxoBaseItem.Trailing>{props.children}</AxoBaseItem.Trailing>;
|
||||
});
|
||||
|
||||
Trailing.displayName = 'AxoItem.Trailing';
|
||||
|
||||
/**
|
||||
* <AxoItem.Arrow>
|
||||
* --------------------------------------------------------------------------
|
||||
|
||||
@@ -18,10 +18,12 @@ function ExampleItems() {
|
||||
return (
|
||||
<AxoItem.Group>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="info" />
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol="info-circle" />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>First Item</AxoItem.Title>
|
||||
<AxoItem.Label>First Item</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
Description of the first item
|
||||
</AxoItem.Description>
|
||||
@@ -30,10 +32,12 @@ function ExampleItems() {
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="info" />
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol="info-circle" />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Second Item</AxoItem.Title>
|
||||
<AxoItem.Label>Second Item</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
Description of the second item
|
||||
</AxoItem.Description>
|
||||
@@ -42,10 +46,12 @@ function ExampleItems() {
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Icon symbol="info" />
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol="info-circle" />
|
||||
</AxoItem.Leading>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>Third Item</AxoItem.Title>
|
||||
<AxoItem.Label>Third Item</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
Description of the third item
|
||||
</AxoItem.Description>
|
||||
@@ -74,7 +80,7 @@ export function WithTitle(): React.JSX.Element {
|
||||
<div className={tw('bg-surface-secondary p-8')}>
|
||||
<AxoList.Root>
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>List Title</AxoList.Title>
|
||||
<AxoList.Label>List Title</AxoList.Label>
|
||||
</AxoList.Header>
|
||||
<AxoList.Body>
|
||||
<ExampleItems />
|
||||
@@ -89,7 +95,7 @@ export function WithDescription(): React.JSX.Element {
|
||||
<div className={tw('bg-surface-secondary p-8')}>
|
||||
<AxoList.Root>
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>List Title</AxoList.Title>
|
||||
<AxoList.Label>List Title</AxoList.Label>
|
||||
<AxoList.Description>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
</AxoList.Description>
|
||||
@@ -102,20 +108,20 @@ export function WithDescription(): React.JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
export function WithHelp(): React.JSX.Element {
|
||||
export function WithFooterDescription(): React.JSX.Element {
|
||||
return (
|
||||
<div className={tw('bg-surface-secondary p-8')}>
|
||||
<AxoList.Root>
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>List Title</AxoList.Title>
|
||||
<AxoList.Label>List Title</AxoList.Label>
|
||||
</AxoList.Header>
|
||||
<AxoList.Body>
|
||||
<ExampleItems />
|
||||
</AxoList.Body>
|
||||
<AxoList.Footer>
|
||||
<AxoList.Help>
|
||||
<AxoList.FooterDescription>
|
||||
This is some helpful text that describes the section above.
|
||||
</AxoList.Help>
|
||||
</AxoList.FooterDescription>
|
||||
</AxoList.Footer>
|
||||
</AxoList.Root>
|
||||
</div>
|
||||
@@ -133,19 +139,21 @@ export function MultipleLists(): React.JSX.Element {
|
||||
|
||||
<AxoList.Root>
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>Second Section</AxoList.Title>
|
||||
<AxoList.Label>Second Section</AxoList.Label>
|
||||
</AxoList.Header>
|
||||
<AxoList.Body>
|
||||
<ExampleItems />
|
||||
</AxoList.Body>
|
||||
<AxoList.Footer>
|
||||
<AxoList.Help>Help text for the second section.</AxoList.Help>
|
||||
<AxoList.FooterDescription>
|
||||
Help text for the second section.
|
||||
</AxoList.FooterDescription>
|
||||
</AxoList.Footer>
|
||||
</AxoList.Root>
|
||||
|
||||
<AxoList.Root>
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>Third Section</AxoList.Title>
|
||||
<AxoList.Label>Third Section</AxoList.Label>
|
||||
</AxoList.Header>
|
||||
<AxoList.Body>
|
||||
<ExampleItems />
|
||||
|
||||
@@ -42,15 +42,15 @@ export namespace AxoList {
|
||||
Header.displayName = 'AxoList.Header';
|
||||
|
||||
/**
|
||||
* <AxoList.Title>
|
||||
* <AxoList.Label>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type TitleProps = Readonly<{
|
||||
export type LabelProps = Readonly<{
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Title: FC<TitleProps> = memo(props => {
|
||||
export const Label: FC<LabelProps> = memo(props => {
|
||||
return (
|
||||
<AriaLabelled.Label asChild>
|
||||
<h2 className={tw('type-body-medium font-semibold')}>
|
||||
@@ -60,7 +60,7 @@ export namespace AxoList {
|
||||
);
|
||||
});
|
||||
|
||||
Title.displayName = 'AxoList.Title';
|
||||
Label.displayName = 'AxoList.Label';
|
||||
|
||||
/**
|
||||
* <AxoList.Description>
|
||||
@@ -95,7 +95,7 @@ export namespace AxoList {
|
||||
<div
|
||||
className={tw(
|
||||
'min-w-fit',
|
||||
'curved-20 bg-surface-card p-1.5 shadow-elevation-0',
|
||||
'curved-2xl bg-surface-card p-1 shadow-elevation-0',
|
||||
'forced-colors:bg-[Canvas] forced-colors:text-[CanvasText]',
|
||||
'forced-colors:border forced-colors:border-[ButtonBorder]'
|
||||
)}
|
||||
@@ -123,15 +123,15 @@ export namespace AxoList {
|
||||
Footer.displayName = 'AxoList.Footer';
|
||||
|
||||
/**
|
||||
* <AxoList.Help>
|
||||
* <AxoList.FooterDescription>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type HelpProps = Readonly<{
|
||||
export type FooterDescriptionProps = Readonly<{
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Help: FC<HelpProps> = memo(props => {
|
||||
export const FooterDescription: FC<FooterDescriptionProps> = memo(props => {
|
||||
return (
|
||||
<AriaLabelled.Description asChild>
|
||||
<p
|
||||
@@ -146,5 +146,5 @@ export namespace AxoList {
|
||||
);
|
||||
});
|
||||
|
||||
Help.displayName = 'AxoList.Help';
|
||||
FooterDescription.displayName = 'AxoList.FooterDescription';
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export namespace AxoRadioGroupList {
|
||||
<AxoList.Root>
|
||||
{props.title != null && (
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>{props.title}</AxoList.Title>
|
||||
<AxoList.Label>{props.title}</AxoList.Label>
|
||||
{/* We probably don't ever want to show a description without a title */}
|
||||
{props.description != null && (
|
||||
<AxoList.Description>{props.description}</AxoList.Description>
|
||||
@@ -50,7 +50,7 @@ export namespace AxoRadioGroupList {
|
||||
</AxoList.Body>
|
||||
{props.help != null && (
|
||||
<AxoList.Footer>
|
||||
<AxoList.Help>{props.help}</AxoList.Help>
|
||||
<AxoList.FooterDescription>{props.help}</AxoList.FooterDescription>
|
||||
</AxoList.Footer>
|
||||
)}
|
||||
</AxoList.Root>
|
||||
@@ -78,9 +78,9 @@ export namespace AxoRadioGroupList {
|
||||
asChild
|
||||
>
|
||||
<AxoBaseItem.Root>
|
||||
<AxoBaseItem.LeadingSlot>
|
||||
<AxoBaseItem.Leading>
|
||||
<AxoBaseRadioGroup.Indicator />
|
||||
</AxoBaseItem.LeadingSlot>
|
||||
</AxoBaseItem.Leading>
|
||||
<AxoBaseItem.Content>
|
||||
<AxoBaseItem.Body>{props.children}</AxoBaseItem.Body>
|
||||
</AxoBaseItem.Content>
|
||||
@@ -103,7 +103,7 @@ export namespace AxoRadioGroupList {
|
||||
export const Label: FC<LabelProps> = memo(props => {
|
||||
return (
|
||||
<AxoBaseRadioGroup.Label asChild>
|
||||
<AxoBaseItem.Title>{props.children}</AxoBaseItem.Title>
|
||||
<AxoBaseItem.Label>{props.children}</AxoBaseItem.Label>
|
||||
</AxoBaseRadioGroup.Label>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright 2026 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
@utility axo-item-centering-to-max-height {
|
||||
@apply flex h-full min-h-fit items-center;
|
||||
/* --axo-leading-body-medium + --axo-leading-body-small + (description margin top) */
|
||||
max-height: 38px;
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.axo-item-group {
|
||||
@apply grid;
|
||||
@apply min-w-90;
|
||||
grid-template-columns:
|
||||
[axo-item-leading] min-content
|
||||
[axo-item-content] auto;
|
||||
}
|
||||
|
||||
:where(.axo-item-group) .axo-item-root:where(.group) {
|
||||
@apply p-0.5;
|
||||
/* Forward Grid */
|
||||
@apply col-span-full grid grid-cols-subgrid;
|
||||
}
|
||||
|
||||
:where(.axo-item-root) .axo-item-root-inner {
|
||||
/* Forward Grid */
|
||||
@apply col-span-full grid grid-cols-subgrid;
|
||||
@apply gap-x-3 curved-xl px-3 text-primary;
|
||||
/* Hovered */
|
||||
@apply group-data-hovered:bg-secondary;
|
||||
/* Pressed */
|
||||
@apply group-data-pressed:bg-secondary-pressed;
|
||||
/* Focus ring */
|
||||
@apply outline-none;
|
||||
@apply keyboard-mode:group-data-focused:axo-focus-ring;
|
||||
@apply keyboard-mode:group-focus:axo-focus-ring;
|
||||
}
|
||||
|
||||
:where(.axo-item-root-inner) .axo-item-leading {
|
||||
grid-column: axo-item-leading;
|
||||
@apply self-start;
|
||||
@apply axo-item-centering-to-max-height;
|
||||
}
|
||||
|
||||
:where(.axo-item-root-inner) .axo-item-content {
|
||||
grid-column: axo-item-content;
|
||||
@apply self-center;
|
||||
@apply min-w-0;
|
||||
/* Leave room for focus rings */
|
||||
@apply -m-1;
|
||||
}
|
||||
|
||||
:where(.axo-item-content) .axo-item-content-inner {
|
||||
@apply flex;
|
||||
@apply p-1;
|
||||
@apply h-full;
|
||||
}
|
||||
|
||||
:where(.axo-item-content-inner) .axo-item-body {
|
||||
@apply shrink grow;
|
||||
@apply grid;
|
||||
}
|
||||
|
||||
:where(.axo-item-body) .axo-item-label {
|
||||
@apply type-body-medium text-primary;
|
||||
}
|
||||
|
||||
:where(.axo-item-body) .axo-item-value {
|
||||
@apply type-body-medium text-secondary;
|
||||
}
|
||||
|
||||
:where(.axo-item-body) .axo-item-description {
|
||||
@apply mt-0.5;
|
||||
@apply type-body-small text-secondary forced-colors:text-[GrayText];
|
||||
@apply min-w-[min(max-content,120px)];
|
||||
@apply wrap-break-word [word-break:auto-phrase];
|
||||
}
|
||||
|
||||
:where(.axo-item-body) .axo-item-accessory {
|
||||
@apply flex items-center gap-1.5;
|
||||
}
|
||||
|
||||
:where(.axo-item-content-inner) .axo-item-trailing {
|
||||
@apply axo-item-centering-to-max-height;
|
||||
@apply ml-1.5;
|
||||
}
|
||||
|
||||
:where(.axo-item-trailing) .axo-item-arrow {
|
||||
@apply type-body-medium text-placeholder;
|
||||
}
|
||||
|
||||
/* When not overflowing container */
|
||||
@container scroll-state(scrollable: none) {
|
||||
.axo-item-body {
|
||||
grid-template:
|
||||
'axo-item-label axo-item-value axo-item-accessory' 1fr
|
||||
'axo-item-description axo-item-value axo-item-accessory' min-content / auto min-content min-content;
|
||||
}
|
||||
|
||||
.axo-item-label {
|
||||
grid-area: axo-item-label;
|
||||
@apply self-center;
|
||||
@apply text-nowrap;
|
||||
}
|
||||
|
||||
.axo-item-value {
|
||||
grid-area: axo-item-value;
|
||||
@apply w-fit text-nowrap;
|
||||
@apply ms-3;
|
||||
@apply axo-item-centering-to-max-height;
|
||||
}
|
||||
|
||||
.axo-item-description {
|
||||
grid-area: axo-item-description;
|
||||
@apply contain-inline-size contain-layout;
|
||||
}
|
||||
|
||||
.axo-item-accessory {
|
||||
grid-area: axo-item-accessory;
|
||||
@apply ms-3;
|
||||
}
|
||||
}
|
||||
|
||||
/* When overflowing container */
|
||||
@container scroll-state(scrollable: inline) {
|
||||
.axo-item-content-inner {
|
||||
width: calc(100% + 1px);
|
||||
padding-inline-end: 1px;
|
||||
}
|
||||
|
||||
.axo-item-accessory {
|
||||
@apply mt-0.5;
|
||||
@apply flex-col items-stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,39 +15,49 @@ import { AxoButton } from '../AxoButton.dom.tsx';
|
||||
import { AxoCheckbox } from '../AxoCheckbox.dom.tsx';
|
||||
import { AxoAvatar } from '../AxoAvatar.dom.tsx';
|
||||
import { variants } from '../_internal/variants.dom.tsx';
|
||||
import { FlexWrapDetector } from '../_internal/FlexWrapDetector.dom.tsx';
|
||||
|
||||
const LEADING_SLOT = 'axo-item-leading-slot';
|
||||
const CONTENT_SLOT = 'axo-item-content-slot';
|
||||
const TRAILING_SLOT = 'axo-item-trailing-slot';
|
||||
|
||||
const GRID_TEMPLATE_COLUMNS =
|
||||
`[${LEADING_SLOT}] min-content ` +
|
||||
`[${CONTENT_SLOT}] auto ` +
|
||||
`[${TRAILING_SLOT}] min-content`;
|
||||
const AXO_ITEM_GROUP_CLASS = 'axo-item-group';
|
||||
const AXO_ITEM_ROOT_CLASS = 'axo-item-root';
|
||||
const AXO_ITEM_ROOT_INNER_CLASS = 'axo-item-root-inner';
|
||||
const AXO_ITEM_LEADING_CLASS = 'axo-item-leading';
|
||||
const AXO_ITEM_CONTENT_CLASS = 'axo-item-content';
|
||||
const AXO_ITEM_CONTENT_INNER_CLASS = 'axo-item-content-inner';
|
||||
const AXO_ITEM_BODY_CLASS = 'axo-item-body';
|
||||
const AXO_ITEM_LABEL_CLASS = 'axo-item-label';
|
||||
const AXO_ITEM_ACCESSORY_CLASS = 'axo-item-accessory';
|
||||
const AXO_ITEM_VALUE_CLASS = 'axo-item-value';
|
||||
const AXO_ITEM_DESCRIPTION_CLASS = 'axo-item-description';
|
||||
const AXO_ITEM_TRAILING_CLASS = 'axo-item-trailing';
|
||||
const AXO_ITEM_ARROW_CLASS = 'axo-item-arrow';
|
||||
|
||||
/**
|
||||
* @example Anatomy
|
||||
* ```tsx
|
||||
* <AxoBaseItem.Group>
|
||||
* <AxoBaseItem.Root>
|
||||
* <AxoBaseItem.Icon />
|
||||
* <AxoBaseItem.Leading>
|
||||
* <AxoBaseItem.Icon />
|
||||
* </AxoBaseItem.Leading>
|
||||
* <AxoBaseItem.Content>
|
||||
* <AxoBaseItem.Body>
|
||||
* <AxoBaseItem.Title />
|
||||
* <AxoBaseItem.Label />
|
||||
* <AxoBaseItem.Value />
|
||||
* <AxoBaseItem.Description />
|
||||
* <AxoBaseItem.HiddenTrigger />
|
||||
* <AxoBaseItem.Accessory>
|
||||
* <AxoBaseItem.Action />
|
||||
* <AxoBaseItem.IconAction />
|
||||
* <AxoSelect.Root />
|
||||
* <AxoSwitch.Root />
|
||||
* </AxoBaseItem.Accessory>
|
||||
* </AxoBaseItem.Body>
|
||||
* <AxoBaseItem.Accessory>
|
||||
* <AxoBaseItem.Action />
|
||||
* <AxoBaseItem.IconAction />
|
||||
* <AxoSelect.Root />
|
||||
* <AxoSwitch.Root />
|
||||
* </AxoBaseItem.Accessory>
|
||||
* <AxoBaseItem.Trailing>
|
||||
* <AxoBaseItem.Arrow />
|
||||
* </AxoBaseItem.Trailing>
|
||||
* </AxoBaseItem.Content>
|
||||
* <AxoBaseItem.Arrow />
|
||||
* </AxoBaseItem.Root>
|
||||
* </AxoBaseItem.Layout>
|
||||
* </AxoBaseItem.Group>
|
||||
* ```
|
||||
*/
|
||||
export namespace AxoBaseItem {
|
||||
@@ -82,13 +92,8 @@ export namespace AxoBaseItem {
|
||||
<GroupContext value={context}>
|
||||
<div
|
||||
ref={ref}
|
||||
className={tw('grid min-w-90')}
|
||||
className={AXO_ITEM_GROUP_CLASS}
|
||||
{...forwardExtraPropsForRadix(rest)}
|
||||
// Style needs to come after forwarded props. Long-term we should
|
||||
// figure out how to automatically merge props like these
|
||||
style={{
|
||||
gridTemplateColumns: GRID_TEMPLATE_COLUMNS,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
@@ -119,28 +124,13 @@ export namespace AxoBaseItem {
|
||||
return (
|
||||
<AriaClickable.Root asChild>
|
||||
<div
|
||||
className={tw(
|
||||
'group',
|
||||
// forward grid
|
||||
'col-span-full grid grid-cols-subgrid',
|
||||
'p-0.5',
|
||||
'outline-none'
|
||||
)}
|
||||
className={tw(AXO_ITEM_ROOT_CLASS, 'group')}
|
||||
{...forwardExtraPropsForRadix(rest)}
|
||||
>
|
||||
<div
|
||||
className={tw(
|
||||
// forward grid
|
||||
'col-span-full grid grid-cols-subgrid',
|
||||
'gap-x-3 px-3',
|
||||
RootSpacing.get(groupContext.spacing),
|
||||
'items-baseline',
|
||||
'text-primary',
|
||||
'curved-14',
|
||||
'group-data-hovered:bg-secondary',
|
||||
'group-data-pressed:bg-secondary-pressed',
|
||||
'outline-none keyboard-mode:group-data-focused:axo-focus-ring',
|
||||
'keyboard-mode:group-focus:axo-focus-ring'
|
||||
AXO_ITEM_ROOT_INNER_CLASS,
|
||||
RootSpacing.get(groupContext.spacing)
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
@@ -153,46 +143,19 @@ export namespace AxoBaseItem {
|
||||
Root.displayName = 'AxoBaseItem.Root';
|
||||
|
||||
/**
|
||||
* <AxoBaseItem.LeadingSlot>
|
||||
* <AxoBaseItem.Leading>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type LeadingSlotProps = Readonly<{
|
||||
className?: string;
|
||||
export type LeadingProps = Readonly<{
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const LeadingSlot: FC<LeadingSlotProps> = memo(props => {
|
||||
return (
|
||||
<div style={{ gridColumn: LEADING_SLOT }} className={props.className}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
export const Leading: FC<LeadingProps> = memo(props => {
|
||||
return <div className={AXO_ITEM_LEADING_CLASS}>{props.children}</div>;
|
||||
});
|
||||
|
||||
LeadingSlot.displayName = 'AxoBaseItem.LeadingSlot';
|
||||
|
||||
/**
|
||||
* <AxoBaseItem.TrailingSlot>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @internal */
|
||||
type TrailingSlotProps = Readonly<{
|
||||
className?: string;
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
/** @internal */
|
||||
const TrailingSlot: FC<TrailingSlotProps> = memo(props => {
|
||||
return (
|
||||
<div style={{ gridColumn: TRAILING_SLOT }} className={props.className}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
TrailingSlot.displayName = 'AxoBaseItem.TrailingSlot';
|
||||
Leading.displayName = 'AxoBaseItem.Leading';
|
||||
|
||||
/**
|
||||
* <AxoBaseItem.Icon>
|
||||
@@ -204,11 +167,7 @@ export namespace AxoBaseItem {
|
||||
}>;
|
||||
|
||||
export const Icon: FC<IconProps> = memo(props => {
|
||||
return (
|
||||
<LeadingSlot>
|
||||
<AxoSymbol.Icon size={18} symbol={props.symbol} label={null} />
|
||||
</LeadingSlot>
|
||||
);
|
||||
return <AxoSymbol.Icon size={18} symbol={props.symbol} label={null} />;
|
||||
});
|
||||
|
||||
Icon.displayName = 'AxoBaseItem.Icon';
|
||||
@@ -228,14 +187,12 @@ export namespace AxoBaseItem {
|
||||
|
||||
export const Checkbox: FC<CheckboxProps> = memo(props => {
|
||||
return (
|
||||
<LeadingSlot>
|
||||
<AxoCheckbox.Root
|
||||
id={props.id}
|
||||
variant="square"
|
||||
checked={props.checked}
|
||||
onCheckedChange={props.onCheckedChange}
|
||||
/>
|
||||
</LeadingSlot>
|
||||
<AxoCheckbox.Root
|
||||
id={props.id}
|
||||
variant="square"
|
||||
checked={props.checked}
|
||||
onCheckedChange={props.onCheckedChange}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -255,13 +212,11 @@ export namespace AxoBaseItem {
|
||||
|
||||
export const IconAvatar: FC<IconAvatarProps> = memo(props => {
|
||||
return (
|
||||
<LeadingSlot>
|
||||
<AxoAvatar.Root size={props.size}>
|
||||
<AxoAvatar.Content label={null}>
|
||||
<AxoAvatar.Icon symbol={props.symbol} />
|
||||
</AxoAvatar.Content>
|
||||
</AxoAvatar.Root>
|
||||
</LeadingSlot>
|
||||
<AxoAvatar.Root size={props.size}>
|
||||
<AxoAvatar.Content label={null}>
|
||||
<AxoAvatar.Icon symbol={props.symbol} />
|
||||
</AxoAvatar.Content>
|
||||
</AxoAvatar.Root>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -278,16 +233,10 @@ export namespace AxoBaseItem {
|
||||
|
||||
export const Content: FC<ContentProps> = memo(props => {
|
||||
return (
|
||||
<div
|
||||
style={{ gridColumn: CONTENT_SLOT }}
|
||||
className={tw(
|
||||
'flex min-w-50 grow basis-0 flex-wrap',
|
||||
'self-stretch',
|
||||
'items-baseline',
|
||||
'gap-x-3 gap-y-2'
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
<div className={AXO_ITEM_CONTENT_CLASS}>
|
||||
<FlexWrapDetector>
|
||||
<div className={AXO_ITEM_CONTENT_INNER_CLASS}>{props.children}</div>
|
||||
</FlexWrapDetector>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
@@ -304,18 +253,7 @@ export namespace AxoBaseItem {
|
||||
}>;
|
||||
|
||||
export const Body: FC<BodyProps> = memo(props => {
|
||||
return (
|
||||
<div
|
||||
className={tw(
|
||||
'flex shrink grow basis-0 flex-wrap',
|
||||
'min-w-50', // Note: We need an absolute length for min-width for description to truncate (even if its 0)
|
||||
'self-center-safe',
|
||||
'gap-x-3 gap-y-0.5'
|
||||
)}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
return <div className={AXO_ITEM_BODY_CLASS}>{props.children}</div>;
|
||||
});
|
||||
|
||||
Body.displayName = 'AxoBaseItem.Body';
|
||||
@@ -325,24 +263,18 @@ export namespace AxoBaseItem {
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type TitleProps = Readonly<{
|
||||
export type LabelProps = Readonly<{
|
||||
ref?: Ref<HTMLDivElement>;
|
||||
truncate?: boolean;
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Title: FC<TitleProps> = memo(props => {
|
||||
export const Label: FC<LabelProps> = memo(props => {
|
||||
const { ref, truncate, children, ...rest } = props;
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={tw(
|
||||
'min-w-50', // force value to next line if there's not much space
|
||||
'grow-[calc(infinity)]',
|
||||
'type-body-medium text-primary',
|
||||
truncate ? 'truncate' : 'line-clamp-2',
|
||||
'-my-0.75 py-0.75' // extra space for focus rings
|
||||
)}
|
||||
className={tw(AXO_ITEM_LABEL_CLASS, truncate && 'truncate')}
|
||||
{...forwardExtraPropsForRadix(rest)}
|
||||
>
|
||||
{children}
|
||||
@@ -350,7 +282,7 @@ export namespace AxoBaseItem {
|
||||
);
|
||||
});
|
||||
|
||||
Title.displayName = 'AxoBaseItem.Title';
|
||||
Label.displayName = 'AxoBaseItem.Label';
|
||||
|
||||
/**
|
||||
* <AxoBaseItem.Value>
|
||||
@@ -367,7 +299,7 @@ export namespace AxoBaseItem {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={tw('w-fit grow type-body-medium text-secondary')}
|
||||
className={AXO_ITEM_VALUE_CLASS}
|
||||
{...forwardExtraPropsForRadix(rest)}
|
||||
>
|
||||
{children}
|
||||
@@ -391,23 +323,13 @@ export namespace AxoBaseItem {
|
||||
export const Description: FC<DescriptionProps> = memo(props => {
|
||||
const { ref, truncate, children, ...rest } = props;
|
||||
return (
|
||||
<>
|
||||
{/* Force description to its own line */}
|
||||
<div className={tw('basis-full')} />
|
||||
<div
|
||||
ref={ref}
|
||||
className={tw(
|
||||
'min-w-0',
|
||||
'type-body-small text-secondary',
|
||||
'forced-colors:text-[GrayText]',
|
||||
truncate && 'truncate',
|
||||
'-my-0.5 py-0.5' // extra space for focus rings
|
||||
)}
|
||||
{...forwardExtraPropsForRadix(rest)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</>
|
||||
<div
|
||||
ref={ref}
|
||||
className={tw(AXO_ITEM_DESCRIPTION_CLASS, truncate && 'truncate')}
|
||||
{...forwardExtraPropsForRadix(rest)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -446,11 +368,7 @@ export namespace AxoBaseItem {
|
||||
}>;
|
||||
|
||||
export const Accessory: FC<AccessoryProps> = memo(props => {
|
||||
return (
|
||||
<AriaClickable.DeadArea className={tw('flex gap-1.5')}>
|
||||
{props.children}
|
||||
</AriaClickable.DeadArea>
|
||||
);
|
||||
return <div className={AXO_ITEM_ACCESSORY_CLASS}>{props.children}</div>;
|
||||
});
|
||||
|
||||
Accessory.displayName = 'AxoBaseItem.Accessory';
|
||||
@@ -527,6 +445,21 @@ export namespace AxoBaseItem {
|
||||
|
||||
IconAction.displayName = 'AxoBaseItem.IconAction';
|
||||
|
||||
/**
|
||||
* <AxoBaseItem.Trailing>
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
export type TrailingProps = Readonly<{
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
export const Trailing: FC<TrailingProps> = memo(props => {
|
||||
return <div className={AXO_ITEM_TRAILING_CLASS}>{props.children}</div>;
|
||||
});
|
||||
|
||||
Trailing.displayName = 'AxoBaseItem.Trailing';
|
||||
|
||||
/**
|
||||
* <AxoBaseItem.Arrow>
|
||||
* --------------------------------------------------------------------------
|
||||
@@ -534,11 +467,9 @@ export namespace AxoBaseItem {
|
||||
|
||||
export const Arrow: FC = memo(() => {
|
||||
return (
|
||||
<TrailingSlot
|
||||
className={tw('shrink-0 type-body-medium text-placeholder')}
|
||||
>
|
||||
<div className={AXO_ITEM_ARROW_CLASS}>
|
||||
<AxoSymbol.InlineGlyph label={null} symbol="chevron-[end]" />
|
||||
</TrailingSlot>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
+152
-132
@@ -864,30 +864,32 @@ export function Preferences({
|
||||
} else if (settingsLocation.page === SettingsPage.General) {
|
||||
const pageContents = (
|
||||
<ListGroup>
|
||||
<List help={i18n('icu:Preferences--device-name__description')}>
|
||||
<List
|
||||
footerDescription={i18n('icu:Preferences--device-name__description')}
|
||||
>
|
||||
<ValueItem
|
||||
title={i18n('icu:Preferences--phone-number')}
|
||||
label={i18n('icu:Preferences--phone-number')}
|
||||
value={phoneNumber}
|
||||
/>
|
||||
<ValueItem
|
||||
title={i18n('icu:Preferences--device-name')}
|
||||
label={i18n('icu:Preferences--device-name')}
|
||||
value={deviceName}
|
||||
/>
|
||||
</List>
|
||||
{weArePrimaryDevice && (
|
||||
<List title={i18n('icu:Preferences--signal-pin')}>
|
||||
<List label={i18n('icu:Preferences--signal-pin')}>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences--pin-reminders--header')}
|
||||
label={i18n('icu:Preferences--pin-reminders--header')}
|
||||
description={i18n('icu:Preferences--pin-reminders--description')}
|
||||
checked={hasPinReminders ?? false}
|
||||
onCheckedChange={onPinRemindersChange}
|
||||
/>
|
||||
</List>
|
||||
)}
|
||||
<List title={i18n('icu:Preferences--system')}>
|
||||
<List label={i18n('icu:Preferences--system')}>
|
||||
{isAutoLaunchSupported && (
|
||||
<SwitchItem
|
||||
title={i18n('icu:autoLaunchDescription')}
|
||||
label={i18n('icu:autoLaunchDescription')}
|
||||
disabled={hasAutoLaunch === undefined}
|
||||
checked={hasAutoLaunch ?? false}
|
||||
onCheckedChange={onAutoLaunchChange}
|
||||
@@ -895,7 +897,7 @@ export function Preferences({
|
||||
)}
|
||||
{isHideMenuBarSupported && (
|
||||
<SwitchItem
|
||||
title={i18n('icu:hideMenuBar')}
|
||||
label={i18n('icu:hideMenuBar')}
|
||||
checked={hasHideMenuBar ?? false}
|
||||
onCheckedChange={onHideMenuBarChange}
|
||||
/>
|
||||
@@ -903,14 +905,14 @@ export function Preferences({
|
||||
{isSystemTraySupported && (
|
||||
<>
|
||||
<SwitchItem
|
||||
title={i18n('icu:SystemTraySetting__minimize-to-system-tray')}
|
||||
label={i18n('icu:SystemTraySetting__minimize-to-system-tray')}
|
||||
disabled={hasMinimizeToSystemTray === undefined}
|
||||
checked={hasMinimizeToSystemTray ?? false}
|
||||
onCheckedChange={onMinimizeToSystemTrayChange}
|
||||
/>
|
||||
{isMinimizeToAndStartInSystemTraySupported && (
|
||||
<SwitchItem
|
||||
title={i18n(
|
||||
label={i18n(
|
||||
'icu:SystemTraySetting__minimize-to-and-start-in-system-tray'
|
||||
)}
|
||||
disabled={
|
||||
@@ -924,24 +926,24 @@ export function Preferences({
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
<List title={i18n('icu:permissions')}>
|
||||
<List label={i18n('icu:permissions')}>
|
||||
<SwitchItem
|
||||
title={i18n('icu:mediaPermissionsDescription')}
|
||||
label={i18n('icu:mediaPermissionsDescription')}
|
||||
disabled={hasMediaPermissions === undefined}
|
||||
checked={hasMediaPermissions ?? false}
|
||||
onCheckedChange={onMediaPermissionsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:mediaCameraPermissionsDescription')}
|
||||
label={i18n('icu:mediaCameraPermissionsDescription')}
|
||||
disabled={hasMediaCameraPermissions === undefined}
|
||||
checked={hasMediaCameraPermissions ?? false}
|
||||
onCheckedChange={onMediaCameraPermissionsChange}
|
||||
/>
|
||||
</List>
|
||||
{isAutoDownloadUpdatesSupported && (
|
||||
<List title={i18n('icu:Preferences--updates')}>
|
||||
<List label={i18n('icu:Preferences--updates')}>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__download-update')}
|
||||
label={i18n('icu:Preferences__download-update')}
|
||||
checked={hasAutoDownloadUpdate}
|
||||
onCheckedChange={onAutoDownloadUpdateChange}
|
||||
/>
|
||||
@@ -951,7 +953,7 @@ export function Preferences({
|
||||
<List>
|
||||
{!weArePrimaryDevice && (
|
||||
<ItemWithAction
|
||||
title={i18n('icu:clearDataHeader')}
|
||||
label={i18n('icu:clearDataHeader')}
|
||||
description={i18n('icu:clearDataExplanation')}
|
||||
action={
|
||||
<AxoItem.Action
|
||||
@@ -980,7 +982,7 @@ export function Preferences({
|
||||
|
||||
{weArePrimaryDevice && (
|
||||
<ItemWithAction
|
||||
title={i18n('icu:deleteAccountHeader')}
|
||||
label={i18n('icu:deleteAccountHeader')}
|
||||
description={i18n('icu:deleteAccountExplanation')}
|
||||
action={
|
||||
<AxoItem.Action
|
||||
@@ -1050,7 +1052,7 @@ export function Preferences({
|
||||
<List>
|
||||
<ClickableItem
|
||||
symbol="globe"
|
||||
title={i18n('icu:Preferences__Language__Label')}
|
||||
label={i18n('icu:Preferences__Language__Label')}
|
||||
arrow
|
||||
value={
|
||||
<span
|
||||
@@ -1176,7 +1178,7 @@ export function Preferences({
|
||||
)}
|
||||
<SelectItem
|
||||
symbol="contrast"
|
||||
title={i18n('icu:Preferences--theme')}
|
||||
label={i18n('icu:Preferences--theme')}
|
||||
disabled={themeSetting === undefined}
|
||||
value={themeSetting ?? null}
|
||||
onValueChange={value => {
|
||||
@@ -1200,8 +1202,8 @@ export function Preferences({
|
||||
/>
|
||||
<ClickableItem
|
||||
symbol="palette"
|
||||
title={i18n('icu:showChatColorEditor')}
|
||||
arrow={false}
|
||||
label={i18n('icu:showChatColorEditor')}
|
||||
arrow
|
||||
onClick={() => {
|
||||
setSettingsLocation({ page: SettingsPage.ChatColor });
|
||||
}}
|
||||
@@ -1218,7 +1220,7 @@ export function Preferences({
|
||||
/>
|
||||
<SelectItem
|
||||
symbol="zoom-in"
|
||||
title={i18n('icu:Preferences--zoom')}
|
||||
label={i18n('icu:Preferences--zoom')}
|
||||
disabled={zoomFactor === undefined}
|
||||
value={zoomFactor != null ? String(zoomFactor) : null}
|
||||
onValueChange={onZoomSelectChange}
|
||||
@@ -1258,7 +1260,7 @@ export function Preferences({
|
||||
<ListGroup>
|
||||
<List accessibilityLabel={i18n('icu:Preferences__button--chats')}>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__address-book-photos--title')}
|
||||
label={i18n('icu:Preferences__address-book-photos--title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__address-book-photos--description'
|
||||
)}
|
||||
@@ -1266,7 +1268,7 @@ export function Preferences({
|
||||
onCheckedChange={onPreferContactAvatarsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__keep-muted-chats-archived--title')}
|
||||
label={i18n('icu:Preferences__keep-muted-chats-archived--title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__keep-muted-chats-archived--description'
|
||||
)}
|
||||
@@ -1274,21 +1276,21 @@ export function Preferences({
|
||||
onCheckedChange={onKeepMutedChatsArchivedChange}
|
||||
/>
|
||||
</List>
|
||||
<List title={i18n('icu:Preferences__Chats__TextInputSection__Title')}>
|
||||
<List label={i18n('icu:Preferences__Chats__TextInputSection__Title')}>
|
||||
<SwitchItem
|
||||
title={i18n('icu:spellCheckDescription')}
|
||||
label={i18n('icu:spellCheckDescription')}
|
||||
description={spellCheckDirtyText}
|
||||
disabled={hasSpellCheck === undefined}
|
||||
checked={hasSpellCheck ?? false}
|
||||
onCheckedChange={onSpellCheckChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:textFormattingDescription')}
|
||||
label={i18n('icu:textFormattingDescription')}
|
||||
checked={hasTextFormatting}
|
||||
onCheckedChange={onTextFormattingChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__link-previews--title')}
|
||||
label={i18n('icu:Preferences__link-previews--title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__link-previews--new-description'
|
||||
)}
|
||||
@@ -1296,7 +1298,7 @@ export function Preferences({
|
||||
onCheckedChange={onLinkPreviewsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__auto-convert-emoji--title')}
|
||||
label={i18n('icu:Preferences__auto-convert-emoji--title')}
|
||||
description={
|
||||
<I18n
|
||||
i18n={i18n}
|
||||
@@ -1308,11 +1310,9 @@ export function Preferences({
|
||||
/>
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>
|
||||
{i18n('icu:Preferences__EmojiSkinToneDefaultSetting__Label')}
|
||||
</AxoItem.Title>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Label>
|
||||
{i18n('icu:Preferences__EmojiSkinToneDefaultSetting__Label')}
|
||||
</AxoItem.Label>
|
||||
<AxoItem.Accessory>
|
||||
<FunSkinTonesList
|
||||
i18n={i18n}
|
||||
@@ -1324,9 +1324,9 @@ export function Preferences({
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
</List>
|
||||
<List title={i18n('icu:Preferences__Chats__ChatFoldersSection__Title')}>
|
||||
<List label={i18n('icu:Preferences__Chats__ChatFoldersSection__Title')}>
|
||||
<ClickableItem
|
||||
title={
|
||||
label={
|
||||
hasAnyCurrentCustomChatFolders
|
||||
? i18n(
|
||||
'icu:Preferences__ChatsPage__ChatFoldersSection__AddChatFolderItem__Title--WithChatFolders'
|
||||
@@ -1358,7 +1358,7 @@ export function Preferences({
|
||||
|
||||
<List>
|
||||
<ItemWithAction
|
||||
title={i18n('icu:PlaintextExport--PreferencesRow--Header')}
|
||||
label={i18n('icu:PlaintextExport--PreferencesRow--Header')}
|
||||
description={i18n(
|
||||
'icu:PlaintextExport--PreferencesRow--Description'
|
||||
)}
|
||||
@@ -1376,7 +1376,7 @@ export function Preferences({
|
||||
{isSyncSupported && (
|
||||
<List>
|
||||
<ItemWithAction
|
||||
title={i18n('icu:sync')}
|
||||
label={i18n('icu:sync')}
|
||||
description={
|
||||
<>
|
||||
<div>
|
||||
@@ -1430,19 +1430,19 @@ export function Preferences({
|
||||
<ListGroup>
|
||||
<List accessibilityLabel={i18n('icu:calling')}>
|
||||
<SwitchItem
|
||||
title={i18n('icu:incomingCallNotificationDescription')}
|
||||
label={i18n('icu:incomingCallNotificationDescription')}
|
||||
checked={hasIncomingCallNotifications}
|
||||
onCheckedChange={onIncomingCallNotificationsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:callRingtoneNotificationDescription')}
|
||||
label={i18n('icu:callRingtoneNotificationDescription')}
|
||||
checked={hasCallRingtoneNotification}
|
||||
onCheckedChange={onCallRingtoneNotificationChange}
|
||||
/>
|
||||
</List>
|
||||
<List title={i18n('icu:Preferences__devices')}>
|
||||
<List label={i18n('icu:Preferences__devices')}>
|
||||
<SelectItem
|
||||
title={i18n('icu:callingDeviceSelection__label--video')}
|
||||
label={i18n('icu:callingDeviceSelection__label--video')}
|
||||
disabled={!availableCameras.length}
|
||||
emptyOptionsLabel={i18n(
|
||||
'icu:callingDeviceSelection__select--no-device'
|
||||
@@ -1458,7 +1458,7 @@ export function Preferences({
|
||||
})}
|
||||
/>
|
||||
<SelectItem
|
||||
title={i18n('icu:callingDeviceSelection__label--audio-input')}
|
||||
label={i18n('icu:callingDeviceSelection__label--audio-input')}
|
||||
disabled={!availableMicrophones.length}
|
||||
value={
|
||||
selectedMicrophone != null
|
||||
@@ -1479,7 +1479,7 @@ export function Preferences({
|
||||
/>
|
||||
|
||||
<SelectItem
|
||||
title={i18n('icu:callingDeviceSelection__label--audio-output')}
|
||||
label={i18n('icu:callingDeviceSelection__label--audio-output')}
|
||||
disabled={!availableSpeakers.length}
|
||||
value={
|
||||
selectedSpeaker != null ? String(selectedSpeaker.index) : null
|
||||
@@ -1497,10 +1497,10 @@ export function Preferences({
|
||||
})}
|
||||
/>
|
||||
</List>
|
||||
<List title={i18n('icu:Preferences--advanced')}>
|
||||
<List label={i18n('icu:Preferences--advanced')}>
|
||||
<SwitchItem
|
||||
description={i18n('icu:alwaysRelayCallsDetail')}
|
||||
title={i18n('icu:alwaysRelayCallsDescription')}
|
||||
label={i18n('icu:alwaysRelayCallsDescription')}
|
||||
checked={hasRelayCalls ?? false}
|
||||
onCheckedChange={onRelayCallsChange}
|
||||
/>
|
||||
@@ -1519,17 +1519,17 @@ export function Preferences({
|
||||
<ListGroup>
|
||||
<List>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__enable-notifications')}
|
||||
label={i18n('icu:Preferences__enable-notifications')}
|
||||
checked={hasNotifications}
|
||||
onCheckedChange={onNotificationsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:callSystemNotificationDescription')}
|
||||
label={i18n('icu:callSystemNotificationDescription')}
|
||||
checked={hasCallNotifications}
|
||||
onCheckedChange={onCallNotificationsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__reaction-notifications-title')}
|
||||
label={i18n('icu:Preferences__reaction-notifications-title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__reaction-notifications-description'
|
||||
)}
|
||||
@@ -1538,13 +1538,13 @@ export function Preferences({
|
||||
/>
|
||||
{isNotificationAttentionSupported && (
|
||||
<SwitchItem
|
||||
title={i18n('icu:notificationDrawAttention')}
|
||||
label={i18n('icu:notificationDrawAttention')}
|
||||
checked={hasNotificationAttention}
|
||||
onCheckedChange={onNotificationAttentionChange}
|
||||
/>
|
||||
)}
|
||||
<SelectItem
|
||||
title={i18n('icu:Preferences--notification-content')}
|
||||
label={i18n('icu:Preferences--notification-content')}
|
||||
disabled={!hasNotifications}
|
||||
value={notificationContent}
|
||||
onValueChange={onNotificationContentChange}
|
||||
@@ -1564,7 +1564,7 @@ export function Preferences({
|
||||
]}
|
||||
/>
|
||||
<ClickableItem
|
||||
title={i18n('icu:WhileMuted__title')}
|
||||
label={i18n('icu:WhileMuted__title')}
|
||||
value={getNotifyWhileMutedSummary(notifyWhileMuted, i18n)}
|
||||
description={i18n('icu:Preferences__WhileMuted__description')}
|
||||
arrow
|
||||
@@ -1576,15 +1576,15 @@ export function Preferences({
|
||||
</List>
|
||||
|
||||
<List
|
||||
title={i18n('icu:Preferences__Notifications__SoundsSection__Title')}
|
||||
label={i18n('icu:Preferences__Notifications__SoundsSection__Title')}
|
||||
>
|
||||
<SwitchItem
|
||||
title={i18n('icu:audioNotificationDescription')}
|
||||
label={i18n('icu:audioNotificationDescription')}
|
||||
checked={hasAudioNotifications ?? false}
|
||||
onCheckedChange={onAudioNotificationsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__message-audio-title')}
|
||||
label={i18n('icu:Preferences__message-audio-title')}
|
||||
description={i18n('icu:Preferences__message-audio-description')}
|
||||
checked={hasMessageAudio}
|
||||
onCheckedChange={onMessageAudioChange}
|
||||
@@ -1592,10 +1592,10 @@ export function Preferences({
|
||||
</List>
|
||||
|
||||
<List
|
||||
title={i18n('icu:Preferences__Notifications__AppBadgeSection__Title')}
|
||||
label={i18n('icu:Preferences__Notifications__AppBadgeSection__Title')}
|
||||
>
|
||||
<SwitchItem
|
||||
title={i18n('icu:countMutedConversationsDescription')}
|
||||
label={i18n('icu:countMutedConversationsDescription')}
|
||||
checked={hasCountMutedConversations}
|
||||
onCheckedChange={onCountMutedConversationsChange}
|
||||
/>
|
||||
@@ -1603,7 +1603,7 @@ export function Preferences({
|
||||
|
||||
<List>
|
||||
<ClickableItem
|
||||
title={i18n('icu:NotificationProfiles--setting')}
|
||||
label={i18n('icu:NotificationProfiles--setting')}
|
||||
description={i18n('icu:NotificationProfiles--manage-description')}
|
||||
arrow
|
||||
onClick={() =>
|
||||
@@ -1616,7 +1616,7 @@ export function Preferences({
|
||||
|
||||
<List>
|
||||
<ItemWithAction
|
||||
title={i18n('icu:Preferences__Notifications__Reset__title')}
|
||||
label={i18n('icu:Preferences__Notifications__Reset__title')}
|
||||
action={
|
||||
<AxoItem.Action
|
||||
variant="subtle-destructive"
|
||||
@@ -1688,7 +1688,7 @@ export function Preferences({
|
||||
<ListGroup>
|
||||
<List>
|
||||
<ClickableItem
|
||||
title={i18n('icu:Preferences__pnp__row--title')}
|
||||
label={i18n('icu:Preferences__pnp__row--title')}
|
||||
description={i18n('icu:Preferences__pnp__row--body')}
|
||||
arrow
|
||||
onClick={() => setSettingsLocation({ page: SettingsPage.PNP })}
|
||||
@@ -1696,7 +1696,7 @@ export function Preferences({
|
||||
</List>
|
||||
<List>
|
||||
<ClickableItem
|
||||
title={i18n('icu:Preferences--blocked')}
|
||||
label={i18n('icu:Preferences--blocked')}
|
||||
description={blockedDescription}
|
||||
arrow
|
||||
disabled={!blockedContacts.length && !blockedGroups.length}
|
||||
@@ -1704,16 +1704,16 @@ export function Preferences({
|
||||
/>
|
||||
</List>
|
||||
<List
|
||||
title={i18n('icu:Preferences--messaging')}
|
||||
help={i18n('icu:Preferences--messaging-help')}
|
||||
label={i18n('icu:Preferences--messaging')}
|
||||
footerDescription={i18n('icu:Preferences--messaging-help')}
|
||||
>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences--read-receipts')}
|
||||
label={i18n('icu:Preferences--read-receipts')}
|
||||
checked={hasReadReceipts}
|
||||
onCheckedChange={onReadReceiptsChange}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences--typing-indicators')}
|
||||
label={i18n('icu:Preferences--typing-indicators')}
|
||||
checked={hasTypingIndicators}
|
||||
onCheckedChange={onTypingIndicatorsChange}
|
||||
/>
|
||||
@@ -1726,9 +1726,9 @@ export function Preferences({
|
||||
onSubmit={onUniversalExpireTimerChange}
|
||||
/>
|
||||
)}
|
||||
<List title={i18n('icu:disappearingMessages')}>
|
||||
<List label={i18n('icu:disappearingMessages')}>
|
||||
<SelectItem
|
||||
title={i18n('icu:settings__DisappearingMessages__timer__label')}
|
||||
label={i18n('icu:settings__DisappearingMessages__timer__label')}
|
||||
description={i18n('icu:settings__DisappearingMessages__footer')}
|
||||
value={String(universalExpireTimer)}
|
||||
onValueChange={value => {
|
||||
@@ -1760,12 +1760,12 @@ export function Preferences({
|
||||
/>
|
||||
</List>
|
||||
{isContentProtectionSupported && (
|
||||
<List title={i18n('icu:Preferences__Privacy__Application')}>
|
||||
<List label={i18n('icu:Preferences__Privacy__Application')}>
|
||||
<SwitchItem
|
||||
description={i18n(
|
||||
'icu:Preferences__content-protection--description'
|
||||
)}
|
||||
title={i18n('icu:Preferences__content-protection--label')}
|
||||
label={i18n('icu:Preferences__content-protection--label')}
|
||||
disabled={hasContentProtection === undefined}
|
||||
checked={hasContentProtection ?? false}
|
||||
onCheckedChange={handleContentProtectionChange}
|
||||
@@ -1790,9 +1790,9 @@ export function Preferences({
|
||||
</AxoConfirmDialog.Action>
|
||||
</AxoConfirmDialog.Root>
|
||||
) : null}
|
||||
<List title={i18n('icu:Stories__title')}>
|
||||
<List label={i18n('icu:Stories__title')}>
|
||||
<ItemWithAction
|
||||
title={i18n('icu:Stories__settings-toggle--title')}
|
||||
label={i18n('icu:Stories__settings-toggle--title')}
|
||||
description={i18n('icu:Stories__settings-toggle--description')}
|
||||
action={
|
||||
hasStoriesDisabled ? (
|
||||
@@ -1813,9 +1813,9 @@ export function Preferences({
|
||||
}
|
||||
/>
|
||||
</List>
|
||||
<List title={i18n('icu:Preferences--advanced')}>
|
||||
<List label={i18n('icu:Preferences--advanced')}>
|
||||
<SwitchItem
|
||||
title={
|
||||
label={
|
||||
<>
|
||||
{i18n('icu:Preferences__PrivacyPage__ShowStatusIcon__Label')}
|
||||
<div className="Preferences__Privacy__StatusIcon" />
|
||||
@@ -1829,7 +1829,7 @@ export function Preferences({
|
||||
/>
|
||||
{isKeyTransparencyAvailable && (
|
||||
<SwitchItem
|
||||
title={i18n(
|
||||
label={i18n(
|
||||
'icu:Preferences__PrivacyPage__KeyTransparency__Label'
|
||||
)}
|
||||
description={
|
||||
@@ -1888,11 +1888,13 @@ export function Preferences({
|
||||
const pageContents = (
|
||||
<ListGroup>
|
||||
<List
|
||||
title={i18n('icu:Preferences__media-auto-download')}
|
||||
help={i18n('icu:Preferences__media-auto-download__description')}
|
||||
label={i18n('icu:Preferences__media-auto-download')}
|
||||
footerDescription={i18n(
|
||||
'icu:Preferences__media-auto-download__description'
|
||||
)}
|
||||
>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__media-auto-download__photos')}
|
||||
label={i18n('icu:Preferences__media-auto-download__photos')}
|
||||
checked={autoDownloadAttachment.photos}
|
||||
onCheckedChange={(newValue: boolean) => {
|
||||
onAutoDownloadAttachmentChange({
|
||||
@@ -1902,7 +1904,7 @@ export function Preferences({
|
||||
}}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__media-auto-download__videos')}
|
||||
label={i18n('icu:Preferences__media-auto-download__videos')}
|
||||
checked={autoDownloadAttachment.videos}
|
||||
onCheckedChange={(newValue: boolean) => {
|
||||
onAutoDownloadAttachmentChange({
|
||||
@@ -1912,7 +1914,7 @@ export function Preferences({
|
||||
}}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__media-auto-download__audio')}
|
||||
label={i18n('icu:Preferences__media-auto-download__audio')}
|
||||
checked={autoDownloadAttachment.audio}
|
||||
onCheckedChange={(newValue: boolean) => {
|
||||
onAutoDownloadAttachmentChange({
|
||||
@@ -1922,7 +1924,7 @@ export function Preferences({
|
||||
}}
|
||||
/>
|
||||
<SwitchItem
|
||||
title={i18n('icu:Preferences__media-auto-download__documents')}
|
||||
label={i18n('icu:Preferences__media-auto-download__documents')}
|
||||
checked={autoDownloadAttachment.documents}
|
||||
onCheckedChange={(newValue: boolean) => {
|
||||
onAutoDownloadAttachmentChange({
|
||||
@@ -1934,7 +1936,7 @@ export function Preferences({
|
||||
</List>
|
||||
<List>
|
||||
<SelectItem
|
||||
title={i18n('icu:Preferences__sent-media-quality')}
|
||||
label={i18n('icu:Preferences__sent-media-quality')}
|
||||
description={i18n(
|
||||
'icu:Preferences__sent-media-quality__description'
|
||||
)}
|
||||
@@ -2319,7 +2321,7 @@ export function Preferences({
|
||||
<List>
|
||||
<SwitchItem
|
||||
symbol="phone"
|
||||
title={i18n('icu:WhileMuted__calls__title')}
|
||||
label={i18n('icu:WhileMuted__calls__title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__WhileMuted__calls__description'
|
||||
)}
|
||||
@@ -2330,7 +2332,7 @@ export function Preferences({
|
||||
/>
|
||||
<SwitchItem
|
||||
symbol="at"
|
||||
title={i18n('icu:WhileMuted__mentions__title')}
|
||||
label={i18n('icu:WhileMuted__mentions__title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__WhileMuted__mentions__description'
|
||||
)}
|
||||
@@ -2341,7 +2343,7 @@ export function Preferences({
|
||||
/>
|
||||
<SwitchItem
|
||||
symbol="reply"
|
||||
title={i18n('icu:WhileMuted__replies__title')}
|
||||
label={i18n('icu:WhileMuted__replies__title')}
|
||||
description={i18n(
|
||||
'icu:Preferences__WhileMuted__replies__description'
|
||||
)}
|
||||
@@ -2725,25 +2727,27 @@ function ListGroup(props: ListGroupProps): ReactNode {
|
||||
|
||||
type ListProps = Readonly<{
|
||||
accessibilityLabel?: string;
|
||||
title?: string;
|
||||
help?: ReactNode;
|
||||
label?: string;
|
||||
footerDescription?: ReactNode;
|
||||
children: ReactNode;
|
||||
}>;
|
||||
|
||||
function List(props: ListProps): ReactNode {
|
||||
return (
|
||||
<AxoList.Root accessibilityLabel={props.accessibilityLabel}>
|
||||
{props.title != null && (
|
||||
{props.label != null && (
|
||||
<AxoList.Header>
|
||||
<AxoList.Title>{props.title}</AxoList.Title>
|
||||
<AxoList.Label>{props.label}</AxoList.Label>
|
||||
</AxoList.Header>
|
||||
)}
|
||||
<AxoList.Body>
|
||||
<AxoItem.Group>{props.children}</AxoItem.Group>
|
||||
</AxoList.Body>
|
||||
{props.help != null && (
|
||||
{props.footerDescription != null && (
|
||||
<AxoList.Footer>
|
||||
<AxoList.Help>{props.help}</AxoList.Help>
|
||||
<AxoList.FooterDescription>
|
||||
{props.footerDescription}
|
||||
</AxoList.FooterDescription>
|
||||
</AxoList.Footer>
|
||||
)}
|
||||
</AxoList.Root>
|
||||
@@ -2752,7 +2756,7 @@ function List(props: ListProps): ReactNode {
|
||||
|
||||
type SwitchItemProps = Readonly<{
|
||||
symbol?: AxoSymbol.Name;
|
||||
title: ReactNode;
|
||||
label: ReactNode;
|
||||
description?: ReactNode;
|
||||
disabled?: boolean;
|
||||
checked: boolean;
|
||||
@@ -2762,21 +2766,25 @@ type SwitchItemProps = Readonly<{
|
||||
function SwitchItem(props: SwitchItemProps): ReactNode {
|
||||
return (
|
||||
<AxoItem.Root>
|
||||
{props.symbol != null && <AxoItem.Icon symbol={props.symbol} />}
|
||||
{props.symbol != null && (
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol={props.symbol} />
|
||||
</AxoItem.Leading>
|
||||
)}
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>{props.title}</AxoItem.Title>
|
||||
<AxoItem.Label>{props.label}</AxoItem.Label>
|
||||
{props.description != null && (
|
||||
<AxoItem.Description>{props.description}</AxoItem.Description>
|
||||
)}
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoItem.Trailing>
|
||||
<AxoSwitch.Root
|
||||
disabled={props.disabled}
|
||||
checked={props.checked}
|
||||
onCheckedChange={props.onCheckedChange}
|
||||
/>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Trailing>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
);
|
||||
@@ -2790,7 +2798,7 @@ type SelectItemOption<T extends string> = Readonly<{
|
||||
|
||||
type SelectItemProps<T extends string> = Readonly<{
|
||||
symbol?: AxoSymbol.Name;
|
||||
title: ReactNode;
|
||||
label: ReactNode;
|
||||
description?: ReactNode;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
@@ -2835,43 +2843,47 @@ function SelectItem<T extends string>(props: SelectItemProps<T>): ReactNode {
|
||||
|
||||
return (
|
||||
<AxoItem.Root>
|
||||
{props.symbol != null && <AxoItem.Icon symbol={props.symbol} />}
|
||||
{props.symbol != null && (
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol={props.symbol} />
|
||||
</AxoItem.Leading>
|
||||
)}
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>{props.title}</AxoItem.Title>
|
||||
<AxoItem.Label>{props.label}</AxoItem.Label>
|
||||
{props.description != null && (
|
||||
<AxoItem.Description>{props.description}</AxoItem.Description>
|
||||
)}
|
||||
<AxoItem.Accessory>
|
||||
<AxoSelect.Root
|
||||
disabled={props.disabled}
|
||||
value={props.value}
|
||||
onValueChange={handleValueChange}
|
||||
>
|
||||
<AxoSelect.Trigger placeholder={renderPlaceholder} />
|
||||
<AxoSelect.Content>
|
||||
{options.map(item => {
|
||||
return (
|
||||
<AxoSelect.Item
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
disabled={item.disabled}
|
||||
>
|
||||
<AxoSelect.ItemText>{item.label}</AxoSelect.ItemText>
|
||||
</AxoSelect.Item>
|
||||
);
|
||||
})}
|
||||
</AxoSelect.Content>
|
||||
</AxoSelect.Root>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<AxoSelect.Root
|
||||
disabled={props.disabled}
|
||||
value={props.value}
|
||||
onValueChange={handleValueChange}
|
||||
>
|
||||
<AxoSelect.Trigger placeholder={renderPlaceholder} />
|
||||
<AxoSelect.Content>
|
||||
{options.map(item => {
|
||||
return (
|
||||
<AxoSelect.Item
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
disabled={item.disabled}
|
||||
>
|
||||
<AxoSelect.ItemText>{item.label}</AxoSelect.ItemText>
|
||||
</AxoSelect.Item>
|
||||
);
|
||||
})}
|
||||
</AxoSelect.Content>
|
||||
</AxoSelect.Root>
|
||||
</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
);
|
||||
}
|
||||
|
||||
type ValueItemProps = Readonly<{
|
||||
title: ReactNode;
|
||||
label: ReactNode;
|
||||
value: ReactNode;
|
||||
}>;
|
||||
|
||||
@@ -2881,7 +2893,7 @@ function ValueItem(props: ValueItemProps): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title id={id}>{props.title}</AxoItem.Title>
|
||||
<AxoItem.Label id={id}>{props.label}</AxoItem.Label>
|
||||
<AxoItem.Value>{props.value}</AxoItem.Value>
|
||||
</AxoItem.Body>
|
||||
</AxoItem.Content>
|
||||
@@ -2891,7 +2903,7 @@ function ValueItem(props: ValueItemProps): ReactNode {
|
||||
|
||||
type ClickableItemProps = Readonly<{
|
||||
symbol?: AxoSymbol.Name;
|
||||
title: ReactNode;
|
||||
label: ReactNode;
|
||||
description?: ReactNode;
|
||||
value?: ReactNode;
|
||||
accessory?: ReactNode;
|
||||
@@ -2904,10 +2916,14 @@ function ClickableItem(props: ClickableItemProps): ReactNode {
|
||||
const id = useId();
|
||||
return (
|
||||
<AxoItem.Root>
|
||||
{props.symbol != null && <AxoItem.Icon symbol={props.symbol} />}
|
||||
{props.symbol != null && (
|
||||
<AxoItem.Leading>
|
||||
<AxoItem.Icon symbol={props.symbol} />
|
||||
</AxoItem.Leading>
|
||||
)}
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title id={id}>{props.title}</AxoItem.Title>
|
||||
<AxoItem.Label id={id}>{props.label}</AxoItem.Label>
|
||||
{props.value != null && <AxoItem.Value>{props.value}</AxoItem.Value>}
|
||||
{props.description != null && (
|
||||
<AxoItem.Description>{props.description}</AxoItem.Description>
|
||||
@@ -2915,18 +2931,22 @@ function ClickableItem(props: ClickableItemProps): ReactNode {
|
||||
{!props.disabled && (
|
||||
<AxoItem.HiddenTrigger labelledby={id} onClick={props.onClick} />
|
||||
)}
|
||||
{props.accessory != null && (
|
||||
<AxoItem.Accessory>{props.accessory}</AxoItem.Accessory>
|
||||
)}
|
||||
</AxoItem.Body>
|
||||
{props.accessory != null && (
|
||||
<AxoItem.Accessory>{props.accessory}</AxoItem.Accessory>
|
||||
)}
|
||||
</AxoItem.Content>
|
||||
{props.arrow && !props.disabled && <AxoItem.Arrow />}
|
||||
{props.arrow && !props.disabled && (
|
||||
<AxoItem.Trailing>
|
||||
<AxoItem.Arrow />
|
||||
</AxoItem.Trailing>
|
||||
)}
|
||||
</AxoItem.Root>
|
||||
);
|
||||
}
|
||||
|
||||
type ItemWithActionProps = Readonly<{
|
||||
title: ReactNode;
|
||||
label: ReactNode;
|
||||
description?: ReactNode;
|
||||
action: ReactNode;
|
||||
}>;
|
||||
@@ -2937,12 +2957,12 @@ function ItemWithAction(props: ItemWithActionProps): ReactNode {
|
||||
<AxoItem.Root>
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title id={id}>{props.title}</AxoItem.Title>
|
||||
<AxoItem.Label id={id}>{props.label}</AxoItem.Label>
|
||||
{props.description != null && (
|
||||
<AxoItem.Description>{props.description}</AxoItem.Description>
|
||||
)}
|
||||
<AxoItem.Accessory>{props.action}</AxoItem.Accessory>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>{props.action}</AxoItem.Accessory>
|
||||
</AxoItem.Content>
|
||||
</AxoItem.Root>
|
||||
);
|
||||
|
||||
+6
-6
@@ -37,7 +37,7 @@ export function ConversationNotificationsSettings({
|
||||
onOpenWhileMutedSettings,
|
||||
setMuteExpiration,
|
||||
}: PropsType): JSX.Element {
|
||||
const whileMutedTitleId = useId();
|
||||
const whileMutedLabelId = useId();
|
||||
|
||||
const mutedUntilText =
|
||||
muteExpiresAt != null && isConversationMuted({ muteExpiresAt })
|
||||
@@ -81,9 +81,9 @@ export function ConversationNotificationsSettings({
|
||||
<AxoItem.Icon symbol="bell-slash" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>
|
||||
<AxoItem.Label>
|
||||
{i18n('icu:muteNotificationsTitle')}
|
||||
</AxoItem.Title>
|
||||
</AxoItem.Label>
|
||||
<AxoItem.Description>
|
||||
{mutedUntilText ?? i18n('icu:notMuted')}
|
||||
</AxoItem.Description>
|
||||
@@ -115,15 +115,15 @@ export function ConversationNotificationsSettings({
|
||||
<AxoItem.Icon symbol="bell-badge" />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title id={whileMutedTitleId}>
|
||||
<AxoItem.Label id={whileMutedLabelId}>
|
||||
{i18n('icu:WhileMuted__title')}
|
||||
</AxoItem.Title>
|
||||
</AxoItem.Label>
|
||||
<AxoItem.Value>{whileMutedSummary}</AxoItem.Value>
|
||||
<AxoItem.Description>
|
||||
{i18n('icu:WhileMuted__description')}
|
||||
</AxoItem.Description>
|
||||
<AxoItem.HiddenTrigger
|
||||
labelledby={whileMutedTitleId}
|
||||
labelledby={whileMutedLabelId}
|
||||
onClick={onOpenWhileMutedSettings}
|
||||
/>
|
||||
</AxoItem.Body>
|
||||
|
||||
@@ -36,7 +36,7 @@ export function WhileMutedSettings({
|
||||
<WhileMutedSwitch
|
||||
settingKey="calls"
|
||||
symbol="phone"
|
||||
title={i18n('icu:WhileMuted__calls__title')}
|
||||
label={i18n('icu:WhileMuted__calls__title')}
|
||||
description={i18n('icu:WhileMuted__calls__description')}
|
||||
checked={notifyWhileMuted.calls}
|
||||
setNotifyWhileMuted={setNotifyWhileMuted}
|
||||
@@ -46,7 +46,7 @@ export function WhileMutedSettings({
|
||||
<WhileMutedSwitch
|
||||
settingKey="mentions"
|
||||
symbol="at"
|
||||
title={i18n('icu:WhileMuted__mentions__title')}
|
||||
label={i18n('icu:WhileMuted__mentions__title')}
|
||||
description={i18n('icu:WhileMuted__mentions__description')}
|
||||
checked={notifyWhileMuted.mentions}
|
||||
setNotifyWhileMuted={setNotifyWhileMuted}
|
||||
@@ -54,7 +54,7 @@ export function WhileMutedSettings({
|
||||
<WhileMutedSwitch
|
||||
settingKey="replies"
|
||||
symbol="reply"
|
||||
title={i18n('icu:WhileMuted__replies__title')}
|
||||
label={i18n('icu:WhileMuted__replies__title')}
|
||||
description={i18n('icu:WhileMuted__replies__description')}
|
||||
checked={notifyWhileMuted.replies}
|
||||
setNotifyWhileMuted={setNotifyWhileMuted}
|
||||
@@ -71,7 +71,7 @@ export function WhileMutedSettings({
|
||||
type WhileMutedSwitchProps = Readonly<{
|
||||
settingKey: NotifyWhileMutedKey;
|
||||
symbol: AxoSymbol.Name;
|
||||
title: string;
|
||||
label: string;
|
||||
description: string;
|
||||
checked: boolean;
|
||||
setNotifyWhileMuted: PropsType['setNotifyWhileMuted'];
|
||||
@@ -80,7 +80,7 @@ type WhileMutedSwitchProps = Readonly<{
|
||||
function WhileMutedSwitch({
|
||||
settingKey,
|
||||
symbol,
|
||||
title,
|
||||
label,
|
||||
description,
|
||||
checked,
|
||||
setNotifyWhileMuted,
|
||||
@@ -97,12 +97,12 @@ function WhileMutedSwitch({
|
||||
<AxoItem.Icon symbol={symbol} />
|
||||
<AxoItem.Content>
|
||||
<AxoItem.Body>
|
||||
<AxoItem.Title>{title}</AxoItem.Title>
|
||||
<AxoItem.Label>{label}</AxoItem.Label>
|
||||
<AxoItem.Description>{description}</AxoItem.Description>
|
||||
</AxoItem.Body>
|
||||
<AxoItem.Accessory>
|
||||
<label>
|
||||
<span className={tw('sr-only')}>{title}</span>
|
||||
<span className={tw('sr-only')}>{label}</span>
|
||||
<AxoSwitch.Root
|
||||
checked={checked}
|
||||
onCheckedChange={handleCheckedChange}
|
||||
|
||||
Reference in New Issue
Block a user