From cacc3f3374bb991a0689f7da2914f23d97476a98 Mon Sep 17 00:00:00 2001 From: Shubhdeep Chhabra Date: Sat, 19 Oct 2024 13:31:30 +0530 Subject: [PATCH 1/3] Added badge component --- apps/docs/src/examples/badge.module.css | 7 ++ apps/docs/src/examples/badge.tsx | 11 +++ apps/docs/src/routes/docs/core.tsx | 5 + .../src/routes/docs/core/components/badge.mdx | 94 +++++++++++++++++++ packages/core/dev/App.tsx | 7 +- packages/core/src/badge/badge-root.tsx | 46 +++++++++ packages/core/src/badge/badge.test.tsx | 33 +++++++ packages/core/src/badge/index.tsx | 17 ++++ packages/core/src/index.tsx | 1 + 9 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 apps/docs/src/examples/badge.module.css create mode 100644 apps/docs/src/examples/badge.tsx create mode 100644 apps/docs/src/routes/docs/core/components/badge.mdx create mode 100644 packages/core/src/badge/badge-root.tsx create mode 100644 packages/core/src/badge/badge.test.tsx create mode 100644 packages/core/src/badge/index.tsx diff --git a/apps/docs/src/examples/badge.module.css b/apps/docs/src/examples/badge.module.css new file mode 100644 index 00000000..99d579d0 --- /dev/null +++ b/apps/docs/src/examples/badge.module.css @@ -0,0 +1,7 @@ +.badge { + display: inline-block; + padding: 0.2em 0.4em; + background-color: hsl(201 96% 32%); + color: white; border-radius: 12px; + font-size: 0.875rem; +} \ No newline at end of file diff --git a/apps/docs/src/examples/badge.tsx b/apps/docs/src/examples/badge.tsx new file mode 100644 index 00000000..5d4afad8 --- /dev/null +++ b/apps/docs/src/examples/badge.tsx @@ -0,0 +1,11 @@ +import { Badge } from "@kobalte/core/badge"; + +import style from "./badge.module.css"; + +export function BasicExample() { + return ( + + 5 messages + + ); +} \ No newline at end of file diff --git a/apps/docs/src/routes/docs/core.tsx b/apps/docs/src/routes/docs/core.tsx index d4b1efb2..958ac966 100644 --- a/apps/docs/src/routes/docs/core.tsx +++ b/apps/docs/src/routes/docs/core.tsx @@ -49,6 +49,11 @@ const CORE_NAV_SECTIONS: NavSection[] = [ title: "Alert Dialog", href: "/docs/core/components/alert-dialog", }, + { + title: "Badge", + href: "/docs/core/components/badge", + status: "new", + }, { title: "Breadcrumbs", href: "/docs/core/components/breadcrumbs", diff --git a/apps/docs/src/routes/docs/core/components/badge.mdx b/apps/docs/src/routes/docs/core/components/badge.mdx new file mode 100644 index 00000000..91a4217d --- /dev/null +++ b/apps/docs/src/routes/docs/core/components/badge.mdx @@ -0,0 +1,94 @@ +import { Preview, TabsSnippets, Callout } from "../../../../components"; +import { BasicExample } from "../../../../examples/badge"; + +# Badge + +A `Badge` component is used to display small pieces of information or status indicators. + +## Import + +```ts +import { Badge } from "@kobalte/core/badge"; +// or +import { Root } from "@kobalte/core/badge"; +// or (deprecated) +import { Badge } from "@kobalte/core"; +``` + +## Features + +- Auto-populated ARIA labeling via the textValue prop for enhanced accessibility. +- Built-in ARIA support with role="status" to communicate dynamic updates. + +## Anatomy + +The badge consists of: + +- **Badge:** The root container for the badge that supports accessibility and content customization. + +```tsx +3 +``` + +## Example + + + + + + + + index.tsx + style.css + + {/* */} + + ```tsx + import { Badge } from "@kobalte/core/badge"; + import "./style.css"; + + function App() { + return ( + + 5 messages + + ); + } + ``` + + + + ```css + .badge { + display: inline-block; + padding: 0.2em 0.4em; + background-color: hsl(201 96% 32%); + color: white; border-radius: 12px; + font-size: 0.875rem; + } + ``` + + + {/* */} + + + +## API Reference + +### Badge + +`Badge` is equivalent to the `Root` import from `@kobalte/core/badge` (and deprecated `Badge.Root`). + +| Prop | Description | +| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| textValue | `string \| undefined`
The textValue prop is essential for accessibility. It auto-populates the aria-label attribute, allowing screen readers to interpret the badge’s content. | + +| Data attribute | Description | +| :------------- | :------------------------------------------------------------ | +| data-label | Present when textValue is passed or aria-label is passed as a prop. | + +## Rendered elements + +| Component | Default rendered element | +| :---------------- | :------------------------ | +| `Badge` | `span` | diff --git a/packages/core/dev/App.tsx b/packages/core/dev/App.tsx index bf49446a..b6ac7134 100644 --- a/packages/core/dev/App.tsx +++ b/packages/core/dev/App.tsx @@ -1,5 +1,10 @@ +import { Badge } from "../src/badge"; + export default function App() { return ( - <> + <> + aaa1123 + 11 + ); } diff --git a/packages/core/src/badge/badge-root.tsx b/packages/core/src/badge/badge-root.tsx new file mode 100644 index 00000000..f99e8f1d --- /dev/null +++ b/packages/core/src/badge/badge-root.tsx @@ -0,0 +1,46 @@ +/* + * Portions of this file are based on code from react-spectrum. + * Apache License Version 2.0, Copyright 2020 Adobe. + * + * Credits to the React Spectrum team: + * https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/badge/src/Badge.tsx + */ + +import { type ValidComponent, splitProps } from "solid-js"; +import { Polymorphic, type PolymorphicProps } from "../polymorphic"; + +export interface BadgeRootOptions { + /** + * Optional textValue for badge. + */ + textValue?: string; +} + +export interface BadgeRootCommonProps { + "aria-label"?: string; +} + +export interface BadgeRootRenderProps extends BadgeRootCommonProps {} + +export type BadgeRootProps< + T extends ValidComponent | HTMLElement = HTMLElement, +> = BadgeRootOptions & Partial; + +export function BadgeRoot( + props: PolymorphicProps>, +) { + const [local, others] = splitProps(props, ["textValue", "aria-label"]); + + const ariaLabel = () => local["aria-label"] || local.textValue; + + return ( + + as="span" + role="status" + aria-label={ariaLabel()} + {...others} + > + {others.children} + + ); +} diff --git a/packages/core/src/badge/badge.test.tsx b/packages/core/src/badge/badge.test.tsx new file mode 100644 index 00000000..e7a0e798 --- /dev/null +++ b/packages/core/src/badge/badge.test.tsx @@ -0,0 +1,33 @@ +import { render } from "@solidjs/testing-library"; +import * as Badge from "."; + +describe("Badge", () => { + it("badge with textValue", () => { + const { getByRole } = render(() => ( + Online + )); + + const badge = getByRole("status"); + expect(badge).toHaveTextContent("Online"); + }); + + it("badge with defined aria-label", () => { + const { getByText } = render(() => ( + + Online + + )); + + const badge = getByText("Online"); + expect(badge).toHaveAttribute("aria-label", "User is online"); + }); + + it("badge with default aria-labe as textValue", () => { + const { getByRole } = render(() => ( + Online + )); + + const badge = getByRole("status"); + expect(badge).toHaveAttribute("aria-label", "Online"); + }); +}); diff --git a/packages/core/src/badge/index.tsx b/packages/core/src/badge/index.tsx new file mode 100644 index 00000000..a67a51c4 --- /dev/null +++ b/packages/core/src/badge/index.tsx @@ -0,0 +1,17 @@ +import { + type BadgeRootCommonProps, + type BadgeRootOptions, + type BadgeRootProps, + type BadgeRootRenderProps, + BadgeRoot as Root, +} from "./badge-root"; + +export type { + BadgeRootOptions, + BadgeRootCommonProps, + BadgeRootRenderProps, + BadgeRootProps, +}; +export { Root }; + +export const Badge = Root; diff --git a/packages/core/src/index.tsx b/packages/core/src/index.tsx index 4a72a633..90f859c7 100644 --- a/packages/core/src/index.tsx +++ b/packages/core/src/index.tsx @@ -13,6 +13,7 @@ export * from "./toast/toaster"; export * as Accordion from "./accordion"; export * as Alert from "./alert"; export * as AlertDialog from "./alert-dialog"; +export * as Badge from "./badge"; export * as Breadcrumbs from "./breadcrumbs"; export * as Button from "./button"; //export * as Calendar from "./calendar"; From 5353ba2648b1711eda8a50ff9f45b9c960e0febc Mon Sep 17 00:00:00 2001 From: Shubhdeep Chhabra Date: Sat, 19 Oct 2024 22:27:45 +0530 Subject: [PATCH 2/3] fixed typo --- packages/core/src/badge/badge.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/badge/badge.test.tsx b/packages/core/src/badge/badge.test.tsx index e7a0e798..f9ffa4f0 100644 --- a/packages/core/src/badge/badge.test.tsx +++ b/packages/core/src/badge/badge.test.tsx @@ -22,7 +22,7 @@ describe("Badge", () => { expect(badge).toHaveAttribute("aria-label", "User is online"); }); - it("badge with default aria-labe as textValue", () => { + it("badge with default aria-label as textValue", () => { const { getByRole } = render(() => ( Online )); From 9e86352607562dc23775ceaacbddbdb801c3d516 Mon Sep 17 00:00:00 2001 From: Shubhdeep Chhabra Date: Tue, 22 Oct 2024 10:53:37 +0530 Subject: [PATCH 3/3] formatting fixed --- apps/docs/src/examples/badge.module.css | 15 ++++++------- apps/docs/src/examples/badge.tsx | 2 +- .../src/routes/docs/core/components/badge.mdx | 21 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/docs/src/examples/badge.module.css b/apps/docs/src/examples/badge.module.css index 99d579d0..663fb207 100644 --- a/apps/docs/src/examples/badge.module.css +++ b/apps/docs/src/examples/badge.module.css @@ -1,7 +1,8 @@ -.badge { - display: inline-block; - padding: 0.2em 0.4em; - background-color: hsl(201 96% 32%); - color: white; border-radius: 12px; - font-size: 0.875rem; -} \ No newline at end of file +.badge { + display: inline-block; + padding: 0.2em 0.4em; + background-color: hsl(201 96% 32%); + color: white; + border-radius: 12px; + font-size: 0.875rem; +} diff --git a/apps/docs/src/examples/badge.tsx b/apps/docs/src/examples/badge.tsx index 5d4afad8..5f9fc681 100644 --- a/apps/docs/src/examples/badge.tsx +++ b/apps/docs/src/examples/badge.tsx @@ -8,4 +8,4 @@ export function BasicExample() { 5 messages ); -} \ No newline at end of file +} diff --git a/apps/docs/src/routes/docs/core/components/badge.mdx b/apps/docs/src/routes/docs/core/components/badge.mdx index 91a4217d..4d227622 100644 --- a/apps/docs/src/routes/docs/core/components/badge.mdx +++ b/apps/docs/src/routes/docs/core/components/badge.mdx @@ -50,8 +50,8 @@ The badge consists of: function App() { return ( - 5 messages - + 5 messages + ); } ``` @@ -72,23 +72,22 @@ The badge consists of: {/* */} - ## API Reference ### Badge `Badge` is equivalent to the `Root` import from `@kobalte/core/badge` (and deprecated `Badge.Root`). -| Prop | Description | -| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| textValue | `string \| undefined`
The textValue prop is essential for accessibility. It auto-populates the aria-label attribute, allowing screen readers to interpret the badge’s content. | +| Prop | Description | +| :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| textValue | `string \| undefined`
The textValue prop is essential for accessibility. It auto-populates the aria-label attribute, allowing screen readers to interpret the badge’s content. | -| Data attribute | Description | -| :------------- | :------------------------------------------------------------ | +| Data attribute | Description | +| :------------- | :------------------------------------------------------------------ | | data-label | Present when textValue is passed or aria-label is passed as a prop. | ## Rendered elements -| Component | Default rendered element | -| :---------------- | :------------------------ | -| `Badge` | `span` | +| Component | Default rendered element | +| :-------- | :----------------------- | +| `Badge` | `span` |