diff --git a/.changeset/pretty-poets-appear.md b/.changeset/pretty-poets-appear.md new file mode 100644 index 00000000000..884ca3d9d92 --- /dev/null +++ b/.changeset/pretty-poets-appear.md @@ -0,0 +1,6 @@ +--- +"@salt-ds/lab": minor +--- + +- Removed `onClose` prop from `PillNext`. PillNext has been updated to support only one action. The `onClick`prop can be used instead. +- Remove `icon` prop from `PillNext`. An icon can be added as a children instead. diff --git a/packages/lab/src/__tests__/__e2e__/pill-next/PillNext.cy.tsx b/packages/lab/src/__tests__/__e2e__/pill-next/PillNext.cy.tsx index d40276f8a08..8f57b633d9e 100644 --- a/packages/lab/src/__tests__/__e2e__/pill-next/PillNext.cy.tsx +++ b/packages/lab/src/__tests__/__e2e__/pill-next/PillNext.cy.tsx @@ -1,5 +1,4 @@ import { PillNext } from "../../../pill-next"; -import { CallIcon } from "@salt-ds/icons"; describe("GIVEN a Pill", () => { it("THEN should render a `standard` Pill", () => { @@ -50,54 +49,6 @@ describe("GIVEN a Pill", () => { }); }); - describe("GIVEN an icon prop", () => { - it("THEN should render an icon given icon component", () => { - cy.mount(}>label); - cy.findByTestId(/CallIcon/i).should("exist"); - }); - }); - - describe("GIVEN a closable pill", () => { - it("THEN should not trigger close by clicking the pill", () => { - const clickSpy = cy.stub().as("clickSpy"); - const closeSpy = cy.stub().as("closeSpy"); - cy.mount( - - Closable Pill - - ); - cy.findByTestId("pill").realClick(); - cy.get("@clickSpy").should("have.callCount", 1); - cy.get("@closeSpy").should("have.callCount", 0); - }); - it("THEN should close the pill on clicking the close button", () => { - const clickSpy = cy.stub().as("clickSpy"); - const closeSpy = cy.stub().as("closeSpy"); - cy.mount( - - Closable Pill - - ); - cy.findByTestId("pill-close-button").realClick(); - cy.get("@clickSpy").should("have.callCount", 0); - cy.get("@closeSpy").should("have.callCount", 1); - }); - it("THEN should close on enter", () => { - const closeSpy = cy.stub().as("closeSpy"); - cy.mount(Closable Pill); - cy.findByTestId("pill-close-button").focus(); - cy.realPress("Enter"); - cy.get("@closeSpy").should("have.callCount", 1); - }); - it("THEN should close on space", () => { - const closeSpy = cy.stub().as("closeSpy"); - cy.mount(Closable Pill); - cy.findByTestId("pill-close-button").focus(); - cy.realPress(" "); - cy.get("@closeSpy").should("have.callCount", 1); - }); - }); - it("SHOULD have no a11y violations on load", () => { const clickSpy = cy.stub().as("clickSpy"); cy.mount(Pill); diff --git a/packages/lab/src/pill-next/PillNext.css b/packages/lab/src/pill-next/PillNext.css index 65a72a9763a..730ddd17cfd 100644 --- a/packages/lab/src/pill-next/PillNext.css +++ b/packages/lab/src/pill-next/PillNext.css @@ -1,27 +1,9 @@ /* Styles applied to the root element */ - .saltPillNext { - display: flex; - max-width: 100%; -} - -.saltPillNext-action { - --pillNext-background: var(--salt-actionable-primary-background); - --pillNext-background-active: var(--salt-actionable-primary-background-active); - --pillNext-background-disabled: var(--salt-actionable-primary-background-disabled); - --pillNext-background-hover: var(--salt-actionable-primary-background-hover); - --pillNext-text-color: var(--salt-actionable-primary-foreground); - --pillNext-text-color-active: var(--salt-actionable-primary-foreground-active); - --pillNext-text-color-hover: var(--salt-actionable-primary-foreground-hover); - --pillNext-text-color-disabled: var(--salt-actionable-primary-foreground-disabled); -} - -.saltPillNext-action { appearance: none; - -webkit-appearance: none; display: inline-flex; align-items: center; - background: var(--pillNext-background); + background: var(--saltPillNext-background, var(--salt-actionable-primary-background)); border-radius: 0; border: 0; height: calc(var(--salt-size-base) - var(--salt-spacing-100)); @@ -31,64 +13,41 @@ gap: var(--salt-spacing-50); padding-left: var(--salt-spacing-50); padding-right: var(--salt-spacing-50); - color: var(--pillNext-text-color); + color: var(--saltPillNext-color, var(--salt-actionable-primary-foreground)); font-family: var(--salt-text-fontFamily); font-size: var(--salt-text-fontSize); font-weight: var(--salt-text-fontWeight); line-height: var(--salt-text-lineHeight); -} - -.saltPillNext-label { - min-width: 0; overflow: hidden; - text-overflow: ellipsis; white-space: nowrap; } -.saltPillNext-close-button { - --saltButton-height: calc(var(--salt-size-base) - var(--salt-spacing-100)); - --saltButton-padding: var(--salt-spacing-50); -} - -/* Style applied to Pill if `onClick` prop is provided */ +/* Style applied to Pill if pill is clickable */ .saltPillNext-clickable { cursor: var(--salt-selectable-cursor-hover); } .saltPillNext-clickable:hover, .saltPillNext-clickable:focus-visible { - color: var(--pillNext-text-color-hover); - background: var(--pillNext-background-hover); -} - -.saltPillNext-clickable.saltPillNext-disabled:hover { - color: var(--pillNext-text-color); - background: var(--pillNext-background); + color: var(--salt-actionable-primary-foreground-hover); + background: var(--salt-actionable-primary-background-hover); } .saltPillNext-clickable.saltPillNext-active, .saltPillNext-clickable:active { - background: var(--pillNext-background-active); - color: var(--pillNext-text-color-active); -} - -.saltPillNext-clickable.saltPillNext-disabled.saltPillNext-active, -.saltPillNext-clickable.saltPillNext-disabled:active { - background: var(--pillNext-background); - color: var(--pillNext-text-color); + background: var(--salt-actionable-primary-background-active); + color: var(--salt-actionable-primary-foreground-active); } /* Style applied to Pill on focus */ -.saltPillNext-action:focus-visible { +.saltPillNext:focus-visible { outline: var(--salt-focused-outline); - /* increase index by one so the focus ring sits on top of the sibling button */ - z-index: var(--salt-zIndex-default); } /* Style applied to Pill when disabled */ -.saltPillNext-action.saltPillNext-disabled, -.saltPillNext-action.saltPillNext-disabled:hover { - color: var(--pillNext-text-color-disabled); - background: var(--pillNext-background-disabled); +.saltPillNext:disabled, +.saltPillNext:disabled:hover { + color: var(--salt-actionable-primary-foreground-disabled); + background: var(--salt-actionable-primary-background-disabled); cursor: var(--salt-selectable-cursor-disabled); } diff --git a/packages/lab/src/pill-next/PillNext.tsx b/packages/lab/src/pill-next/PillNext.tsx index e8aaf4fe9e1..2d286d0878c 100644 --- a/packages/lab/src/pill-next/PillNext.tsx +++ b/packages/lab/src/pill-next/PillNext.tsx @@ -1,24 +1,27 @@ -import { forwardRef, ComponentPropsWithoutRef, MouseEvent } from "react"; +import { forwardRef, ComponentPropsWithoutRef } from "react"; import clsx from "clsx"; import { useWindow } from "@salt-ds/window"; import { useComponentCssInjection } from "@salt-ds/styles"; -import { Button, makePrefixer, useButton } from "@salt-ds/core"; +import { makePrefixer, useButton } from "@salt-ds/core"; import pillCss from "./PillNext.css"; -import { CloseIcon } from "@salt-ds/icons"; - -export interface PillNextProps extends ComponentPropsWithoutRef<"button"> { - /* If true the pill will be disabled */ - disabled?: boolean; - onClose?: (event: MouseEvent) => void; - /* Pass an element to render an icon descriptor on the left of the label */ - icon?: React.ReactNode; -} const withBaseName = makePrefixer("saltPillNext"); +/* eslint-disable @typescript-eslint/no-empty-interface */ +export interface PillNextProps extends ComponentPropsWithoutRef<"button"> {} + export const PillNext = forwardRef( function PillNext( - { children, className, icon, disabled, onClose, ...restProps }, + { + children, + className, + disabled, + onKeyUp, + onKeyDown, + onClick, + onBlur, + ...rest + }, ref ) { const targetWindow = useWindow(); @@ -29,39 +32,30 @@ export const PillNext = forwardRef( }); const { buttonProps, active } = useButton({ disabled, - ...restProps, + onKeyUp, + onKeyDown, + onClick, + onBlur, }); // we do not want to spread tab index in this case because the button element // does not require tabindex="0" attribute // eslint-disable-next-line @typescript-eslint/no-unused-vars const { tabIndex, ...restButtonProps } = buttonProps; - return ( -
- - {onClose && ( - + ); } ); diff --git a/packages/lab/stories/pill-next/pill-next.qa.stories.tsx b/packages/lab/stories/pill-next/pill-next.qa.stories.tsx index 97b570165bc..c71a3e37156 100644 --- a/packages/lab/stories/pill-next/pill-next.qa.stories.tsx +++ b/packages/lab/stories/pill-next/pill-next.qa.stories.tsx @@ -20,14 +20,8 @@ export const ExamplesGrid: StoryFn = (props) => { Disabled Pill - } onClick={noop}> - With Icon Pill - - - Closable Pill - - - Extra extra long Pill label example. + + With Icon Pill ); diff --git a/packages/lab/stories/pill-next/pill-next.stories.tsx b/packages/lab/stories/pill-next/pill-next.stories.tsx index 97648411424..8712f47926a 100644 --- a/packages/lab/stories/pill-next/pill-next.stories.tsx +++ b/packages/lab/stories/pill-next/pill-next.stories.tsx @@ -1,9 +1,9 @@ import { PillNext } from "@salt-ds/lab"; -import { FavoriteIcon } from "@salt-ds/icons"; +import { CloseIcon, FavoriteIcon } from "@salt-ds/icons"; import { Meta, StoryFn } from "@storybook/react"; -import { ChangeEvent, Ref, useEffect, useRef, useState } from "react"; +import { useState } from "react"; import { shortColorData } from "./../assets/exampleData"; -import { Button, FlowLayout, Input, StackLayout, Tooltip } from "@salt-ds/core"; +import { Button, FlowLayout } from "@salt-ds/core"; export default { title: "Lab/Pill Next", @@ -48,10 +48,9 @@ export const Closable: StoryFn = () => { console.log(`Clicked ${color}`)} - onClose={() => removeColor(color)} + onClick={() => removeColor(color)} > - {color} + {color} ))} @@ -60,42 +59,8 @@ export const Closable: StoryFn = () => { export const Icon: StoryFn = () => { return ( - } onClick={() => console.log("Clicked.")}> - Pill with Icon + console.log("Clicked.")}> + Pill with Icon ); }; - -export const Truncated: StoryFn = () => { - const pillRef = useRef(null); - const [maxWidth, setMaxWidth] = useState("150"); - const [isEllipsisActive, setEllipsisActive] = useState(false); - - useEffect(() => { - const text = pillRef?.current?.firstElementChild as HTMLElement; - setEllipsisActive(text?.offsetWidth < text?.scrollWidth); - }, [maxWidth]); - - const content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; - - return ( - - ) => - setMaxWidth(event.target.value) - } - /> - - } - style={{ maxWidth: `${maxWidth}px` }} - > - {content} - - - - ); -}; diff --git a/site/docs/components/pill/accessibility.mdx b/site/docs/components/pill/accessibility.mdx index 12fdbc4431b..5a99479b629 100644 --- a/site/docs/components/pill/accessibility.mdx +++ b/site/docs/components/pill/accessibility.mdx @@ -12,18 +12,15 @@ data: - When focus is on the pill, this action activates it. - - When focus is on the close button, this action closes the pill. - Tab sets focus on the entire pill. - When the pill has focus, Tab moves focus out of the pill to next component in tab order. - - When a closable pill has focus, Tab moves focus into the close button. - When the pill has focus, this action moves focus out of the pill to the previous component in the tab order. - - When the close button has focus, this action moves focus back to the pill. diff --git a/site/docs/components/pill/examples.mdx b/site/docs/components/pill/examples.mdx index 397bb61f2f7..f006e25ec0f 100644 --- a/site/docs/components/pill/examples.mdx +++ b/site/docs/components/pill/examples.mdx @@ -35,12 +35,5 @@ data: The closable pill represents a value selected via another mechanism, and which the user can remove within the pill. It can appear on its own, such as alongside a complex filter panel, or within an input control such as [`ComboBox`](../combo-box). - - - - ### Closable - - The closable pill represents a value selected via another mechanism, and which the user can remove within the pill. It can appear on its own, such as alongside a complex filter panel, or within an input control such as [`ComboBox`](../combo-box). - diff --git a/site/docs/components/pill/index.mdx b/site/docs/components/pill/index.mdx index ad7ed03194b..6edb0422b7d 100644 --- a/site/docs/components/pill/index.mdx +++ b/site/docs/components/pill/index.mdx @@ -10,7 +10,6 @@ data: [ { name: "Button", relationship: "similarTo" }, { name: "Toggle button", relationship: "similarTo" }, - { name: "Icon", relationship: "contains" }, ] stickerSheet: "" layout: DetailComponent diff --git a/site/src/examples/pill/Closable.tsx b/site/src/examples/pill/Closable.tsx index f58eda816ee..29fd4967234 100644 --- a/site/src/examples/pill/Closable.tsx +++ b/site/src/examples/pill/Closable.tsx @@ -1,10 +1,13 @@ import { ReactElement } from "react"; import { PillNext } from "@salt-ds/lab"; +import { CloseIcon } from "@salt-ds/icons"; const handleClose = () => { console.log("closed"); }; export const Closable = (): ReactElement => ( - Closable Pill + + Closable Pill + ); diff --git a/site/src/examples/pill/Icon.tsx b/site/src/examples/pill/Icon.tsx index 264e7c769ae..9363de9e554 100644 --- a/site/src/examples/pill/Icon.tsx +++ b/site/src/examples/pill/Icon.tsx @@ -7,7 +7,7 @@ const handleClick = () => { }; export const Icon = (): ReactElement => ( - } onClick={handleClick}> - Pill with Icon + + Pill with Icon );