Skip to content

Commit

Permalink
SideNavigation: Add disable and helper text props (#3905)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkmatheson authored Dec 6, 2024
1 parent 2918681 commit f28e6b3
Show file tree
Hide file tree
Showing 8 changed files with 902 additions and 74 deletions.
51 changes: 51 additions & 0 deletions docs/examples/sidenavigation/disableItemExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { Box, SideNavigation } from 'gestalt';

export default function Example() {
return (
<Box height="100%" width={300}>
<SideNavigation accessibilityLabel="Disabled item example">
<SideNavigation.TopItem
disabled
href="#"
icon="ads-stats"
label="Reports"
onClick={({ event }) => event.preventDefault()}
/>
<SideNavigation.Section label="Catalogs">
<SideNavigation.TopItem
disabled
href="#"
icon="people"
label="Thanksgiving"
onClick={({ event }) => event.preventDefault()}
subtext="Disabled thanksgiving section"
/>

<SideNavigation.Group expanded icon="people" label="Christmas">
<SideNavigation.NestedItem
disabled
href="#"
label="Luxury Christmas"
onClick={({ event }) => event.preventDefault()}
/>

<SideNavigation.NestedGroup label="Shopping Categories">
<SideNavigation.NestedItem
disabled
href="#"
label="Gifts"
onClick={({ event }) => event.preventDefault()}
/>
<SideNavigation.NestedItem
href="#"
label="Decorations"
onClick={({ event }) => event.preventDefault()}
/>
</SideNavigation.NestedGroup>
</SideNavigation.Group>
</SideNavigation.Section>
</SideNavigation>
</Box>
);
}
51 changes: 51 additions & 0 deletions docs/examples/sidenavigation/subtextItemExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { Box, SideNavigation } from 'gestalt';

export default function Example() {
return (
<Box height="100%" width={300}>
<SideNavigation accessibilityLabel="Helper text items">
<SideNavigation.TopItem
href="#"
icon="ads-stats"
label="Reports"
onClick={({ event }) => event.preventDefault()}
subtext="Reporting subtext"
/>
<SideNavigation.Section label="Audiences">
<SideNavigation.TopItem
href="#"
icon="people"
label="Group A"
onClick={({ event }) => event.preventDefault()}
subtext="8.5m+ users"
/>

<SideNavigation.Group expanded icon="people" label="Group B">
<SideNavigation.NestedItem
href="#"
label="Sub audience 1"
onClick={({ event }) => event.preventDefault()}
subtext="2.3m+ users"
/>

<SideNavigation.NestedGroup label="Sub audience 2">
<SideNavigation.NestedItem
href="#"
label="Region 1"
onClick={({ event }) => event.preventDefault()}
subtext="100k+ users"
/>
<SideNavigation.NestedItem
href="#"
label="Region 2"
onClick={({ event }) => event.preventDefault()}
subtext="50k+ users"
/>
</SideNavigation.NestedGroup>
</SideNavigation.Group>
</SideNavigation.Section>
</SideNavigation>
</Box>
);
}
22 changes: 22 additions & 0 deletions docs/pages/web/sidenavigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import correctIconExample from '../../examples/sidenavigation/correctIconExample
import correctLengthExample from '../../examples/sidenavigation/correctLengthExample';
import counterExample from '../../examples/sidenavigation/counterExample';
import customIconsExample from '../../examples/sidenavigation/customIconsExample';
import disableItemExample from '../../examples/sidenavigation/disableItemExample';
import displayExpandable from '../../examples/sidenavigation/displayExpandable';
import displayExpanded from '../../examples/sidenavigation/displayExpanded';
import displayStatic from '../../examples/sidenavigation/displayStatic';
Expand All @@ -40,6 +41,7 @@ import notificationsExample from '../../examples/sidenavigation/notificationsExa
import primaryAction from '../../examples/sidenavigation/primaryAction';
import sectionsExample from '../../examples/sidenavigation/sectionsExample';
import subcomponent from '../../examples/sidenavigation/subcomponent';
import subtextItemExample from '../../examples/sidenavigation/subtextItemExample';

const DOC_NAMES = [
'SideNavigation',
Expand Down Expand Up @@ -337,6 +339,26 @@ Note that \`dismissButton.accessibilityLabel\` is optional as DefaultLabelProvid
sandpackExample={<SandpackExample code={borderExample} name="Border example" />}
/>
</MainSection.Subsection>
<MainSection.Subsection
description="Items can be disabled to prevent clicking or navigation to a page if that page is unavailable to users."
title="Disabled"
>
<MainSection.Card
sandpackExample={
<SandpackExample code={disableItemExample} name="Disabled item example" />
}
/>
</MainSection.Subsection>
<MainSection.Subsection
description="Subtext adds a new line to an item, providing additional information about the page the item represents."
title="Subtext"
>
<MainSection.Card
sandpackExample={
<SandpackExample code={subtextItemExample} name="Subtext item example" />
}
/>
</MainSection.Subsection>
<MainSection.Subsection
description="Icons are used when simple, clear icons help users with scanning the content of a menu. Only supported in SideNavigation.TopItem and SideNavigation.Group."
title="Icons"
Expand Down
18 changes: 18 additions & 0 deletions packages/gestalt/src/SideNavigation.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,22 @@ describe('SideNavigation', () => {
).toJSON();
expect(tree).toMatchSnapshot();
});

it('renders disabled item', () => {
const tree = create(
<SideNavigation accessibilityLabel="label">
<SideNavigation.TopItem disabled href="#" label="test" />
</SideNavigation>,
).toJSON();
expect(tree).toMatchSnapshot();
});

it('renders subtext on an item', () => {
const tree = create(
<SideNavigation accessibilityLabel="label">
<SideNavigation.TopItem href="#" label="test" subtext="subtext" />
</SideNavigation>,
).toJSON();
expect(tree).toMatchSnapshot();
});
});
76 changes: 59 additions & 17 deletions packages/gestalt/src/SideNavigation/ItemContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,27 @@ import Indicator from '../Indicator';
import Text from '../Text';
import { Indexable } from '../zIndex';

function getTextColor({
active,
disabled,
subtext,
}: {
active?: string;
disabled?: boolean;
subtext?: boolean;
}) {
if (active) {
return 'inverse';
}
if (disabled) {
return 'disabled';
}
if (subtext) {
return 'subtle';
}
return 'default';
}

export const NESTING_MARGIN_START_MAP = {
'0': TOKEN_SPACE_400,
'1': TOKEN_SPACE_1200,
Expand Down Expand Up @@ -56,6 +77,8 @@ type Props = {
counter?: Counter;
icon?: IconType;
label: string;
subtext?: string;
disabled?: boolean;
notificationAccessibilityLabel?: string;
primaryAction?: PrimaryAction;
setCompression: (arg1: 'compress' | 'none') => void;
Expand All @@ -70,6 +93,8 @@ export default function ItemContent({
counter,
icon,
label,
subtext,
disabled,
primaryAction,
notificationAccessibilityLabel,
setCompression,
Expand Down Expand Up @@ -115,7 +140,8 @@ export default function ItemContent({

const inactiveItemColor = hovered ? 'secondary' : undefined;
const itemColor = active ? 'selected' : inactiveItemColor;
const textColor = active ? 'inverse' : 'default';
const mainTextColor = getTextColor({ active, disabled });
const subTextColor = getTextColor({ active, disabled, subtext: true });
const counterColor = active ? 'inverse' : 'subtle';

const nestingMargin = isMobile
Expand Down Expand Up @@ -164,15 +190,15 @@ export default function ItemContent({
{typeof icon === 'string' ? (
<Icon
accessibilityLabel={collapsed ? label : ''}
color={textColor}
color={mainTextColor}
icon={icon}
inline
size={20}
/>
) : (
<Icon
accessibilityLabel={collapsed ? label : ''}
color={textColor}
color={mainTextColor}
dangerouslySetSvgPath={icon}
inline
size={20}
Expand All @@ -184,20 +210,36 @@ export default function ItemContent({

{!collapsed && (
<Flex.Item flex="grow">
<Text color={textColor} inline>
{label}
{(badge || notificationAccessibilityLabel) && (
<Box display="inlineBlock" height="100%" marginStart={1}>
{/* Adds a pause for screen reader users between the text content */}
<Box display="visuallyHidden">{`, `}</Box>
{!notificationAccessibilityLabel && badge ? (
<Badge text={badge.text} type={badge.type} />
) : null}
{notificationAccessibilityLabel ? (
<Indicator accessibilityLabel={notificationAccessibilityLabel} />
) : null}
</Box>
)}
<Text color={mainTextColor} inline>
<Flex alignItems="center" direction="row" gap={1}>
<Flex direction="column" gap={1}>
{label}
{subtext && (
<Text color={subTextColor} lineClamp={1} size="200">
{subtext}
</Text>
)}
</Flex>
{(badge || notificationAccessibilityLabel) && !disabled && (
<Box display="inlineBlock" height="100%" marginStart={1}>
{/* Adds a pause for screen reader users between the text content */}
<Box display="visuallyHidden">{`, `}</Box>
{!notificationAccessibilityLabel && badge ? (
<Badge text={badge.text} type={badge.type} />
) : null}
{notificationAccessibilityLabel ? (
<Box
aria-label={notificationAccessibilityLabel}
color="primary"
height={8}
role="status"
rounding="circle"
width={8}
/>
) : null}
</Box>
)}
</Flex>
</Text>
</Flex.Item>
)}
Expand Down
12 changes: 11 additions & 1 deletion packages/gestalt/src/SideNavigationNestedItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,18 @@ type Props = {
number: string;
accessibilityLabel: string;
};
/**
* Indicates if row item is disabled and therefore inactive and non-interactive. See [disabled variant](https://gestalt.pinterest.systems/web/sidenavigation#Disabled) to learn more.
*/
disabled?: boolean;
/**
* Directs users to the url when item is selected.
*/
href: string;
/**
* Provides optional additional information about a row item. See [subtext variant](https://gestalt.pinterest.systems/web/sidenavigation#Subtext) to learn more.
*/
subtext?: string;
/**
* Label for the item.
*/
Expand Down Expand Up @@ -55,18 +63,20 @@ type Props = {
*/
const SideNavigationNestedItemWithForwardRef = forwardRef<HTMLLIElement, Props>(
function SideNavigationNestedItem(
{ active, counter, href, label, onClick, primaryAction }: Props,
{ active, counter, disabled, subtext, href, label, onClick, primaryAction }: Props,
ref,
) {
return (
<SideNavigationTopItem
ref={ref}
active={active}
counter={counter}
disabled={disabled}
href={href}
label={label}
onClick={onClick}
primaryAction={primaryAction}
subtext={subtext}
/>
);
},
Expand Down
17 changes: 15 additions & 2 deletions packages/gestalt/src/SideNavigationTopItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export type Props = {
number: string;
accessibilityLabel: string;
};
/**
* Indicates if row item is disabled and therefore inactive and non-interactive. See [disabled variant](https://gestalt.pinterest.systems/web/sidenavigation#Disabled) to learn more.
*/
disabled?: boolean;
/**
* Directs users to the url when item is selected.
*/
Expand All @@ -49,6 +53,10 @@ export type Props = {
event: React.MouseEvent<HTMLAnchorElement> | React.KeyboardEvent<HTMLAnchorElement>;
dangerouslyDisableOnNavigation: () => void;
}) => void;
/**
* Provides optional additional information about a row item. See [subtext variant](https://gestalt.pinterest.systems/web/sidenavigation#Subtext) to learn more.
*/
subtext?: string;
/**
* Label for the item.
*/
Expand Down Expand Up @@ -84,8 +92,10 @@ const SideNavigationTopItemWithForwardRef = forwardRef<HTMLLIElement, Props>(
href,
badge,
counter,
disabled,
icon,
label,
subtext,
primaryAction,
notificationAccessibilityLabel,
onClick,
Expand All @@ -108,6 +118,7 @@ const SideNavigationTopItemWithForwardRef = forwardRef<HTMLLIElement, Props>(
<li ref={ref} className={classnames(styles.liItem)}>
<TapAreaLink
accessibilityCurrent={active}
disabled={disabled}
href={href}
onBlur={() => setFocused(false)}
onFocus={() => setFocused(true)}
Expand All @@ -125,14 +136,16 @@ const SideNavigationTopItemWithForwardRef = forwardRef<HTMLLIElement, Props>(
<ItemContent
active={active}
badge={badge}
counter={counter}
counter={disabled ? undefined : counter}
disabled={disabled}
focused={focused}
hovered={hovered}
icon={icon}
label={label}
notificationAccessibilityLabel={notificationAccessibilityLabel}
notificationAccessibilityLabel={disabled ? undefined : notificationAccessibilityLabel}
primaryAction={primaryAction}
setCompression={setCompression}
subtext={subtext}
/>
</TapAreaLink>
</li>
Expand Down
Loading

0 comments on commit f28e6b3

Please sign in to comment.