Skip to content

Commit

Permalink
feat(split-button): add position prop
Browse files Browse the repository at this point in the history
Adds position prop to allow consumers to specify on which side the menu is aligned to when opened.
  • Loading branch information
nuria1110 committed May 14, 2024
1 parent ba20f73 commit 716bed3
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 8 deletions.
7 changes: 7 additions & 0 deletions src/components/split-button/split-button-test.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SPLIT_BUTTON_ICON_POSITIONS,
SPLIT_BUTTON_SIZES,
SPLIT_BUTTON_THEMES,
SPLIT_BUTTON_POSITIONS,
} from "./split-button.config";
import SplitButton, { SplitButtonProps } from "./split-button.component";

Expand Down Expand Up @@ -50,6 +51,12 @@ export default {
type: "select",
},
},
position: {
options: SPLIT_BUTTON_POSITIONS,
control: {
type: "select",
},
},
},
};

Expand Down
13 changes: 10 additions & 3 deletions src/components/split-button/split-button.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,19 @@ export interface SplitButtonProps
iconPosition?: "before" | "after";
/** Defines an Icon type within the button */
iconType?: IconType;
/** The size of the buttons in the SplitButton. */
/** The size of the buttons. */
size?: "small" | "medium" | "large";
/** Second text child, renders under main text, only when size is "large" */
subtext?: string;
/** The text to be displayed in the SplitButton. */
/** The text to be displayed in the main button. */
text: string;
/** Sets rendering position of menu */
position?: "left" | "right";
}

export const SplitButton = ({
align = "left",
position = "right",
buttonType = "secondary",
children,
disabled = false,
Expand Down Expand Up @@ -160,7 +163,11 @@ export const SplitButton = ({

return (
<Popover
placement="bottom-end"
placement={
position === "left"
? /* istanbul ignore next */ "bottom-start"
: "bottom-end"
}
reference={buttonNode}
middleware={[
offset(6),
Expand Down
1 change: 1 addition & 0 deletions src/components/split-button/split-button.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export const SPLIT_BUTTON_ICON_POSITIONS = ["before", "after"];
export const SPLIT_BUTTON_THEMES = ["primary", "secondary"];
export const SPLIT_BUTTON_SIZES = ["small", "medium", "large"];
export const SPLIT_BUTTON_ALIGNMENTS = ["left", "right"];
export const SPLIT_BUTTON_POSITIONS = ["left", "right"];
12 changes: 11 additions & 1 deletion src/components/split-button/split-button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,20 @@ Buttons used as a content of `SplitButton` can be of any type.

<Canvas of={SplitButtonStories.Sizes} />

### Alignment
### Button text alignment

Use the `align` prop to change the alignment of the text in the menu Buttons.

<Canvas of={SplitButtonStories.Align} />

### Menu position

By default, the menu will open aligned to the "right" of the button, but you can use the `position` prop to change this to the "left".

Note: The position of the menu will also be automatically adjusted to fit within the viewport.

<Canvas of={SplitButtonStories.Position} />

### Subtext

Subtext only works when `size` is `large`
Expand Down
30 changes: 26 additions & 4 deletions src/components/split-button/split-button.pw.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import Button from "../button";
import Box from "../box";
import { buttonSubtextPreview } from "../../../playwright/components/button";
import {
checkAccessibility,
getStyle,
assertCssValueIsApproximately,
checkAccessibility,
} from "../../../playwright/support/helper";
import { icon, getDataElementByValue } from "../../../playwright/components";
import {
Expand Down Expand Up @@ -253,13 +254,34 @@ test.describe("Prop tests", () => {
}) => {
await mount(<SplitButtonList align={alignment} />);

await expect(splitMainButton(page)).toHaveCSS(
`margin-${alignment}`,
"0px"
await getDataElementByValue(page, "dropdown").click();
await expect(additionalButton(page, 1)).toHaveCSS(
"justify-content",
alignment as string
);
});
});

([
["left", 200],
["right", 242],
] as [SplitButtonProps["position"], number][]).forEach(
([position, value]) => {
test(`should render with menu position to the ${position}`, async ({
mount,
page,
}) => {
await mount(<SplitButtonList ml="200px" position={position} />);

await getDataElementByValue(page, "dropdown").click();
const listContainer = additionalButtonsContainer(page);
await expect(listContainer).toHaveCSS("position", "absolute");
await assertCssValueIsApproximately(listContainer, "top", 45);
await assertCssValueIsApproximately(listContainer, "left", value);
});
}
);

test(`should render with component disabled`, async ({ mount, page }) => {
await mount(<SplitButtonList disabled />);

Expand Down
20 changes: 20 additions & 0 deletions src/components/split-button/split-button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ export const Align: Story = () => {
Align.storyName = "Align";
Align.parameters = { chromatic: { disableSnapshot: true } };

export const Position: Story = () => {
return (
<Box display="flex" justifyContent="space-around">
<SplitButton position="left" text="Left position">
<Button href="#">Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</SplitButton>

<SplitButton position="right" text="Right position">
<Button href="#">Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</SplitButton>
</Box>
);
};
Position.storyName = "Position";
Position.parameters = { chromatic: { disableSnapshot: true } };

export const Subtext: Story = () => {
return (
<SplitButton size="large" subtext="subtext" text="Split button">
Expand Down
30 changes: 30 additions & 0 deletions src/components/split-button/split-button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,36 @@ describe("The SplitButton component", () => {
});
});

it("should render additional button text with align set to 'left'", async () => {
const user = userEvent.setup();
render(
<SplitButton text="Main" align="left">
<Button>Single Button</Button>
</SplitButton>
);

await user.click(screen.getByRole("button", { name: "Show more" }));
const childButton = await screen.findByRole("button", {
name: "Single Button",
});
expect(childButton).toHaveStyle({ textAlign: "left" });
});

it("should render additional button text with align set to 'right'", async () => {
const user = userEvent.setup();
render(
<SplitButton text="Main" align="right">
<Button>Single Button</Button>
</SplitButton>
);

await user.click(screen.getByRole("button", { name: "Show more" }));
const childButton = await screen.findByRole("button", {
name: "Single Button",
});
expect(childButton).toHaveStyle({ textAlign: "right" });
});

it("should render the child buttons when a click event detected on toggle button", async () => {
const user = userEvent.setup();
render(
Expand Down

0 comments on commit 716bed3

Please sign in to comment.