From 90c90d9c99873ce306f13c2a55d4ce10d835b952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Lopes?= Date: Mon, 31 Aug 2026 16:09:15 -0300 Subject: [PATCH] feat(data-table): show an inbox icon on the default empty state Empty tables looked sparse with only a title. A semantic inbox icon fills the default EmptyState without changing standalone EmptyState. --- packages/core/src/Adapters/__tests__/icon.test.ts | 1 + packages/core/src/Adapters/icon.ts | 1 + packages/react/docs/components/DataTable.md | 2 +- packages/react/docs/examples/icon-fontawesome.ts | 2 ++ packages/react/docs/examples/icon-heroicons.ts | 2 ++ packages/react/docs/examples/icon-lucide.ts | 2 ++ packages/react/docs/examples/icon-phosphor.ts | 2 ++ packages/react/docs/examples/icon-tabler.ts | 2 ++ .../react/src/Components/DataTable/DataTable.tsx | 1 + .../Components/DataTable/__tests__/DataTable.cy.tsx | 7 +++++++ .../DataTable/__tests__/DataTable.test.tsx | 1 + packages/vue/docs/components/DataTable.md | 2 +- packages/vue/docs/examples/icon-fontawesome.ts | 2 ++ packages/vue/docs/examples/icon-heroicons.ts | 2 ++ packages/vue/docs/examples/icon-lucide.ts | 2 ++ packages/vue/docs/examples/icon-phosphor.ts | 2 ++ packages/vue/docs/examples/icon-tabler.ts | 2 ++ packages/vue/src/Components/DataTable/DataTable.vue | 1 + .../Components/DataTable/__tests__/DataTable.cy.ts | 12 ++++++++++++ .../Components/DataTable/__tests__/DataTable.test.ts | 1 + 20 files changed, 47 insertions(+), 2 deletions(-) diff --git a/packages/core/src/Adapters/__tests__/icon.test.ts b/packages/core/src/Adapters/__tests__/icon.test.ts index 79f6396d..059b0bd7 100644 --- a/packages/core/src/Adapters/__tests__/icon.test.ts +++ b/packages/core/src/Adapters/__tests__/icon.test.ts @@ -25,6 +25,7 @@ function createTestIconAdapter( describe("isSemanticIconName", () => { test("it should return true for default semantic names", () => { expect(isSemanticIconName("clear")).toBe(true); + expect(isSemanticIconName("inbox")).toBe(true); expect(isSemanticIconName("chevronUpDown")).toBe(true); }); diff --git a/packages/core/src/Adapters/icon.ts b/packages/core/src/Adapters/icon.ts index f60f993c..eaea5a49 100644 --- a/packages/core/src/Adapters/icon.ts +++ b/packages/core/src/Adapters/icon.ts @@ -24,6 +24,7 @@ export const SEMANTIC_ICON_NAMES = [ "clear", "clock", "error", + "inbox", "minus", "eyeOff", "filter", diff --git a/packages/react/docs/components/DataTable.md b/packages/react/docs/components/DataTable.md index 0b492e3e..498284b2 100644 --- a/packages/react/docs/components/DataTable.md +++ b/packages/react/docs/components/DataTable.md @@ -159,7 +159,7 @@ When `page` and `pageCount` (or `totalCount`) are set, DataTable does not sort o ### Empty, loading, and footer -Empty rows render `EmptyState` at the table `size`, with the i18n title `"No data"`. `slots.empty` replaces it. `loading` keeps the table visible. `loadingVariant="overlay"` (default) dims the table with a spin; `loadingVariant="bar"` dims the table and draws a progress line under the header. `slots.loading` replaces the indicator. `slots.footer` renders below the table, above pagination: +Empty rows render `EmptyState` at the table `size`, with the semantic `inbox` icon and the i18n title `"No data"`. `slots.empty` replaces it. `loading` keeps the table visible. `loadingVariant="overlay"` (default) dims the table with a spin; `loadingVariant="bar"` dims the table and draws a progress line under the header. `slots.loading` replaces the indicator. `slots.footer` renders below the table, above pagination: ```tsx (props: DataTableProps) {
{slots?.empty ?? ( diff --git a/packages/react/src/Components/DataTable/__tests__/DataTable.cy.tsx b/packages/react/src/Components/DataTable/__tests__/DataTable.cy.tsx index 88711aee..8479fdce 100644 --- a/packages/react/src/Components/DataTable/__tests__/DataTable.cy.tsx +++ b/packages/react/src/Components/DataTable/__tests__/DataTable.cy.tsx @@ -18,6 +18,13 @@ test("it should render a data table in the browser", () => { cy.contains("Ada Lovelace").should("be.visible"); }); +test("it should render the default empty state", () => { + cy.mount(); + + cy.get("svg").should("be.visible"); + cy.contains("No data").should("be.visible"); +}); + test("it should render the bordered variant", () => { cy.mount( { const { container } = render(); expect(screen.getByText("No data")).toBeTruthy(); + expect(container.querySelector("svg")).not.toBeNull(); expect(container.querySelector(".max-w-md")).not.toBeNull(); }); diff --git a/packages/vue/docs/components/DataTable.md b/packages/vue/docs/components/DataTable.md index f3ac546c..b1bfb840 100644 --- a/packages/vue/docs/components/DataTable.md +++ b/packages/vue/docs/components/DataTable.md @@ -141,7 +141,7 @@ When `page` and `page-count` (or `total-count`) are set, DataTable does not sort ### Empty, loading, and footer -Empty rows render `EmptyState` at the table `size`, with the i18n title `"No data"`. `#empty` replaces it. `loading` keeps the table visible. `loadingVariant="overlay"` (default) dims the table with a spin; `loadingVariant="bar"` dims the table and draws a progress line under the header. `#loading` replaces the indicator. `#footer` renders below the table, above pagination: +Empty rows render `EmptyState` at the table `size`, with the semantic `inbox` icon and the i18n title `"No data"`. `#empty` replaces it. `loading` keeps the table visible. `loadingVariant="overlay"` (default) dims the table with a spin; `loadingVariant="bar"` dims the table and draws a progress line under the header. `#loading` replaces the indicator. `#footer` renders below the table, above pagination: ```vue diff --git a/packages/vue/docs/examples/icon-fontawesome.ts b/packages/vue/docs/examples/icon-fontawesome.ts index 7f769bce..7842bc90 100644 --- a/packages/vue/docs/examples/icon-fontawesome.ts +++ b/packages/vue/docs/examples/icon-fontawesome.ts @@ -26,6 +26,7 @@ import { faEye, faEyeSlash, faFilter, + faInbox, faMagnifyingGlass, faMinus, faPalette, @@ -94,6 +95,7 @@ const icons = { bell: faBell, user: faUser, plus: faPlus, + inbox: faInbox, clear: faXmark, check: faCheck, clock: faClock, diff --git a/packages/vue/docs/examples/icon-heroicons.ts b/packages/vue/docs/examples/icon-heroicons.ts index 33d19f4e..9060d7a0 100644 --- a/packages/vue/docs/examples/icon-heroicons.ts +++ b/packages/vue/docs/examples/icon-heroicons.ts @@ -24,6 +24,7 @@ import { EyeIcon, EyeSlashIcon, FunnelIcon, + InboxIcon, InformationCircleIcon, MagnifyingGlassIcon, MinusIcon, @@ -44,6 +45,7 @@ const icons = { bell: BellIcon, user: UserIcon, plus: PlusIcon, + inbox: InboxIcon, clear: XMarkIcon, check: CheckIcon, clock: ClockIcon, diff --git a/packages/vue/docs/examples/icon-lucide.ts b/packages/vue/docs/examples/icon-lucide.ts index f6097626..45e25c64 100644 --- a/packages/vue/docs/examples/icon-lucide.ts +++ b/packages/vue/docs/examples/icon-lucide.ts @@ -23,6 +23,7 @@ import { Eye, EyeOff, Filter, + Inbox, Info, Loader2, Minus, @@ -48,6 +49,7 @@ const icons = { plus: Plus, check: Check, clock: Clock, + inbox: Inbox, minus: Minus, error: CircleX, eyeOff: EyeOff, diff --git a/packages/vue/docs/examples/icon-phosphor.ts b/packages/vue/docs/examples/icon-phosphor.ts index baea72a6..ef9da535 100644 --- a/packages/vue/docs/examples/icon-phosphor.ts +++ b/packages/vue/docs/examples/icon-phosphor.ts @@ -28,6 +28,7 @@ import { PhPlus, PhSidebar, PhSpinnerGap, + PhTray, PhUser, PhWarning, PhWarningCircle, @@ -46,6 +47,7 @@ const icons = { info: PhInfo, user: PhUser, plus: PhPlus, + inbox: PhTray, check: PhCheck, clock: PhClock, minus: PhMinus, diff --git a/packages/vue/docs/examples/icon-tabler.ts b/packages/vue/docs/examples/icon-tabler.ts index b05239d3..19dcd644 100644 --- a/packages/vue/docs/examples/icon-tabler.ts +++ b/packages/vue/docs/examples/icon-tabler.ts @@ -23,6 +23,7 @@ import { IconEye, IconEyeOff, IconFilter, + IconInbox, IconInfoCircle, IconLayoutSidebar, IconLoader2, @@ -45,6 +46,7 @@ const icons = { bell: IconBell, user: IconUser, plus: IconPlus, + inbox: IconInbox, check: IconCheck, clock: IconClock, minus: IconMinus, diff --git a/packages/vue/src/Components/DataTable/DataTable.vue b/packages/vue/src/Components/DataTable/DataTable.vue index 23bd8131..83026334 100644 --- a/packages/vue/src/Components/DataTable/DataTable.vue +++ b/packages/vue/src/Components/DataTable/DataTable.vue @@ -328,6 +328,7 @@ const DataTableChild = (childProps: { node?: VNodeChild }) => {
diff --git a/packages/vue/src/Components/DataTable/__tests__/DataTable.cy.ts b/packages/vue/src/Components/DataTable/__tests__/DataTable.cy.ts index a4f3a758..47ffde57 100644 --- a/packages/vue/src/Components/DataTable/__tests__/DataTable.cy.ts +++ b/packages/vue/src/Components/DataTable/__tests__/DataTable.cy.ts @@ -21,6 +21,18 @@ test("it should render a data table in the browser", () => { cy.contains("Ada Lovelace").should("be.visible"); }); +test("it should render the default empty state", () => { + cy.mount(DataTable, { + props: { + columns, + rows: [], + }, + }); + + cy.get("svg").should("be.visible"); + cy.contains("No data").should("be.visible"); +}); + test("it should render the bordered variant", () => { cy.mount(DataTable, { props: { diff --git a/packages/vue/src/Components/DataTable/__tests__/DataTable.test.ts b/packages/vue/src/Components/DataTable/__tests__/DataTable.test.ts index 2fe2f28c..5f1df0bf 100644 --- a/packages/vue/src/Components/DataTable/__tests__/DataTable.test.ts +++ b/packages/vue/src/Components/DataTable/__tests__/DataTable.test.ts @@ -278,6 +278,7 @@ test("it should render a default empty state", () => { }); expect(wrapper.text()).toContain("No data"); + expect(wrapper.find("svg").exists()).toBe(true); expect(wrapper.find(".max-w-md").exists()).toBe(true); });