Skip to content

Commit

Permalink
Refactor onClose and add site docs
Browse files Browse the repository at this point in the history
  • Loading branch information
joshwooding committed Sep 6, 2024
1 parent d9cd70e commit 463cbc6
Show file tree
Hide file tree
Showing 19 changed files with 263 additions and 222 deletions.
2 changes: 1 addition & 1 deletion .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const config: StorybookConfig = {
stories: ["../packages/*/stories/**/*.@(mdx|stories.@(js|jsx|ts|tsx))"],
staticDirs: ["../docs/public"],
typescript: {
reactDocgen: false,
reactDocgen: "react-docgen-typescript",
},
addons: [
{
Expand Down
1 change: 0 additions & 1 deletion packages/lab/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"sideEffects": false,
"dependencies": {
"@floating-ui/react": "^0.26.5",
"@fluentui/react-overflow": "^9.0.19",
"@internationalized/date": "^3.0.0",
"@types/react-window": "^1.8.2",
"aria-hidden": "^1.1.1",
Expand Down
37 changes: 17 additions & 20 deletions packages/lab/src/__tests__/__e2e__/tabs-next/TabstripNext.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("Given a Tabstrip", () => {
.eq(1)
.should("have.attr", "aria-selected", "true");

cy.findAllByRole("tab").eq(0).click();
cy.findAllByRole("tab").eq(0).realClick();

cy.get("@onChange").should("have.been.calledOnce");
});
Expand All @@ -56,7 +56,7 @@ describe("Given a Tabstrip", () => {
it("THEN no overflow indicator will be present", () => {
cy.mount(<DefaultTabstrip width={500} />);
cy.findByRole("tablist")
.findByRole("tab", { name: /More tabs/ })
.findByRole("button", { name: /More tabs/ })
.should("not.exist");
});
});
Expand All @@ -66,23 +66,22 @@ describe("Given a Tabstrip", () => {
cy.mount(<DefaultTabstrip width={500} />);
cy.get(".saltTabstripNext").invoke("css", "width", "350px");
cy.findAllByRole("tab").should("have.length", 5);
cy.findByRole("tab", { name: /More tabs/ })
cy.findAllByRole("tab").filter(":visible").should("have.length", 3);
cy.findByRole("button", { name: /More tabs/ })
.should("exist")
.click();
cy.findByRole("menu")
.findAllByRole("menuitem")
.should("have.length", 1);
.realClick();
cy.findAllByRole("tab").filter(":visible").should("have.length", 5);
});
});
});
describe("WHEN size is not the full width of it's parent", () => {
it("THEN should not overflow if it has enough space", () => {
cy.mount(<DefaultLeftAligned />);
cy.findByRole("tab", { name: /More tabs/ }).should("not.exist");
cy.findByRole("button", { name: /More tabs/ }).should("not.exist");
});
it("THEN should overflow if it there is not enough space", () => {
cy.mount(<LotsOfTabsTabstrip />);
cy.findByRole("tab", { name: /More tabs/ }).should("exist");
cy.findByRole("button", { name: /More tabs/ }).should("exist");
});
});
});
Expand All @@ -97,9 +96,8 @@ describe("Tab selection, Given a Tabstrip", () => {
"aria-selected",
"true",
);
cy.findByRole("tab", { name: /More tabs/ }).realClick();
cy.findByRole("menu").should("be.visible");
cy.findByRole("menuitem", { name: "Loans" }).click();
cy.findByRole("button", { name: /More tabs/ }).realClick();
cy.findByRole("tab", { name: "Loans" }).realClick();
cy.findAllByRole("tab", { name: "Loans" }).should("be.visible");
cy.findAllByRole("tab", { name: "Loans" }).should(
"have.attr",
Expand Down Expand Up @@ -160,12 +158,12 @@ describe("Navigation, Given a Tabstrip", () => {
});

describe("WHEN the left arrow key is pressed (from first tab)", () => {
it("THEN no navigation will occur", () => {
it("THEN navigation will wrap", () => {
cy.mount(<DefaultTabstrip width={500} />);
cy.findAllByRole("tab").eq(0).realClick();
cy.findAllByRole("tab").eq(0).should("be.focused");
cy.realPress("ArrowLeft");
cy.findAllByRole("tab").eq(0).should("be.focused");
cy.findAllByRole("tab").eq(-1).should("be.focused");
});
});

Expand Down Expand Up @@ -209,7 +207,7 @@ describe("Navigation, Given a Tabstrip", () => {
cy.realPress("ArrowRight");
cy.findAllByRole("tab").eq(4).should("be.focused");
cy.realPress("ArrowRight");
cy.findAllByRole("tab").eq(4).should("be.focused");
cy.findAllByRole("tab").eq(0).should("be.focused");
});
});
});
Expand All @@ -220,14 +218,14 @@ describe("Navigation, Given a Tabstrip", () => {
// it("THEN overflow indicator is included in keyboard navigation", () => {
// cy.mount(<DefaultTabstrip width={310} />);
// cy.findAllByRole("tab").eq(0).realClick();
// cy.findByRole("tab", { name: /More tabs/ }).should("be.visible");
// cy.findByRole("button", { name: /More tabs/ }).should("be.visible");
// cy.realPress("Tab");
// cy.findByRole("tab", { name: /More tabs/ }).should("be.focused");
// cy.findByRole("button", { name: /More tabs/ }).should("be.focused");
// });
//
// it("THEN overflow indicator opens overflow menu", () => {
// cy.mount(<DefaultTabstrip width={320} />);
// cy.findByRole("tab", { name: /More tabs/ })
// cy.findByRole("button", { name: /More tabs/ })
// .focus()
// .realPress("Enter");
// cy.findByRole("menu");
Expand All @@ -237,8 +235,7 @@ describe("Navigation, Given a Tabstrip", () => {
describe("WHEN overflow is opened", () => {
it("THEN overflow menu item can be selected with Enter and focus is moved to the active tab", () => {
cy.mount(<DefaultTabstrip width={200} />);
cy.findByRole("tab", { name: /More tabs/ }).click();
cy.findByRole("menu").should("exist");
cy.findByRole("button", { name: /More tabs/ }).realClick();
cy.realPress("ArrowDown").realPress("Enter");
cy.focused()
.should("have.attr", "aria-selected", "true")
Expand Down
35 changes: 25 additions & 10 deletions packages/lab/src/tabs-next/TabNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ import {

import { CloseIcon } from "@salt-ds/icons";
import tabCss from "./TabNext.css";
import { useTabs } from "./TabNextContext";
import { useTabstrip } from "./TabstripNextContext";

const withBaseName = makePrefixer("saltTabNext");

export interface TabNextProps extends ComponentPropsWithoutRef<"div"> {
/* Value prop is mandatory and must be unique in order for overflow to work. */
disabled?: boolean;
value: string;
onClose?: () => void;
closable?: boolean;
}

export const TabNext = forwardRef<HTMLDivElement, TabNextProps>(
Expand All @@ -35,7 +35,7 @@ export const TabNext = forwardRef<HTMLDivElement, TabNextProps>(
className,
disabled: disabledProp,
onClick,
onClose,
closable,
onKeyDown,
onFocus,
value,
Expand All @@ -51,10 +51,11 @@ export const TabNext = forwardRef<HTMLDivElement, TabNextProps>(
registerItem,
variant,
setSelected,
setActive,
selected,
focusInside,
handleClose,
} = useTabs();
} = useTabstrip();
const disabled = disabledProp;

const tabRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -87,25 +88,38 @@ export const TabNext = forwardRef<HTMLDivElement, TabNextProps>(

const handleFocus = () => {
setFocused(true);
setActive(value);
};

const handleBlur = () => {
setFocused(false);
};

const handleCloseButton = (event: MouseEvent<HTMLButtonElement>) => {
onClose?.();
const handleCloseButtonClick = (event: MouseEvent<HTMLButtonElement>) => {
handleClose(event, value);
event.stopPropagation();
};

const handleCloseButtonKeyDown = (
event: KeyboardEvent<HTMLButtonElement>,
) => {
if (event.key === "Enter" || event.key === " ") {
handleClose(event, value);
event.stopPropagation();
}
};

return (
<div
className={clsx(withBaseName(), withBaseName(variant), className)}
data-value={value}
aria-selected={selected === value || undefined}
aria-selected={selected === value}
aria-disabled={disabled}
tabIndex={selected === value ? 0 : -1}
tabIndex={
(focusInside && focused) || (selected === value && !focusInside)
? 0
: -1
}
ref={handleRef}
role="tab"
onClick={!disabled ? handleClick : undefined}
Expand All @@ -118,14 +132,15 @@ export const TabNext = forwardRef<HTMLDivElement, TabNextProps>(
<span className={withBaseName("label")} aria-hidden id={labelId}>
{children}
</span>
{onClose ? (
{closable ? (
<Button
aria-label="Dismiss tab"
id={closeButtonId}
aria-labelledby={clsx(closeButtonId, labelId)}
tabIndex={focused || (!focusInside && selected === value) ? 0 : -1}
variant="secondary"
onClick={handleCloseButton}
onClick={handleCloseButtonClick}
onKeyDown={handleCloseButtonKeyDown}
>
<CloseIcon aria-hidden />
</Button>
Expand Down
29 changes: 0 additions & 29 deletions packages/lab/src/tabs-next/TabNextContext.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions packages/lab/src/tabs-next/TabNextPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useId } from "@salt-ds/core";
import { type ComponentPropsWithoutRef, forwardRef } from "react";

export interface TabNextPanelProps extends ComponentPropsWithoutRef<"div"> {}

export const TabNextPanel = forwardRef<HTMLDivElement, TabNextPanelProps>(
function TabNextPanel(props, ref) {
const { children, id: idProp, ...rest } = props;
const id = useId(idProp);

return (
<div id={id} ref={ref} role="tabpanel" {...rest}>
{children}
</div>
);
},
);
6 changes: 5 additions & 1 deletion packages/lab/src/tabs-next/TabOverflowList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,11 @@ export const TabOverflowList = forwardRef<HTMLDivElement, TabOverflowListProps>(
onBlur={handleBlur}
onClick={handleListClick}
ref={refs.setFloating}
style={{ left: x ?? 0, top: y ?? 0, position: strategy }}
style={
!hidden
? { left: x ?? 0, top: y ?? 0, position: strategy }
: undefined
}
tabIndex={-1}
>
<div className={withBaseName("listContainer")}>{children}</div>
Expand Down
13 changes: 13 additions & 0 deletions packages/lab/src/tabs-next/TabsNext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ReactNode } from "react";

import { TabsNextContext } from "./TabsNextContext";

export interface TabsNextProps {
children: ReactNode;
}

export function TabsNext({ children }: TabsNextProps) {
return (
<TabsNextContext.Provider value={{}}>{children}</TabsNextContext.Provider>
);
}
14 changes: 14 additions & 0 deletions packages/lab/src/tabs-next/TabsNextContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { createContext } from "@salt-ds/core";
import { useContext } from "react";

// biome-ignore lint/complexity/noBannedTypes: <explanation>
export type TabsNextContextValue = {};

export const TabsNextContext = createContext<TabsNextContextValue>(
"TabsNextContext",
{},
);

export function useTabsNext() {
return useContext(TabsNextContext);
}
Loading

0 comments on commit 463cbc6

Please sign in to comment.