diff --git a/apps/website/screens/components/application-layout/overview/ApplicationLayoutOverviewPage.tsx b/apps/website/screens/components/application-layout/overview/ApplicationLayoutOverviewPage.tsx index efb1c5da3..cac27581e 100644 --- a/apps/website/screens/components/application-layout/overview/ApplicationLayoutOverviewPage.tsx +++ b/apps/website/screens/components/application-layout/overview/ApplicationLayoutOverviewPage.tsx @@ -248,7 +248,7 @@ const sections = [ multiples of 8px for visual harmony. - imit 4px adjustments: Reserve finer increments only for edge cases like icon alignment or + Imit 4px adjustments: Reserve finer increments only for edge cases like icon alignment or typography. diff --git a/apps/website/screens/components/footer/code/FooterCodePage.tsx b/apps/website/screens/components/footer/code/FooterCodePage.tsx index 943aee208..7bffbaa62 100644 --- a/apps/website/screens/components/footer/code/FooterCodePage.tsx +++ b/apps/website/screens/components/footer/code/FooterCodePage.tsx @@ -10,7 +10,7 @@ const bottomLinksTypeString = `{ }[]`; const logoTypeString = `{ - src: string; + src: string | SVG; alt: string; }`; diff --git a/packages/lib/src/footer/Footer.stories.tsx b/packages/lib/src/footer/Footer.stories.tsx index 73b52fb5a..647058300 100644 --- a/packages/lib/src/footer/Footer.stories.tsx +++ b/packages/lib/src/footer/Footer.stories.tsx @@ -7,6 +7,7 @@ import DxcFooter from "./Footer"; import DxcLink from "../link/Link"; import { Meta, StoryObj } from "@storybook/react-vite"; import { userEvent, within } from "storybook/internal/test"; +import { useEffect } from "react"; import DxcParagraph from "../paragraph/Paragraph"; import DxcHeading from "../heading/Heading"; import DxcApplicationLayout from "../layout/ApplicationLayout"; @@ -17,6 +18,15 @@ import DxcButton from "../button/Button"; export default { title: "Footer", component: DxcFooter, + decorators: [ + (Story) => { + useEffect(() => { + document.body.style.padding = "0"; + }, []); + + return ; + }, + ], parameters: { a11y: { config: { diff --git a/packages/lib/src/footer/Footer.tsx b/packages/lib/src/footer/Footer.tsx index 577dfe1c5..2d56ad681 100644 --- a/packages/lib/src/footer/Footer.tsx +++ b/packages/lib/src/footer/Footer.tsx @@ -1,4 +1,4 @@ -import { useContext, useEffect, useMemo, useRef, useState } from "react"; +import { isValidElement, useContext, useEffect, useMemo, useRef, useState } from "react"; import styled from "@emotion/styled"; import DxcIcon from "../icon/Icon"; import { Tooltip } from "../tooltip/Tooltip"; @@ -65,6 +65,11 @@ const LogoContainer = styled.span<{ mode?: FooterPropsType["mode"] }>` justify-content: flex-start; align-items: center; `} + + svg { + height: ${(props) => (props.mode === "default" ? "var(--height-m)" : "var(--height-xxs)")}; + width: auto; + } `; const LogoImg = styled.img<{ mode: FooterPropsType["mode"] }>` @@ -213,8 +218,10 @@ const DxcFooter = ({ const translatedLabels = useContext(HalstackLanguageContext); const footerLogo = useMemo(() => { - if (logo) { + if (logo && typeof logo.src === "string") { return ; + } else if (isValidElement(logo?.src)) { + return logo.src; } else { return mode === "default" ? dxcLogo : dxcSmallLogo; } diff --git a/packages/lib/src/footer/types.ts b/packages/lib/src/footer/types.ts index 2706fa804..857425607 100644 --- a/packages/lib/src/footer/types.ts +++ b/packages/lib/src/footer/types.ts @@ -31,7 +31,7 @@ type Logo = { /** * Source of the logo image. */ - src: string; + src: string | SVG; /** * Alternative text for the logo image. */ diff --git a/packages/lib/src/layout/ApplicationLayout.stories.tsx b/packages/lib/src/layout/ApplicationLayout.stories.tsx index 4f1fa5b29..9d468b65d 100644 --- a/packages/lib/src/layout/ApplicationLayout.stories.tsx +++ b/packages/lib/src/layout/ApplicationLayout.stories.tsx @@ -2,10 +2,20 @@ import { Meta, StoryObj } from "@storybook/react-vite"; import Title from "../../.storybook/components/Title"; import DxcApplicationLayout from "./ApplicationLayout"; import { userEvent, within } from "storybook/internal/test"; +import { useEffect } from "react"; export default { title: "Application Layout", component: DxcApplicationLayout, + decorators: [ + (Story) => { + useEffect(() => { + document.body.style.padding = "0"; + }, []); + + return ; + }, + ], } satisfies Meta; const dxcLogo = ( diff --git a/packages/lib/src/layout/ApplicationLayout.tsx b/packages/lib/src/layout/ApplicationLayout.tsx index 16b55ab42..1b760aa71 100644 --- a/packages/lib/src/layout/ApplicationLayout.tsx +++ b/packages/lib/src/layout/ApplicationLayout.tsx @@ -1,4 +1,4 @@ -import { useMemo, useRef } from "react"; +import React, { useMemo, useRef, useState, useCallback } from "react"; import styled from "@emotion/styled"; import DxcFooter from "../footer/Footer"; import DxcHeader from "../header/Header"; @@ -8,46 +8,42 @@ import { bottomLinks, findChildType, socialLinks, year } from "./utils"; import ApplicationLayoutContext from "./ApplicationLayoutContext"; const ApplicationLayoutContainer = styled.div<{ header?: React.ReactNode }>` - top: 0; - left: 0; display: grid; - grid-template-rows: ${({ header }) => (header ? "auto 1fr" : "1fr")}; - height: 100vh; - width: 100vw; - position: absolute; - overflow: hidden; + grid-template-rows: ${({ header }) => (header ? "auto 1fr auto" : "1fr auto")}; + min-height: 100vh; `; const HeaderContainer = styled.div` + position: sticky; + top: 0; width: 100%; - min-height: var(--height-xxxl); height: fit-content; z-index: var(--z-app-layout-header); `; const BodyContainer = styled.div<{ hasSidenav?: boolean }>` + position: relative; display: grid; grid-template-columns: ${({ hasSidenav }) => (hasSidenav ? "auto 1fr" : "1fr")}; grid-template-rows: 1fr; - overflow: hidden; + min-height: 100%; `; -const SidenavContainer = styled.div` +const SidenavContainer = styled.div<{ headerHeight: string }>` width: fit-content; height: 100%; z-index: var(--z-app-layout-sidenav); position: sticky; + top: ${({ headerHeight }) => headerHeight || "0"}; overflow: auto; + max-height: ${({ headerHeight }) => `calc(100vh - ${headerHeight || "0"})`}; `; -const MainContainer = styled.div` - display: flex; - flex-grow: 1; - flex-direction: column; +const MainContainer = styled.main` + position: relative; + display: grid; width: 100%; height: 100%; - position: relative; - overflow: auto; `; const FooterContainer = styled.div` @@ -55,15 +51,21 @@ const FooterContainer = styled.div` width: 100%; `; -const MainContentContainer = styled.main` - height: 100%; - display: grid; - grid-template-rows: 1fr auto; -`; - const Main = ({ children }: AppLayoutMainPropsType): JSX.Element =>
{children}
; const DxcApplicationLayout = ({ logo, header, sidenav, footer, children }: ApplicationLayoutPropsType): JSX.Element => { + const [headerHeight, setHeaderHeight] = useState("0px"); + + const handleHeaderHeight = useCallback( + (headerElement: HTMLDivElement | null) => { + if (headerElement) { + const height = headerElement.offsetHeight; + setHeaderHeight(`${height}px`); + } + }, + [header] + ); + const contextValue = useMemo(() => { return { logo, @@ -75,24 +77,20 @@ const DxcApplicationLayout = ({ logo, header, sidenav, footer, children }: Appli return ( - {header && {header}} + {header && {header}} - {sidenav && {sidenav}} - - - {findChildType(children, Main)} - - {footer ?? ( - - )} - - - + {sidenav && {sidenav}} + {findChildType(children, Main)} + + {footer ?? ( + + )} + ); diff --git a/packages/lib/src/search-bar/SearchBar.tsx b/packages/lib/src/search-bar/SearchBar.tsx index a160ee95e..42440567c 100644 --- a/packages/lib/src/search-bar/SearchBar.tsx +++ b/packages/lib/src/search-bar/SearchBar.tsx @@ -72,8 +72,8 @@ const DxcSearchBar = ({ const inputRef = useRef(null); const [innerValue, setInnerValue] = useState(""); - const handleClearActionOnClick = () => { - setInnerValue(""); + const handleClearAction = () => { + handleSearchChangeValue(""); inputRef.current?.focus(); }; @@ -90,7 +90,7 @@ const DxcSearchBar = ({ case "Escape": e.preventDefault(); if (innerValue.length > 0) { - handleClearActionOnClick(); + handleClearAction(); } break; case "Enter": @@ -123,7 +123,7 @@ const DxcSearchBar = ({ size="xsmall" shape="circle" icon="cancel" - onClick={handleClearActionOnClick} + onClick={handleClearAction} tabIndex={0} title={!disabled ? translatedLabels.searchBar.clearFieldActionTitle : undefined} /> diff --git a/packages/lib/src/sidenav/Sidenav.stories.tsx b/packages/lib/src/sidenav/Sidenav.stories.tsx index e0a68423d..27adbfa10 100644 --- a/packages/lib/src/sidenav/Sidenav.stories.tsx +++ b/packages/lib/src/sidenav/Sidenav.stories.tsx @@ -10,11 +10,20 @@ import DxcAvatar from "../avatar/Avatar"; import { userEvent, within } from "storybook/internal/test"; import disabledRules from "../../test/accessibility/rules/specific/sidenav/disabledRules"; import preview from "../../.storybook/preview"; -import { useState } from "react"; +import { useEffect, useState } from "react"; export default { title: "Sidenav", component: DxcSidenav, + decorators: [ + (Story) => { + useEffect(() => { + document.body.style.padding = "0"; + }, []); + + return ; + }, + ], parameters: { a11y: { config: { @@ -34,7 +43,7 @@ const DetailedAvatar = () => { { Michael Ramirez