Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dropdown Expandable - QA review tweaks from Laura and Orion #1145

Merged
merged 10 commits into from
Oct 19, 2023
5 changes: 5 additions & 0 deletions .changeset/fix-expandableDropdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'react-magma-dom': patch
---

fix(Dropdown): Fixes from QA review of the Dropdown Expandable sub component.
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ export const ExpandableItemsWithIconsAndConsoleWarning = args => {
<Dropdown {...args} width={220}>
<DropdownButton>Expandable Items Dropdown</DropdownButton>
<DropdownContent>
<DropdownExpandableMenuGroup>
<DropdownExpandableMenuGroup isMulti={false} defaultIndex={1}>
<DropdownExpandableMenuItem>
<DropdownExpandableMenuButton>Pasta</DropdownExpandableMenuButton>
<DropdownExpandableMenuPanel>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import { ThemeContext } from '../../theme/ThemeContext';
import { DropdownContext } from './Dropdown';
import { DropdownExpandableMenuGroupContext } from './DropdownExpandableMenuGroup';
import { useForkedRef } from '../../utils';
import { DropdownExpandableMenuItemContext } from './DropdownExpandableMenuItem';

export interface DropdownExpandableMenuButtonProps
extends AccordionButtonProps {
disabled?: boolean;
icon?: React.ReactElement<IconProps>;
testId?: string;
}

const StyledAccordionButton = styled(AccordionButton)<{
disabled?: boolean;
expandableMenuButtonHasIcon?: boolean;
icon?: React.ReactElement<IconProps>;
}>`
Expand All @@ -28,6 +27,9 @@ const StyledAccordionButton = styled(AccordionButton)<{
: `${props.theme.spaceScale.spacing03} ${props.theme.spaceScale.spacing05}`};
margin: 0;
border-top: 0;
&:focus {
outline-offset: -2px;
}
&:hover,
&:focus {
background: ${menuBackground};
Expand All @@ -45,19 +47,23 @@ export const DropdownExpandableMenuButton = React.forwardRef<
HTMLDivElement,
DropdownExpandableMenuButtonProps
>((props, forwardedRef) => {
const { children, disabled, customOnKeyDown, icon, testId, ...other } = props;
const { children, customOnKeyDown, icon, testId, ...other } = props;

const theme = React.useContext(ThemeContext);
const context = React.useContext(DropdownContext);
const expandableMenuGroupContext = React.useContext(
DropdownExpandableMenuGroupContext
);

const expandableMenuItemContext = React.useContext(
DropdownExpandableMenuItemContext
);

const ownRef = React.useRef<HTMLDivElement>();
const ref = useForkedRef(forwardedRef, ownRef);

React.useEffect(() => {
if (!disabled) {
if (!expandableMenuItemContext.disabled) {
context.registerDropdownMenuItem(context.itemRefArray, ownRef);
}
}, []);
Expand All @@ -72,7 +78,6 @@ export const DropdownExpandableMenuButton = React.forwardRef<
return (
<StyledAccordionButton
{...other}
disabled={disabled}
ref={ref}
customOnKeyDown={handleCustomOnKeyDown}
icon={icon}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as React from 'react';
import styled from '../../theme/styled';
import { Accordion, AccordionProps } from '../Accordion';
import { Accordion, AccordionIconPosition, AccordionProps } from '../Accordion';
import { DropdownContext } from './Dropdown';

const StyledAccordion = styled(Accordion)`
border: none;
padding: 0;
`;

export interface DropdownExpandableMenuGroupContextInterface {
Expand Down Expand Up @@ -48,6 +49,7 @@ export const DropdownExpandableMenuGroup = React.forwardRef<
>
<StyledAccordion
{...other}
iconPosition={AccordionIconPosition.right}
isInverse={context.isInverse}
ref={ref}
role="group"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,52 +1,36 @@
import * as React from 'react';
import { IconProps } from 'react-magma-icons';
import { AccordionItem, AccordionItemProps } from '../Accordion';
import {
DropdownExpandableMenuButton,
DropdownExpandableMenuButtonProps,
} from './DropdownExpandableMenuButton';
export interface DropdownExpandableMenuItemProps extends AccordionItemProps {
/**
* If true, item will be disabled; it will appear dimmed and onClick event (or any other events) will not fire
* @default false
*/
disabled?: boolean;
/**
* Leading icon for the menu item
*/
icon?: React.ReactElement<IconProps>;
/**
* @internal
*/
testId?: string;
}

export interface DropdownExpandableMenuItemContextInterface {
disabled?: boolean;
}

export const DropdownExpandableMenuItemContext =
React.createContext<DropdownExpandableMenuItemContextInterface>({});

export const DropdownExpandableMenuItem = React.forwardRef<
HTMLDivElement,
DropdownExpandableMenuItemProps
>((props, ref) => {
const { children, disabled, testId, ...other } = props;

const dropdownExpandableMenuItemChildren = React.Children.map(
children,
child => {
const item = child as React.ReactElement<
React.PropsWithChildren<DropdownExpandableMenuButtonProps>
>;

if (item.type === DropdownExpandableMenuButton) {
if (disabled) {
return React.cloneElement(item, { disabled: true });
}
}
return child;
}
);

return (
<AccordionItem {...other} isDisabled={disabled} ref={ref} testId={testId}>
{dropdownExpandableMenuItemChildren}
</AccordionItem>
<DropdownExpandableMenuItemContext.Provider value={{ disabled }}>
<AccordionItem {...other} isDisabled={disabled} ref={ref} testId={testId}>
{children}
</AccordionItem>
</DropdownExpandableMenuItemContext.Provider>
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { DropdownContext } from './Dropdown';
import { Omit, useForkedRef } from '../../utils';
import { DropdownExpandableMenuGroupContext } from './DropdownExpandableMenuGroup';
import { DropdownMenuItem, DropdownMenuItemProps } from './DropdownMenuItem';
import { DropdownExpandableMenuItemContext } from './DropdownExpandableMenuItem';

export interface DropdownExpandableMenuListItemProps
extends Omit<DropdownMenuItemProps, 'icon'> {
extends Omit<DropdownMenuItemProps, 'icon' | 'disabled'> {
testId?: string;
}

Expand All @@ -31,18 +32,22 @@ export const DropdownExpandableMenuListItem = React.forwardRef<
HTMLDivElement,
DropdownExpandableMenuListItemProps
>((props, forwardedRef) => {
const { children, disabled, ...other } = props;
const { children, ...other } = props;

const ownRef = React.useRef<HTMLDivElement>();
const theme = React.useContext(ThemeContext);
const context = React.useContext(DropdownContext);

const menuGroupContext = React.useContext(DropdownExpandableMenuGroupContext);

const expandableMenuItemContext = React.useContext(
DropdownExpandableMenuItemContext
);

const ref = useForkedRef(forwardedRef, ownRef);

React.useEffect(() => {
if (!disabled)
if (!expandableMenuItemContext.disabled)
context.registerDropdownMenuItem(context.itemRefArray, ownRef);
}, []);

Expand All @@ -51,7 +56,7 @@ export const DropdownExpandableMenuListItem = React.forwardRef<
{...other}
expandableMenuButtonHasIcon={menuGroupContext.expandableMenuButtonHasIcon}
isExpandablePanel={menuGroupContext.isExpandablePanel}
ref={disabled ? null : ref}
ref={expandableMenuItemContext.disabled ? null : ref}
theme={theme}
>
{children}
Expand Down
73 changes: 73 additions & 0 deletions website/react-magma-docs/src/pages/api/dropdown.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ import {
Dropdown,
DropdownButton,
DropdownContent,
DropdownDivider,
DropdownExpandableMenuGroup,
DropdownExpandableMenuItem,
DropdownExpandableMenuButton,
Expand Down Expand Up @@ -427,6 +428,77 @@ export function Example() {
}
```

### Expandable Menu with item auto expanded

By default, the `isMulti` prop is true on `DropdownExpandableMenuGroup`, which means that the expandable dropdown will allow multiple items to be expanded at once. If you wish to limit the number of items open at once, you can set the `isMulti` prop to false.

The `defaultIndex` prop on `DropdownExpandableMenuGroup` uses an array of zero based indices to enable expandable groups to be automatically opened.

When the `isMulti` prop is false, the `defaultIndex` prop will take a single number, instead of an array.

```tsx
import React from 'react';
import {
Dropdown,
DropdownButton,
DropdownContent,
DropdownDivider,
DropdownExpandableMenuGroup,
DropdownExpandableMenuItem,
DropdownExpandableMenuButton,
DropdownExpandableMenuPanel,
DropdownExpandableMenuListItem,
} from 'react-magma-dom';

import {
RestaurantMenuIcon,
LunchDiningIcon,
LocalPizzaIcon,
} from 'react-magma-icons';

export function Example() {
return (
<Dropdown width={240}>
<DropdownButton>Expandable Items Dropdown</DropdownButton>
<DropdownContent>
<DropdownExpandableMenuGroup defaultIndex={[0]}>
<DropdownExpandableMenuItem>
<DropdownExpandableMenuButton icon={<RestaurantMenuIcon />}>
Pasta
</DropdownExpandableMenuButton>
<DropdownExpandableMenuPanel>
<DropdownExpandableMenuListItem>
Fresh
</DropdownExpandableMenuListItem>
<DropdownExpandableMenuListItem>
Processed
</DropdownExpandableMenuListItem>
</DropdownExpandableMenuPanel>
</DropdownExpandableMenuItem>
<DropdownExpandableMenuItem>
<DropdownExpandableMenuButton icon={<LunchDiningIcon />}>
Prosciutto
</DropdownExpandableMenuButton>
<DropdownExpandableMenuPanel>
<DropdownExpandableMenuListItem>
Domestic
</DropdownExpandableMenuListItem>
<DropdownExpandableMenuListItem>
Speck
</DropdownExpandableMenuListItem>
</DropdownExpandableMenuPanel>
</DropdownExpandableMenuItem>
</DropdownExpandableMenuGroup>
<DropdownDivider />
<DropdownExpandableMenuListItem icon={<LocalPizzaIcon />}>
Pizza
</DropdownExpandableMenuListItem>
</DropdownContent>
</Dropdown>
);
}
```

### Text only Expandable Menu Item

```tsx
Expand All @@ -435,6 +507,7 @@ import {
Dropdown,
DropdownButton,
DropdownContent,
DropdownDivider,
DropdownExpandableMenuGroup,
DropdownExpandableMenuItem,
DropdownExpandableMenuButton,
Expand Down
Loading