From c685d9e77e52314f41212fbb2ee8646464753654 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 15 Sep 2026 11:53:54 -0700 Subject: [PATCH 1/3] fix(empty): refine empty state styling --- .changeset/gentle-empty-titles.md | 5 ++ .../kumo/src/components/empty/empty.test.tsx | 66 +++++++++++++++++++ packages/kumo/src/components/empty/empty.tsx | 45 ++++++++----- 3 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 .changeset/gentle-empty-titles.md create mode 100644 packages/kumo/src/components/empty/empty.test.tsx diff --git a/.changeset/gentle-empty-titles.md b/.changeset/gentle-empty-titles.md new file mode 100644 index 0000000000..d1e2331280 --- /dev/null +++ b/.changeset/gentle-empty-titles.md @@ -0,0 +1,5 @@ +--- +"@cloudflare/kumo": patch +--- + +Refine Empty state typography and balance description text when it wraps. diff --git a/packages/kumo/src/components/empty/empty.test.tsx b/packages/kumo/src/components/empty/empty.test.tsx new file mode 100644 index 0000000000..4b2f713bdf --- /dev/null +++ b/packages/kumo/src/components/empty/empty.test.tsx @@ -0,0 +1,66 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vite-plus/test"; +import { Empty } from "./empty"; + +describe("Empty", () => { + it("renders the title as a large heading when a description is present", () => { + render( + , + ); + + const title = screen.getByText("No results found"); + const description = screen.getByText("Try adjusting your search."); + + expect(title.tagName).toBe("H2"); + expect(title.className).toContain("text-xl"); + expect(title.className).toContain("font-semibold"); + expect(description.className).toContain("text-base/[inherit]"); + expect(description.className).toContain("text-kumo-subtle"); + expect(description.className).toContain("text-balance"); + expect(description.className).toContain("leading-normal"); + expect(title.parentElement).toBe(description.parentElement); + expect(title.parentElement?.className).toContain("gap-2.5"); + }); + + it("renders the title as base secondary text without a description", () => { + render(); + + const title = screen.getByText("Nothing here"); + + expect(title.className).toContain("text-base/[inherit]"); + expect(title.className).toContain("text-kumo-subtle"); + expect(title.className).not.toContain("font-semibold"); + }); + + it("renders the command line without a background or brand-colored text", () => { + render(); + + const command = screen.getByText("npm install kumo"); + const commandTextGroup = command.parentElement; + const commandContainer = commandTextGroup?.parentElement; + + expect(command.className).not.toContain("text-kumo-brand"); + expect(commandContainer?.className).not.toContain("bg-kumo-overlay"); + expect(commandContainer?.className.split(" ")).not.toContain("border"); + expect(commandContainer?.className.split(" ")).toContain("ring"); + expect(commandContainer?.className).toContain("ring-kumo-line"); + expect(commandContainer?.className).toContain("items-center"); + expect(commandTextGroup?.className).toContain("items-baseline"); + expect(commandContainer?.className).toContain("shadow-sm"); + expect(commandContainer?.className).not.toContain("shadow-xs"); + expect(commandContainer?.className).not.toContain("hover:"); + + const prompt = screen.getByText("$"); + expect(prompt.className).toContain("text-kumo-subtle"); + expect(prompt.className).not.toContain("text-xs"); + + const copyButton = screen.getByRole("button", { name: "Copy command" }); + expect(copyButton.className).toContain("text-kumo-subtle"); + + const copyIcon = copyButton.querySelector("svg"); + expect(copyIcon?.getAttribute("class") ?? "").not.toContain("group-hover:"); + }); +}); diff --git a/packages/kumo/src/components/empty/empty.tsx b/packages/kumo/src/components/empty/empty.tsx index 7763e1dbc4..2d4bd47871 100644 --- a/packages/kumo/src/components/empty/empty.tsx +++ b/packages/kumo/src/components/empty/empty.tsx @@ -1,6 +1,7 @@ import { CheckIcon, CopyIcon } from "@phosphor-icons/react"; import { useState } from "react"; import { Button } from "../../components/button"; +import { Text } from "../../components/text"; import { cn } from "../../utils/cn"; import { resolveVariant } from "../../utils/resolve-variant"; @@ -102,27 +103,42 @@ export function Empty({ return (
{icon} -

