diff --git a/packages/lib/src/alert/ModalAlertWrapper.tsx b/packages/lib/src/alert/ModalAlertWrapper.tsx index 87402f41a..3e2f5f466 100644 --- a/packages/lib/src/alert/ModalAlertWrapper.tsx +++ b/packages/lib/src/alert/ModalAlertWrapper.tsx @@ -23,7 +23,7 @@ const Modal = styled.div` align-items: center; justify-content: center; height: 100%; - z-index: 2147483647; + z-index: var(--z-alert); `; const Overlay = styled.div` @@ -38,7 +38,6 @@ const ModalAlertContainer = styled.div` box-sizing: border-box; max-width: 80%; min-width: 696px; - z-index: 2147483647; @media (max-width: ${responsiveSizes.medium}rem) { max-width: 92%; diff --git a/packages/lib/src/date-input/DateInput.stories.tsx b/packages/lib/src/date-input/DateInput.stories.tsx index 2a69be99c..0b16912a3 100644 --- a/packages/lib/src/date-input/DateInput.stories.tsx +++ b/packages/lib/src/date-input/DateInput.stories.tsx @@ -120,7 +120,7 @@ const YearPickerComponent = () => ( const DatePickerButtonStates = () => ( <> - + <Title title="Show date picker over another element with a certain z-index" theme="light" level={4} /> <div style={{ display: "flex", @@ -133,7 +133,7 @@ const DatePickerButtonStates = () => ( border: "1px solid black", borderRadius: "4px", overflow: "auto", - zIndex: "1300", + zIndex: "130", position: "relative", }} > diff --git a/packages/lib/src/date-input/DateInput.tsx b/packages/lib/src/date-input/DateInput.tsx index 74a9a8283..12fc76213 100644 --- a/packages/lib/src/date-input/DateInput.tsx +++ b/packages/lib/src/date-input/DateInput.tsx @@ -81,7 +81,7 @@ const HelperText = styled.span<{ disabled: DateInputPropsType["disabled"] }>` `; const StyledPopoverContent = styled(Popover.Content)` - z-index: 2147483647; + z-index: var(--z-date-input); &:focus-visible { outline: none; } diff --git a/packages/lib/src/dialog/Dialog.tsx b/packages/lib/src/dialog/Dialog.tsx index 2c2a3d1f1..6e9e16b4a 100644 --- a/packages/lib/src/dialog/Dialog.tsx +++ b/packages/lib/src/dialog/Dialog.tsx @@ -25,7 +25,7 @@ const DialogContainer = styled.div` align-items: center; justify-content: center; height: 100%; - z-index: 2147483647; + z-index: var(--z-dialog); `; const Overlay = styled.div` @@ -44,7 +44,6 @@ const Dialog = styled.div<{ closable: DialogPropsType["closable"] }>` background-color: var(--color-bg-neutral-lightest); ${(props) => props.closable && "min-height: 72px;"} box-shadow: var(--shadow-low-x-position) var(--shadow-low-y-position) var(--shadow-low-blur) var(--shadow-low-spread) var(--shadow-dark); - z-index: 2147483647; @media (max-width: ${responsiveSizes.medium}rem) { max-width: 92%; diff --git a/packages/lib/src/dropdown/Dropdown.stories.tsx b/packages/lib/src/dropdown/Dropdown.stories.tsx index 31399aa90..f6c5ad947 100644 --- a/packages/lib/src/dropdown/Dropdown.stories.tsx +++ b/packages/lib/src/dropdown/Dropdown.stories.tsx @@ -211,111 +211,102 @@ const Dropdown = () => ( </> ); -const DropdownListStates = () => { - const colorsTheme: any = useContext(HalstackContext); - - return ( - <> - <Title title="Dropdown Menu" theme="light" level={2} /> - <ExampleContainer> - <Title - title="List dialog uses a Radix Popover to appear over elements with a certain z-index" - theme="light" - level={3} - /> - <div - style={{ - position: "relative", - display: "flex", - flexDirection: "column", - gap: "20px", - height: "150px", - width: "min-content", - marginBottom: "100px", - padding: "20px", - border: "1px solid black", - borderRadius: "4px", - overflow: "auto", - zIndex: "1300", - }} - > - <DxcDropdown - label="Select a platform" - options={defaultOptions} - onSelectOption={(option) => {}} - size="medium" - /> - <button style={{ zIndex: "1", width: "100px" }}>Submit</button> - </div> - </ExampleContainer> - <Title title="Option states" theme="light" level={3} /> - <ExampleContainer pseudoState="pseudo-hover"> - <Title title="Hovered option" theme="light" level={4} /> - <DropdownMenu - id="x1" - dropdownTriggerId="dtx1" - iconsPosition="before" - visualFocusIndex={-1} - menuItemOnClick={() => {}} - onKeyDown={() => {}} - options={optionWithIcon} - styles={{ width: 240 }} - /> - </ExampleContainer> - <ExampleContainer pseudoState="pseudo-active"> - <Title title="Active option" theme="light" level={4} /> - <DropdownMenu - id="x2" - dropdownTriggerId="dtx2" - iconsPosition="before" - visualFocusIndex={-1} - menuItemOnClick={() => {}} - onKeyDown={() => {}} - options={optionWithIcon} - styles={{ width: 240 }} - /> - </ExampleContainer> - <ExampleContainer> - <Title title="Focused option" theme="light" level={4} /> - <DropdownMenu - id="x3" - dropdownTriggerId="dtx3" - iconsPosition="before" - visualFocusIndex={0} - menuItemOnClick={() => {}} - onKeyDown={() => {}} - options={options} - styles={{ width: 240 }} - /> - </ExampleContainer> - <Title title="Icons" theme="light" level={3} /> - <ExampleContainer> - <Title title="Before" theme="light" level={4} /> - <DropdownMenu - id="x4" - dropdownTriggerId="dtx4" - iconsPosition="before" - visualFocusIndex={-1} - menuItemOnClick={() => {}} - onKeyDown={() => {}} - options={optionsIcon} - styles={{ width: 240 }} - /> - <Title title="After" theme="light" level={4} /> - <DropdownMenu - id="x5" - dropdownTriggerId="dtx5" - iconsPosition="after" - visualFocusIndex={-1} - menuItemOnClick={() => {}} - onKeyDown={() => {}} - options={optionsIcon} - styles={{ width: 240 }} - /> - </ExampleContainer> - </> - ); -}; +const DropdownListStates = () => ( + <> + <Title title="Dropdown Menu" theme="light" level={2} /> + <ExampleContainer> + <Title + title="List dialog uses a Radix Popover to appear over elements with a certain z-index" + theme="light" + level={3} + /> + <div + style={{ + position: "relative", + display: "flex", + flexDirection: "column", + gap: "20px", + height: "150px", + width: "min-content", + marginBottom: "100px", + padding: "20px", + border: "1px solid black", + borderRadius: "4px", + overflow: "auto", + zIndex: "130", + }} + > + <DxcDropdown label="Select a platform" options={defaultOptions} onSelectOption={(option) => {}} size="medium" /> + <button style={{ zIndex: "1", width: "100px" }}>Submit</button> + </div> + </ExampleContainer> + <Title title="Option states" theme="light" level={3} /> + <ExampleContainer pseudoState="pseudo-hover"> + <Title title="Hovered option" theme="light" level={4} /> + <DropdownMenu + id="x1" + dropdownTriggerId="dtx1" + iconsPosition="before" + visualFocusIndex={-1} + menuItemOnClick={() => {}} + onKeyDown={() => {}} + options={optionWithIcon} + styles={{ width: 240 }} + /> + </ExampleContainer> + <ExampleContainer pseudoState="pseudo-active"> + <Title title="Active option" theme="light" level={4} /> + <DropdownMenu + id="x2" + dropdownTriggerId="dtx2" + iconsPosition="before" + visualFocusIndex={-1} + menuItemOnClick={() => {}} + onKeyDown={() => {}} + options={optionWithIcon} + styles={{ width: 240 }} + /> + </ExampleContainer> + <ExampleContainer> + <Title title="Focused option" theme="light" level={4} /> + <DropdownMenu + id="x3" + dropdownTriggerId="dtx3" + iconsPosition="before" + visualFocusIndex={0} + menuItemOnClick={() => {}} + onKeyDown={() => {}} + options={options} + styles={{ width: 240 }} + /> + </ExampleContainer> + <Title title="Icons" theme="light" level={3} /> + <ExampleContainer> + <Title title="Before" theme="light" level={4} /> + <DropdownMenu + id="x4" + dropdownTriggerId="dtx4" + iconsPosition="before" + visualFocusIndex={-1} + menuItemOnClick={() => {}} + onKeyDown={() => {}} + options={optionsIcon} + styles={{ width: 240 }} + /> + <Title title="After" theme="light" level={4} /> + <DropdownMenu + id="x5" + dropdownTriggerId="dtx5" + iconsPosition="after" + visualFocusIndex={-1} + menuItemOnClick={() => {}} + onKeyDown={() => {}} + options={optionsIcon} + styles={{ width: 240 }} + /> + </ExampleContainer> + </> +); const TooltipTitle = () => ( <ExampleContainer expanded> diff --git a/packages/lib/src/dropdown/DropdownMenu.tsx b/packages/lib/src/dropdown/DropdownMenu.tsx index f6ede9858..3523af212 100644 --- a/packages/lib/src/dropdown/DropdownMenu.tsx +++ b/packages/lib/src/dropdown/DropdownMenu.tsx @@ -15,7 +15,7 @@ const DropdownMenuContainer = styled.ul` var(--shadow-dark); outline: none; overflow-y: auto; - z-index: 2147483647; + z-index: var(--z-dropdown); ${scrollbarStyles} `; diff --git a/packages/lib/src/header/Header.tsx b/packages/lib/src/header/Header.tsx index 33d36c240..5480ebc2e 100644 --- a/packages/lib/src/header/Header.tsx +++ b/packages/lib/src/header/Header.tsx @@ -107,7 +107,7 @@ const ResponsiveMenu = styled.div<{ hasVisibility: boolean }>` position: fixed; top: 0; right: 0; - z-index: 2000; + z-index: var(--z-header-menu); @media (max-width: ${responsiveSizes.large}rem) and (min-width: ${responsiveSizes.small}rem) { width: 60vw; @@ -152,7 +152,7 @@ const Overlay = styled.div<{ hasVisibility: boolean }>` ${(props) => !props.hasVisibility && "display: none"}; } - z-index: 1600; + z-index: var(--z-header-overlay); `; const Dropdown = (props: ComponentProps<typeof DxcDropdown>) => ( diff --git a/packages/lib/src/layout/ApplicationLayout.tsx b/packages/lib/src/layout/ApplicationLayout.tsx index e718f28dd..59bceafef 100644 --- a/packages/lib/src/layout/ApplicationLayout.tsx +++ b/packages/lib/src/layout/ApplicationLayout.tsx @@ -32,7 +32,7 @@ const ApplicationLayoutContainer = styled.div<{ const HeaderContainer = styled.div` width: 100%; height: fit-content; - z-index: 3; + z-index: var(--z-app-layout-header); `; const VisibilityToggle = styled.div` @@ -43,7 +43,7 @@ const VisibilityToggle = styled.div` width: 100%; background-color: var(--color-bg-neutral-light); user-select: none; - z-index: 2; + z-index: 1; `; const HamburgerTrigger = styled.button` @@ -84,7 +84,7 @@ const SidenavContainer = styled.div` width: fit-content; min-width: 280px; height: 100%; - z-index: 1; + z-index: var(--z-app-layout-sidenav); position: sticky; overflow: auto; diff --git a/packages/lib/src/progress-bar/ProgressBar.tsx b/packages/lib/src/progress-bar/ProgressBar.tsx index fbb711e79..0ace4d0c2 100644 --- a/packages/lib/src/progress-bar/ProgressBar.tsx +++ b/packages/lib/src/progress-bar/ProgressBar.tsx @@ -21,7 +21,7 @@ const ProgressBarContainer = styled.div<{ align-items: center; justify-content: center; height: 100%; - z-index: 1300; + z-index: var(--z-progressbar-overlay); `} `; @@ -48,7 +48,7 @@ const MainContainer = styled.div<{ props.margin && typeof props.margin === "object" && props.margin.left ? spaces[props.margin.left] : ""}; display: flex; flex-direction: column; - z-index: ${(props) => (props.overlay ? "100" : "0")}; + z-index: ${(props) => (props.overlay ? "1" : "0")}; gap: var(--spacing-gap-s); `; diff --git a/packages/lib/src/select/Select.stories.tsx b/packages/lib/src/select/Select.stories.tsx index c27a1833b..d6a79009d 100644 --- a/packages/lib/src/select/Select.stories.tsx +++ b/packages/lib/src/select/Select.stories.tsx @@ -381,7 +381,7 @@ const SelectListbox = () => ( border: "1px solid black", borderRadius: "4px", overflow: "auto", - zIndex: "1300", + zIndex: "130", }} > <DxcSelect label="Label" options={single_options} optional placeholder="Choose an option" /> diff --git a/packages/lib/src/select/Select.tsx b/packages/lib/src/select/Select.tsx index 6ee60b7e3..13aac549b 100644 --- a/packages/lib/src/select/Select.tsx +++ b/packages/lib/src/select/Select.tsx @@ -601,7 +601,7 @@ const DxcSelect = forwardRef<RefType, SelectPropsType>( event.preventDefault(); }} sideOffset={4} - style={{ zIndex: "2147483647" }} + style={{ zIndex: "var(--z-dropdown)" }} > <Listbox ariaLabelledBy={labelId} diff --git a/packages/lib/src/spinner/Spinner.tsx b/packages/lib/src/spinner/Spinner.tsx index d491743fa..95a716b17 100644 --- a/packages/lib/src/spinner/Spinner.tsx +++ b/packages/lib/src/spinner/Spinner.tsx @@ -17,7 +17,7 @@ const SpinnerContainer = styled.div<{ align-items: center; justify-content: center; height: 100%; - z-index: 2147483647; + z-index: var(--z-spinner-overlay); `}; margin: ${(props) => diff --git a/packages/lib/src/styles/variables.css b/packages/lib/src/styles/variables.css index 834c43b9e..6107773cc 100644 --- a/packages/lib/src/styles/variables.css +++ b/packages/lib/src/styles/variables.css @@ -1,5 +1,39 @@ :root { - /* _Core */ + /**************/ + /** POSITION **/ + /**************/ + + /* Application Layout */ + --z-app-layout-header: 100; + --z-app-layout-sidenav: 110; + + /* Header */ + --z-header-overlay: 200; + --z-header-menu: 210; + + /* UI components */ + --z-date-input: 300; + --z-dropdown: 310; + --z-textinput: 320; + --z-select: 330; + + /* Modals and overlays */ + --z-spinner-overlay: 400; + --z-progressbar-overlay: 410; + --z-dialog: 420; + --z-alert: 430; + + /* Notifications */ + --z-toast: 500; + + /* Tooltip (topmost) */ + --z-tooltip: 600; + + /************/ + /** TOKENS **/ + /************/ + + /* Core tokens */ --color-absolutes-black: #000000; --color-absolutes-white: #ffffff; --color-alpha-100-a: #ebebeb1a; @@ -122,7 +156,7 @@ --line-style-dashed: dashed; --line-style-solid: solid; - /* Alias */ + /* Alias tokens */ --border-color-error-light: var(--color-red-300); --border-color-error-medium: var(--color-red-600); --border-color-error-strong: var(--color-red-700); @@ -329,4 +363,4 @@ --border-style-outline: var(--line-style-dashed); --typography-font-family: var(--font-family-sans); --typography-helper-text-italic: var(--font-style-lightitalic); -} \ No newline at end of file +} diff --git a/packages/lib/src/text-input/TextInput.stories.tsx b/packages/lib/src/text-input/TextInput.stories.tsx index 500a44470..765812582 100644 --- a/packages/lib/src/text-input/TextInput.stories.tsx +++ b/packages/lib/src/text-input/TextInput.stories.tsx @@ -242,7 +242,7 @@ const AutosuggestListbox = () => ( border: "1px solid black", borderRadius: "4px", overflow: "auto", - zIndex: "1300", + zIndex: "130", position: "relative", }} > diff --git a/packages/lib/src/text-input/TextInput.tsx b/packages/lib/src/text-input/TextInput.tsx index 4568e2363..778629c0a 100644 --- a/packages/lib/src/text-input/TextInput.tsx +++ b/packages/lib/src/text-input/TextInput.tsx @@ -470,7 +470,7 @@ const DxcTextInput = forwardRef<RefType, TextInputPropsType>( event.preventDefault(); }} sideOffset={4} - style={{ zIndex: "2147483647" }} + style={{ zIndex: "var(--z-textinput)" }} > <Suggestions highlightedSuggestions={typeof suggestions !== "function"} diff --git a/packages/lib/src/toast/Toast.stories.tsx b/packages/lib/src/toast/Toast.stories.tsx index ed43840b2..8d2e0e234 100644 --- a/packages/lib/src/toast/Toast.stories.tsx +++ b/packages/lib/src/toast/Toast.stories.tsx @@ -8,6 +8,9 @@ import DxcToastsQueue from "./ToastsQueue"; import useToast from "./useToast"; import { INITIAL_VIEWPORTS } from "@storybook/addon-viewport"; import { Meta, StoryObj } from "@storybook/react"; +import DxcDialog from "../dialog/Dialog"; +import DxcInset from "../inset/Inset"; +import { screen } from "@testing-library/react"; export default { title: "Toast", @@ -264,6 +267,64 @@ const playFunc = async ({ canvasElement }: { canvasElement: HTMLElement }) => { await userEvent.click(canvas.getByText("Show success toast")); }; +const ToastAboveDialog = () => { + const toast = useToast(); + + return ( + <ExampleContainer> + <Title title="Screen placement" /> + <DxcDialog> + <DxcInset space="var(--spacing-padding-l)"> + <DxcFlex gap="var(--spacing-gap-ml)" direction="column"> + <DxcButton + label="Show default toast" + onClick={() => { + toast.default({ message: "This is a simple placed toast." }); + }} + /> + <DxcButton + label="Show info toast" + onClick={() => { + toast.info({ + message: + "This is a very long label for a Toast. Please, always try to avoid this king of messages, be brief and concise.", + action: actionIcon, + }); + }} + /> + <DxcButton + label="Show success toast" + onClick={() => { + toast.success({ + message: + "This is another very long label for a Toast. Please, always try to avoid this king of messages, be brief and concise.", + action: action, + }); + }} + /> + </DxcFlex> + </DxcInset> + </DxcDialog> + </ExampleContainer> + ); +}; + +const ToastsQueueAboveDialog = () => ( + <DxcToastsQueue> + <ToastAboveDialog /> + </DxcToastsQueue> +); + +const playFuncDialog = async () => { + const showDefaultButton = await screen.findByText("Show default toast"); + const showInfoButton = await screen.findByText("Show info toast"); + const showSuccessButton = await screen.findByText("Show success toast"); + + await userEvent.click(showDefaultButton); + await userEvent.click(showInfoButton); + await userEvent.click(showSuccessButton); +}; + type Story = StoryObj<typeof DxcToast>; export const Chromatic: Story = { @@ -285,3 +346,8 @@ export const MobileScreenToast: Story = { }, }, }; + +export const AboveDialogToast: Story = { + render: ToastsQueueAboveDialog, + play: playFuncDialog, +}; diff --git a/packages/lib/src/toast/ToastsQueue.tsx b/packages/lib/src/toast/ToastsQueue.tsx index fdf4fe1e0..9625552d3 100644 --- a/packages/lib/src/toast/ToastsQueue.tsx +++ b/packages/lib/src/toast/ToastsQueue.tsx @@ -13,7 +13,7 @@ const ToastsQueue = styled.section` position: fixed; bottom: 0; right: 0; - z-index: 2147483647; + z-index: var(--z-toast); display: flex; flex-direction: column; align-items: flex-end; diff --git a/packages/lib/src/tooltip/Tooltip.tsx b/packages/lib/src/tooltip/Tooltip.tsx index 67082249d..abf85fbda 100644 --- a/packages/lib/src/tooltip/Tooltip.tsx +++ b/packages/lib/src/tooltip/Tooltip.tsx @@ -11,7 +11,7 @@ const TooltipTriggerContainer = styled.div` `; const StyledTooltipContent = styled(Content)` - z-index: 2147483647; + z-index: var(--z-tooltip); animation-duration: 0.2s; animation-timing-function: ease-out;