Skip to content

Commit 637362e

Browse files
fix: makes productIcon optional in ProductSwitcherItem (#4359)
* fix: makes productIcon optional in ProductSwitcherItem * fix: removes customizationprovider from story * Update .changeset/great-frogs-grin.md Co-authored-by: krisantrobus <55083528+krisantrobus@users.noreply.github.com> * fix(ci): fix failing ci checks * fix(ci): fix failing ci checks --------- Co-authored-by: krisantrobus <55083528+krisantrobus@users.noreply.github.com> Co-authored-by: Kristian Antrobus <kantrobus@twilio.com>
1 parent c0eff2d commit 637362e

File tree

5 files changed

+111
-11
lines changed

5 files changed

+111
-11
lines changed

.changeset/great-frogs-grin.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@twilio-paste/product-switcher": patch
3+
"@twilio-paste/core": patch
4+
---
5+
6+
[ProductSwitcherItem] made productIcon optional

packages/paste-core/components/product-switcher/__tests__/ProductSwitcher.spec.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { act, render, screen } from "@testing-library/react";
22
import * as React from "react";
33

4-
import { CustomElementName, DefaultElementName } from "../stories/ProductSwitcher.customization.stories";
4+
import {
5+
CustomElementName,
6+
DefaultElementName,
7+
WithoutProductIcons,
8+
} from "../stories/ProductSwitcher.customization.stories";
59
import { ProductSwitcherMenu } from "../stories/ProductSwitcher.stories";
610

711
describe("ProductSwitcher", () => {
@@ -64,3 +68,21 @@ describe("ProductSwitcher", () => {
6468
});
6569
});
6670
});
71+
describe("customization of productIcon", () => {
72+
it("should render product icon if set", async () => {
73+
await act(async () => {
74+
render(<DefaultElementName />);
75+
});
76+
const menuItem = screen.getByRole("menuitemradio", { name: "Twilio SMS, Voice & Video" });
77+
const imgChildren = Array.from(menuItem.querySelectorAll('[role="img"]'));
78+
expect(imgChildren).toHaveLength(2);
79+
});
80+
it("should not render product icon if none is set", async () => {
81+
await act(async () => {
82+
render(<WithoutProductIcons />);
83+
});
84+
const menuItem = screen.getByRole("menuitemradio", { name: "Twilio SMS, Voice & Video" });
85+
const imgChildren = Array.from(menuItem.querySelectorAll('[role="img"]'));
86+
expect(imgChildren).toHaveLength(1);
87+
});
88+
});

packages/paste-core/components/product-switcher/src/ProductSwitcherItem.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ export interface ProductSwitcherItemProps extends Omit<MenuItemRadioProps, "vari
2424
* Icon to use for the ProductSwitcherItem. Use a Paste Icon.
2525
*
2626
* @default 'PRODUCT_SWITCHER_ITEM'
27-
* @type {NonNullable<React.ReactNode>}
27+
* @type {React.ReactNode}
2828
* @memberof ProductSwitcherItemProps
2929
*/
30-
productIcon: NonNullable<React.ReactNode>;
30+
productIcon?: React.ReactNode;
3131
/**
3232
* Overrides the default element name to apply unique styles with the Customization Provider.
3333
*
@@ -43,7 +43,7 @@ const ProductSwitcherItem = React.forwardRef<HTMLDivElement, ProductSwitcherItem
4343
return (
4444
<MenuItemRadio element={element} {...props} ref={ref}>
4545
<Box display="flex" flexDirection="row" columnGap="space50" alignItems="center">
46-
<Box color="colorTextIcon">{productIcon}</Box>
46+
{productIcon && <Box color="colorTextIcon">{productIcon}</Box>}
4747
<Box>
4848
<Text as="span" display="block">
4949
{productName}

packages/paste-core/components/product-switcher/stories/ProductSwitcher.customization.stories.tsx

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,75 @@ export const CustomElementName: StoryFn = () => {
173173
</CustomizationProvider>
174174
);
175175
};
176+
177+
export const WithoutProductIcons: StoryFn = () => {
178+
const productSwitcher = useProductSwitcherState({ visible: true });
179+
const [product, setProduct] = React.useState("twilio");
180+
return (
181+
<>
182+
<ProductSwitcherButton {...productSwitcher} element="FOO" i18nButtonLabel="Switch products" />
183+
<ProductSwitcher {...productSwitcher} element="BAR" aria-label="Avaiable accounts">
184+
<ProductSwitcherItem
185+
{...productSwitcher}
186+
element="BAZ"
187+
name="product"
188+
value="twilio"
189+
checked={product === "twilio"}
190+
onChange={() => {
191+
setProduct("twilio");
192+
}}
193+
productName="Twilio"
194+
productStrapline="SMS, Voice & Video"
195+
/>
196+
<ProductSwitcherItem
197+
{...productSwitcher}
198+
element="BAZ"
199+
name="product"
200+
value="segment"
201+
checked={product === "segment"}
202+
onChange={() => {
203+
setProduct("segment");
204+
}}
205+
productName="Segment"
206+
productStrapline="Customer data platform"
207+
/>
208+
<ProductSwitcherItem
209+
{...productSwitcher}
210+
element="BAZ"
211+
name="product"
212+
value="flex"
213+
checked={product === "flex"}
214+
onChange={() => {
215+
setProduct("flex");
216+
}}
217+
productName="Flex"
218+
productStrapline="Cloud-based contact center"
219+
/>
220+
<ProductSwitcherItem
221+
{...productSwitcher}
222+
element="BAZ"
223+
name="product"
224+
value="sendgrid"
225+
checked={product === "sendgrid"}
226+
onChange={() => {
227+
setProduct("sendgrid");
228+
}}
229+
productName="SendGrid"
230+
productStrapline="Email delivery and API"
231+
/>
232+
<ProductSwitcherItem
233+
{...productSwitcher}
234+
element="BAZ"
235+
name="product"
236+
value="admin"
237+
checked={product === "admin"}
238+
onChange={() => {
239+
setProduct("admin");
240+
}}
241+
productName="Console Admin"
242+
productStrapline="Admin center"
243+
/>
244+
</ProductSwitcher>
245+
</>
246+
);
247+
};

packages/paste-core/components/product-switcher/type-docs.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2026,13 +2026,6 @@
20262026
"externalProp": true,
20272027
"description": "Moves focus to the previous item."
20282028
},
2029-
"productIcon": {
2030-
"type": "NonNullable<ReactNode>",
2031-
"defaultValue": "'PRODUCT_SWITCHER_ITEM'",
2032-
"required": true,
2033-
"externalProp": false,
2034-
"description": "Icon to use for the ProductSwitcherItem. Use a Paste Icon."
2035-
},
20362029
"productName": {
20372030
"type": "string",
20382031
"defaultValue": null,
@@ -3883,6 +3876,13 @@
38833876
"required": false,
38843877
"externalProp": true
38853878
},
3879+
"productIcon": {
3880+
"type": "string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...>",
3881+
"defaultValue": "'PRODUCT_SWITCHER_ITEM'",
3882+
"required": false,
3883+
"externalProp": false,
3884+
"description": "Icon to use for the ProductSwitcherItem. Use a Paste Icon."
3885+
},
38863886
"property": {
38873887
"type": "string",
38883888
"defaultValue": null,

0 commit comments

Comments
 (0)