{title}

+
+ {description ? ( + + {title} + + ) : ( + + {title} + + )} - {description && ( -

{description}

- )} + {description && ( + + {description} + + )} +
{commandLine && (
- $ - - {commandLine} + + $ + + {commandLine} +
From 5901e287f3d237c870d827a9bdcaab6c06033653 Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 15 Sep 2026 11:55:36 -0700 Subject: [PATCH 2/3] fix(empty): adjust command line styling --- packages/kumo/src/components/empty/empty.test.tsx | 11 ++++++----- packages/kumo/src/components/empty/empty.tsx | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/kumo/src/components/empty/empty.test.tsx b/packages/kumo/src/components/empty/empty.test.tsx index 4b2f713bdf..a0661e7f22 100644 --- a/packages/kumo/src/components/empty/empty.test.tsx +++ b/packages/kumo/src/components/empty/empty.test.tsx @@ -35,7 +35,7 @@ describe("Empty", () => { expect(title.className).not.toContain("font-semibold"); }); - it("renders the command line without a background or brand-colored text", () => { + it("renders the command line with inset styling and without brand-colored text", () => { render(); const command = screen.getByText("npm install kumo"); @@ -43,14 +43,15 @@ describe("Empty", () => { const commandContainer = commandTextGroup?.parentElement; expect(command.className).not.toContain("text-kumo-brand"); - expect(commandContainer?.className).not.toContain("bg-kumo-overlay"); - expect(commandContainer?.className.split(" ")).not.toContain("border"); + expect(commandContainer?.className).toContain("bg-kumo-overlay"); + expect(commandContainer?.className.split(" ")).toContain("border"); + expect(commandContainer?.className).toContain("border-white"); expect(commandContainer?.className.split(" ")).toContain("ring"); expect(commandContainer?.className).toContain("ring-kumo-line"); expect(commandContainer?.className).toContain("items-center"); expect(commandTextGroup?.className).toContain("items-baseline"); - expect(commandContainer?.className).toContain("shadow-sm"); - expect(commandContainer?.className).not.toContain("shadow-xs"); + expect(commandContainer?.className).toContain("shadow-xs"); + expect(commandContainer?.className).not.toContain("shadow-inner"); expect(commandContainer?.className).not.toContain("hover:"); const prompt = screen.getByText("$"); diff --git a/packages/kumo/src/components/empty/empty.tsx b/packages/kumo/src/components/empty/empty.tsx index 2d4bd47871..6b31e65458 100644 --- a/packages/kumo/src/components/empty/empty.tsx +++ b/packages/kumo/src/components/empty/empty.tsx @@ -128,7 +128,7 @@ export function Empty({ {commandLine && (
From 7d1af63120e9d2771da4541eafd61f85c8809f3b Mon Sep 17 00:00:00 2001 From: nanda Date: Tue, 15 Sep 2026 11:58:27 -0700 Subject: [PATCH 3/3] fix(empty): preserve title semantics without description --- packages/kumo/src/components/empty/empty.test.tsx | 1 + packages/kumo/src/components/empty/empty.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/kumo/src/components/empty/empty.test.tsx b/packages/kumo/src/components/empty/empty.test.tsx index a0661e7f22..b5b9e685a6 100644 --- a/packages/kumo/src/components/empty/empty.test.tsx +++ b/packages/kumo/src/components/empty/empty.test.tsx @@ -30,6 +30,7 @@ describe("Empty", () => { const title = screen.getByText("Nothing here"); + expect(title.tagName).toBe("H2"); expect(title.className).toContain("text-base/[inherit]"); expect(title.className).toContain("text-kumo-subtle"); expect(title.className).not.toContain("font-semibold"); diff --git a/packages/kumo/src/components/empty/empty.tsx b/packages/kumo/src/components/empty/empty.tsx index 6b31e65458..bbea8acdbb 100644 --- a/packages/kumo/src/components/empty/empty.tsx +++ b/packages/kumo/src/components/empty/empty.tsx @@ -109,7 +109,7 @@ export function Empty({ {title} ) : ( - + {title} )}