diff --git a/apps/web/src/components/chat/ComposerBannerStack.test.tsx b/apps/web/src/components/chat/ComposerBannerStack.test.tsx new file mode 100644 index 00000000000..16fdff64425 --- /dev/null +++ b/apps/web/src/components/chat/ComposerBannerStack.test.tsx @@ -0,0 +1,37 @@ +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, it } from "vite-plus/test"; + +import { ComposerBannerStack, type ComposerBannerStackItem } from "./ComposerBannerStack"; + +const banner = (id: string): ComposerBannerStackItem => ({ + id, + variant: "warning", + icon: , + title: `${id} warning`, +}); + +describe("ComposerBannerStack", () => { + it("keeps expanded banners in layout flow so surrounding content moves out of their way", () => { + const markup = renderToStaticMarkup( + , + ); + + const expandedItems = markup.match( + /
/, + ); + + expect(expandedItems?.[1]).toContain("grid-rows-[0fr]"); + expect(expandedItems?.[1]).toContain("group-hover/banner-stack:grid-rows-[1fr]"); + expect(expandedItems?.[1]).toContain("z-20"); + expect(expandedItems?.[1]).not.toContain("absolute"); + expect(markup.indexOf("front warning")).toBeLessThan(markup.indexOf("stacked warning")); + expect(markup).toContain("invisible pointer-events-none"); + expect(markup).toContain("group-focus-within/banner-stack:visible"); + }); + + it("does not render an expandable region for a single banner", () => { + const markup = renderToStaticMarkup(); + + expect(markup).not.toContain("data-composer-banner-stack-expanded-items"); + }); +}); diff --git a/apps/web/src/components/chat/ComposerBannerStack.tsx b/apps/web/src/components/chat/ComposerBannerStack.tsx index 1f82c452b05..d51c23a2f27 100644 --- a/apps/web/src/components/chat/ComposerBannerStack.tsx +++ b/apps/web/src/components/chat/ComposerBannerStack.tsx @@ -85,7 +85,7 @@ export function ComposerBannerStack({ className, items }: ComposerBannerStackPro
@@ -119,30 +119,39 @@ export function ComposerBannerStack({ className, items }: ComposerBannerStackPro
{hasStack ? (
- {stackedItems.map((item) => ( +
- requestDismiss(item)} - /> + {stackedItems.map((item) => ( +
+ requestDismiss(item)} + /> +
+ ))}
- ))} +
) : null}
diff --git a/apps/web/src/components/chat/DraftHeroHeadline.tsx b/apps/web/src/components/chat/DraftHeroHeadline.tsx index 32d195d7b2e..6a88fb8da19 100644 --- a/apps/web/src/components/chat/DraftHeroHeadline.tsx +++ b/apps/web/src/components/chat/DraftHeroHeadline.tsx @@ -101,7 +101,7 @@ export function DraftHeroHeadline({ ); return ( -

+

{hasResolvedProject ? ( <>What should we build in {projectSelector}? ) : canChooseProject ? (