From b7d6ce0a22e23ba288853ccc4c0e414b765edd7d Mon Sep 17 00:00:00 2001 From: Jialecl Date: Mon, 22 Dec 2025 15:45:49 +0100 Subject: [PATCH] [breaking] alert has 100% conttrolled behaviour --- .../components/alert/code/AlertCodePage.tsx | 10 +++--- .../alert/code/examples/severalMessages.tsx | 33 ++++++++++++++++--- packages/lib/src/alert/Alert.test.tsx | 20 ----------- packages/lib/src/alert/Alert.tsx | 7 ++-- 4 files changed, 34 insertions(+), 36 deletions(-) diff --git a/apps/website/screens/components/alert/code/AlertCodePage.tsx b/apps/website/screens/components/alert/code/AlertCodePage.tsx index 96ce03ed8..bc77e4c8b 100644 --- a/apps/website/screens/components/alert/code/AlertCodePage.tsx +++ b/apps/website/screens/components/alert/code/AlertCodePage.tsx @@ -40,9 +40,7 @@ const sections = [ boolean - If true, the alert will have a close button that will remove the message from the alert, only in banner - and inline modes. The rest of the functionality will depend on the onClose event of each - message (e.g. closing the modal alert). + If true, the alert will have a close button that will call the onClose. true @@ -58,9 +56,9 @@ const sections = [ {messageTypeString} - List of messages to be displayed. Each message has a close action that will, apart from remove from the - alert the current message, call the onClose if it is defined. If the message is an array, the - alert will show a navigation bar to move between the messages.
+ List of messages to be displayed. Each message has a close action that will call the onClose{" "} + if it is defined. If the message is an array, the alert will show a navigation bar to move between the + messages.
The modal mode only allows one message per alert. In this case, the message must be an object and the presence of the onClose attribute is mandatory, since the management of the closing of the alert relies completely on the user. diff --git a/apps/website/screens/components/alert/code/examples/severalMessages.tsx b/apps/website/screens/components/alert/code/examples/severalMessages.tsx index 550ef7f1a..26fd8e6a6 100644 --- a/apps/website/screens/components/alert/code/examples/severalMessages.tsx +++ b/apps/website/screens/components/alert/code/examples/severalMessages.tsx @@ -1,11 +1,33 @@ import { DxcAlert, DxcInset, DxcFlex } from "@dxc-technology/halstack-react"; +import { useState } from "react"; const code = `() => { - const messages = [ - { text: "Your document as been auto-saved." }, - { text: "You can continue working without worrying, as all changes are automatically saved." }, - { text: "You can also go back to the previous version of the document." }, - ]; + const [messages, setMessages] = useState([ + { + text: "Your document as been auto-saved.", + onClose: () => { + setMessages((prevMessages) => prevMessages.filter(({ text }) => text !== "Your document as been auto-saved.")); + }, + }, + { + text: "You can continue working without worrying, as all changes are automatically saved.", + onClose: () => { + setMessages((prevMessages) => + prevMessages.filter( + ({ text }) => text !== "You can continue working without worrying, as all changes are automatically saved." + ) + ); + }, + }, + { + text: "You can also go back to the previous version of the document.", + onClose: () => { + setMessages((prevMessages) => + prevMessages.filter(({ text }) => text !== "You can also go back to the previous version of the document.") + ); + }, + }, + ]); return ( @@ -25,6 +47,7 @@ const scope = { DxcAlert, DxcInset, DxcFlex, + useState, }; export default { code, scope }; diff --git a/packages/lib/src/alert/Alert.test.tsx b/packages/lib/src/alert/Alert.test.tsx index a62c5430d..e47946d01 100644 --- a/packages/lib/src/alert/Alert.test.tsx +++ b/packages/lib/src/alert/Alert.test.tsx @@ -68,26 +68,6 @@ describe("Alert component tests", () => { fireEvent.click(closeButton); expect(onClose).toHaveBeenCalled(); }); - test("Alert with several messages closes properly each one", () => { - const { getByRole, getByText } = render(); - const closeButton = getByRole("button", { name: "Close message" }); - const nextButton = getByRole("button", { name: "Next message" }); - expect(getByText("1 of 4")).toBeTruthy(); - expect(getByText("Message 1")).toBeTruthy(); - fireEvent.click(closeButton); - expect(getByText("Message 2")).toBeTruthy(); - expect(getByText("1 of 3")).toBeTruthy(); - fireEvent.click(nextButton); - fireEvent.click(nextButton); - expect(getByText("Message 4")).toBeTruthy(); - expect(getByText("3 of 3")).toBeTruthy(); - fireEvent.click(closeButton); - expect(getByText("Message 3")).toBeTruthy(); - expect(getByText("2 of 2")).toBeTruthy(); - fireEvent.click(closeButton); - expect(getByRole("button", { name: "Close alert" })).toBeTruthy(); - expect(getByText("Message 2")).toBeTruthy(); - }); test("Alert actions are correctly called when pressed", () => { const primaryAction = jest.fn(); const secondaryAction = jest.fn(); diff --git a/packages/lib/src/alert/Alert.tsx b/packages/lib/src/alert/Alert.tsx index 3e2c5cc51..0c78ef570 100644 --- a/packages/lib/src/alert/Alert.tsx +++ b/packages/lib/src/alert/Alert.tsx @@ -1,6 +1,6 @@ import styled from "@emotion/styled"; import { css } from "@emotion/react"; -import { useState, useId, useEffect, useCallback, useContext } from "react"; +import { useState, useId, useEffect, useCallback, useContext, useMemo } from "react"; import AlertPropsType from "./types"; import DxcIcon from "../icon/Icon"; import DxcDivider from "../divider/Divider"; @@ -101,7 +101,7 @@ const DxcAlert = ({ semantic = "info", title = "", }: AlertPropsType) => { - const [messages, setMessages] = useState(Array.isArray(message) ? message : [message]); + const messages = useMemo(() => (Array.isArray(message) ? message : [message]), [message]); const [currentIndex, setCurrentIndex] = useState(0); const id = useId(); @@ -116,9 +116,6 @@ const DxcAlert = ({ const handleOnClose = useCallback(() => { messages[currentIndex]?.onClose?.(); - if (mode !== "modal") { - setMessages((prevMessages) => prevMessages.filter((_, index) => index !== currentIndex)); - } }, [messages, currentIndex, mode]); useEffect(() => {