@devalok/shilp-sutra 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +91 -0
- package/dist/_chunks/badge-group.js +75 -188
- package/dist/_chunks/badge-group.js.map +1 -1
- package/dist/_chunks/chat.js +244 -243
- package/dist/_chunks/chat.js.map +1 -1
- package/dist/_chunks/image-preview.js +71 -70
- package/dist/_chunks/image-preview.js.map +1 -1
- package/dist/_chunks/motion-preference.js +15 -0
- package/dist/_chunks/motion-preference.js.map +1 -0
- package/dist/_chunks/motion-provider.js +1 -1
- package/dist/_chunks/motion-provider.js.map +1 -1
- package/dist/_chunks/popover.js +50 -49
- package/dist/_chunks/popover.js.map +1 -1
- package/dist/_chunks/primitives-internal.js +29 -29
- package/dist/_chunks/primitives-internal.js.map +1 -1
- package/dist/_chunks/shared.js +48 -47
- package/dist/_chunks/shared.js.map +1 -1
- package/dist/_chunks/success.js +34 -34
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -1
- package/dist/ai/block-renderer.js +8 -8
- package/dist/ai/command-bar.js +65 -65
- package/dist/ai/command-bar.js.map +1 -1
- package/dist/ai/conversation.js +35 -35
- package/dist/ai/conversation.js.map +1 -1
- package/dist/ai/index.js +4 -4
- package/dist/composed/activity-feed.d.ts.map +1 -1
- package/dist/composed/activity-feed.js +108 -107
- package/dist/composed/activity-feed.js.map +1 -1
- package/dist/composed/command-palette.js +137 -137
- package/dist/composed/command-palette.js.map +1 -1
- package/dist/composed/content-card.js +1 -1
- package/dist/composed/content-card.js.map +1 -1
- package/dist/composed/date-picker/index.js +5 -5
- package/dist/composed/date-picker/index.js.map +1 -1
- package/dist/composed/empty-state.js +4 -4
- package/dist/composed/file-preview/image-preview.d.ts.map +1 -1
- package/dist/composed/file-preview/shared.d.ts.map +1 -1
- package/dist/composed/file-preview/video-preview.d.ts.map +1 -1
- package/dist/composed/file-preview.js +151 -150
- package/dist/composed/file-preview.js.map +1 -1
- package/dist/composed/filter-bar.d.ts.map +1 -1
- package/dist/composed/filter-bar.js +53 -52
- package/dist/composed/filter-bar.js.map +1 -1
- package/dist/composed/form-section.d.ts.map +1 -1
- package/dist/composed/form-section.js +38 -37
- package/dist/composed/form-section.js.map +1 -1
- package/dist/composed/master-detail.d.ts.map +1 -1
- package/dist/composed/master-detail.js +1 -1
- package/dist/composed/master-detail.js.map +1 -1
- package/dist/composed/multi-select-popover.d.ts.map +1 -1
- package/dist/composed/multi-select-popover.js +109 -108
- package/dist/composed/multi-select-popover.js.map +1 -1
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.js +467 -466
- package/dist/composed/rich-chat-input.js.map +1 -1
- package/dist/composed/rich-text-editor.js +3 -3
- package/dist/composed/rich-text-editor.js.map +1 -1
- package/dist/composed/schedule-view.js +2 -2
- package/dist/composed/schedule-view.js.map +1 -1
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js +29 -28
- package/dist/composed/status-badge.js.map +1 -1
- package/dist/motion/index.d.ts +1 -0
- package/dist/motion/index.d.ts.map +1 -1
- package/dist/motion/index.js +2 -15
- package/dist/motion/motion-preference.d.ts +36 -0
- package/dist/motion/motion-preference.d.ts.map +1 -0
- package/dist/motion/motion-provider.d.ts +2 -1
- package/dist/motion/motion-provider.d.ts.map +1 -1
- package/dist/motion/primitives-index.js +103 -102
- package/dist/motion/primitives-index.js.map +1 -1
- package/dist/motion/primitives.d.ts.map +1 -1
- package/dist/shell/bottom-navbar.js +19 -19
- package/dist/shell/bottom-navbar.js.map +1 -1
- package/dist/shell/index.d.ts +1 -1
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/notification-center.d.ts +17 -0
- package/dist/shell/notification-center.d.ts.map +1 -1
- package/dist/shell/notification-center.js +109 -104
- package/dist/shell/notification-center.js.map +1 -1
- package/dist/shell/notification-preferences.js +1 -1
- package/dist/shell/notification-preferences.js.map +1 -1
- package/dist/shell/top-bar.js +1 -1
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/tokens/index.css +1 -0
- package/dist/tokens/palettes.css +292 -0
- package/dist/tokens/semantic.css +72 -8
- package/dist/tokens/shilp-sutra.css +1 -0
- package/dist/tokens/utilities.css +10 -7
- package/dist/ui/accordion.d.ts.map +1 -1
- package/dist/ui/accordion.js +27 -26
- package/dist/ui/accordion.js.map +1 -1
- package/dist/ui/alert-dialog.d.ts.map +1 -1
- package/dist/ui/alert-dialog.js +60 -59
- package/dist/ui/alert-dialog.js.map +1 -1
- package/dist/ui/alert.d.ts.map +1 -1
- package/dist/ui/alert.js +55 -113
- package/dist/ui/alert.js.map +1 -1
- package/dist/ui/autocomplete.js +80 -80
- package/dist/ui/autocomplete.js.map +1 -1
- package/dist/ui/avatar.d.ts.map +1 -1
- package/dist/ui/avatar.js +69 -68
- package/dist/ui/avatar.js.map +1 -1
- package/dist/ui/badge-indicator.d.ts +4 -8
- package/dist/ui/badge-indicator.d.ts.map +1 -1
- package/dist/ui/badge-indicator.js +3 -8
- package/dist/ui/badge-indicator.js.map +1 -1
- package/dist/ui/badge.d.ts +8 -1
- package/dist/ui/badge.d.ts.map +1 -1
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +42 -40
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/button-group.d.ts.map +1 -1
- package/dist/ui/button-group.js +3 -23
- package/dist/ui/button-group.js.map +1 -1
- package/dist/ui/button.d.ts +10 -1
- package/dist/ui/button.d.ts.map +1 -1
- package/dist/ui/button.js +79 -212
- package/dist/ui/button.js.map +1 -1
- package/dist/ui/card.d.ts.map +1 -1
- package/dist/ui/card.js +75 -72
- package/dist/ui/card.js.map +1 -1
- package/dist/ui/charts/radar-chart.d.ts.map +1 -1
- package/dist/ui/charts/radar-chart.js +1 -1
- package/dist/ui/charts/radar-chart.js.map +1 -1
- package/dist/ui/chat/message-list.d.ts.map +1 -1
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/typing-indicator.d.ts.map +1 -1
- package/dist/ui/code.js +1 -1
- package/dist/ui/code.js.map +1 -1
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +151 -150
- package/dist/ui/color-input.js.map +1 -1
- package/dist/ui/combobox.d.ts +14 -0
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +152 -148
- package/dist/ui/combobox.js.map +1 -1
- package/dist/ui/context-menu.d.ts.map +1 -1
- package/dist/ui/context-menu.js +70 -69
- package/dist/ui/context-menu.js.map +1 -1
- package/dist/ui/data-table-body.js +2 -2
- package/dist/ui/data-table-body.js.map +1 -1
- package/dist/ui/data-table-context.js +2 -2
- package/dist/ui/data-table-context.js.map +1 -1
- package/dist/ui/data-table-header.d.ts.map +1 -1
- package/dist/ui/data-table-header.js +41 -40
- package/dist/ui/data-table-header.js.map +1 -1
- package/dist/ui/data-table-pagination.js +2 -2
- package/dist/ui/data-table-pagination.js.map +1 -1
- package/dist/ui/dialog.d.ts.map +1 -1
- package/dist/ui/dialog.js +61 -60
- package/dist/ui/dialog.js.map +1 -1
- package/dist/ui/dot.d.ts.map +1 -1
- package/dist/ui/dot.js +10 -41
- package/dist/ui/dot.js.map +1 -1
- package/dist/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/ui/dropdown-menu.js +79 -78
- package/dist/ui/dropdown-menu.js.map +1 -1
- package/dist/ui/file-upload.d.ts.map +1 -1
- package/dist/ui/file-upload.js +116 -115
- package/dist/ui/file-upload.js.map +1 -1
- package/dist/ui/form.d.ts.map +1 -1
- package/dist/ui/form.js +27 -26
- package/dist/ui/form.js.map +1 -1
- package/dist/ui/hover-card.d.ts.map +1 -1
- package/dist/ui/hover-card.js +26 -25
- package/dist/ui/hover-card.js.map +1 -1
- package/dist/ui/icon.js +7 -7
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +3 -3
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/input.js +1 -1
- package/dist/ui/input.js.map +1 -1
- package/dist/ui/menubar.d.ts.map +1 -1
- package/dist/ui/menubar.js +73 -72
- package/dist/ui/menubar.js.map +1 -1
- package/dist/ui/navigation-menu.d.ts.map +1 -1
- package/dist/ui/navigation-menu.js +80 -79
- package/dist/ui/navigation-menu.js.map +1 -1
- package/dist/ui/popover.d.ts.map +1 -1
- package/dist/ui/progress.d.ts.map +1 -1
- package/dist/ui/progress.js +72 -68
- package/dist/ui/progress.js.map +1 -1
- package/dist/ui/radio.d.ts.map +1 -1
- package/dist/ui/radio.js +32 -31
- package/dist/ui/radio.js.map +1 -1
- package/dist/ui/search-input.d.ts.map +1 -1
- package/dist/ui/search-input.js +28 -27
- package/dist/ui/search-input.js.map +1 -1
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +64 -63
- package/dist/ui/select.js.map +1 -1
- package/dist/ui/sidebar.d.ts.map +1 -1
- package/dist/ui/sidebar.js +4 -4
- package/dist/ui/sidebar.js.map +1 -1
- package/dist/ui/slider.d.ts +63 -9
- package/dist/ui/slider.d.ts.map +1 -1
- package/dist/ui/slider.js +74 -32
- package/dist/ui/slider.js.map +1 -1
- package/dist/ui/split-button.d.ts +8 -2
- package/dist/ui/split-button.d.ts.map +1 -1
- package/dist/ui/split-button.js +49 -95
- package/dist/ui/split-button.js.map +1 -1
- package/dist/ui/stat-card.d.ts.map +1 -1
- package/dist/ui/stat-card.js +89 -88
- package/dist/ui/stat-card.js.map +1 -1
- package/dist/ui/stat-flash.js +16 -16
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +63 -62
- package/dist/ui/stepper.js.map +1 -1
- package/dist/ui/table.js +3 -3
- package/dist/ui/table.js.map +1 -1
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +67 -66
- package/dist/ui/tabs.js.map +1 -1
- package/dist/ui/textarea.js +1 -1
- package/dist/ui/textarea.js.map +1 -1
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +195 -194
- package/dist/ui/toast.js.map +1 -1
- package/dist/ui/toggle.d.ts.map +1 -1
- package/dist/ui/toggle.js +24 -22
- package/dist/ui/toggle.js.map +1 -1
- package/dist/ui/tooltip.d.ts.map +1 -1
- package/dist/ui/tooltip.js +37 -36
- package/dist/ui/tooltip.js.map +1 -1
- package/dist/ui/tree-view/tree-item.d.ts.map +1 -1
- package/docs/recipes/customize-brand.md +58 -0
- package/docs/recipes/install-astro.md +1 -1
- package/docs/recipes/install-next-app-router.md +1 -1
- package/docs/recipes/install-next-pages.md +22 -1
- package/docs/recipes/install-remix.md +1 -1
- package/docs/recipes/install-tanstack-start.md +1 -1
- package/docs/recipes/install-vite.md +2 -1
- package/docs/recipes/server-components.md +7 -4
- package/docs/recipes/troubleshoot.md +1 -0
- package/llms.txt +1 -1
- package/mcp-manifest.json +9 -4
- package/package.json +3 -2
- package/skill/SKILL.md +1 -1
- package/skill/references/components.md +1 -1
- package/skill/references/customize-brand.md +58 -0
- package/skill/references/server-components.md +7 -4
- package/skill/references/setup-astro.md +1 -1
- package/skill/references/setup-next-app-router.md +1 -1
- package/skill/references/setup-next-pages.md +22 -1
- package/skill/references/setup-remix.md +1 -1
- package/skill/references/setup-tanstack-start.md +1 -1
- package/skill/references/setup-vite.md +2 -1
- package/skill/references/troubleshoot.md +1 -0
- package/dist/motion/check-motion-provider.d.ts +0 -2
- package/dist/motion/check-motion-provider.d.ts.map +0 -1
- package/dist/motion/index.js.map +0 -1
package/MIGRATION.md
CHANGED
|
@@ -4,6 +4,97 @@ This page indexes all breaking changes across `@devalok/shilp-sutra` versions. F
|
|
|
4
4
|
|
|
5
5
|
> **Upgrading from < 0.36?** Start here, then read each intermediate version section. Breaking changes stack — skipping versions means stacking migrations.
|
|
6
6
|
|
|
7
|
+
## v0.59.0 — additive (no migration required)
|
|
8
|
+
|
|
9
|
+
Nothing breaks at the TypeScript level; this release is additive.
|
|
10
|
+
|
|
11
|
+
> Auto-stubbed by `version-packages` so the release audit's MIGRATION-section gate can't block. If any behavioral or visual change needs consumer action, replace this stub with the specifics on the Version Packages PR before publishing.
|
|
12
|
+
|
|
13
|
+
## v0.58.0 — nothing errors, several things look different
|
|
14
|
+
|
|
15
|
+
No API is removed and no prop type narrows, so `tsc` and your build stay green
|
|
16
|
+
on upgrade day. The reason this section exists anyway is that a number of
|
|
17
|
+
components **change appearance**, and two of them start rendering something that
|
|
18
|
+
previously rendered nothing at all. If you screenshot-test, expect diffs.
|
|
19
|
+
|
|
20
|
+
### Two features that were silently no-ops now work
|
|
21
|
+
|
|
22
|
+
Both were painted in a colour identical to their own background in light mode,
|
|
23
|
+
so they emitted markup and showed nothing:
|
|
24
|
+
|
|
25
|
+
| | before | after |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `<Table striped>` | 1.00:1 — no stripes rendered at all | visible zebra |
|
|
28
|
+
| `<Progress>` groove | 1.00:1 — no track behind the bar | visible track |
|
|
29
|
+
|
|
30
|
+
If you worked around either of these — a local `nth-child` stripe rule, a
|
|
31
|
+
wrapper drawing a track behind Progress — remove the workaround, or you will now
|
|
32
|
+
have two.
|
|
33
|
+
|
|
34
|
+
### Selected rows are more prominent, and correctly so
|
|
35
|
+
|
|
36
|
+
Selection fills moved from accent step 2 to step 4. In dark, steps 1–2 sit
|
|
37
|
+
*below* the panel in lightness while the grey hover sits above it, so a selected
|
|
38
|
+
row receded exactly as a hovered row advanced: the sidebar measured 1.03:1
|
|
39
|
+
selected against 1.30:1 hovered. The wrong row was louder, in the opposite
|
|
40
|
+
direction.
|
|
41
|
+
|
|
42
|
+
Affects Sidebar, MasterDetail, MultiSelectPopover, NotificationCenter, Combobox,
|
|
43
|
+
Autocomplete, Table, BottomNavbar, ScheduleView, TreeView and Toggle. Nothing to
|
|
44
|
+
do unless you override those fills yourself, in which case re-check them against
|
|
45
|
+
your hover state.
|
|
46
|
+
|
|
47
|
+
### `border-card-strong` is now actually stronger than `border-card`
|
|
48
|
+
|
|
49
|
+
They resolved to the same value. Both pointed at `--color-surface-border`, so
|
|
50
|
+
roughly thirteen call sites asking for the heavier edge silently got the faint
|
|
51
|
+
one. `border-card-strong` now resolves to `--color-surface-border-strong`:
|
|
52
|
+
|
|
53
|
+
| | light | dark |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| before | 1.22:1 | 1.33:1 |
|
|
56
|
+
| after | 1.38:1 | 1.63:1 |
|
|
57
|
+
|
|
58
|
+
If you picked `border-card-strong` *because* it looked identical to
|
|
59
|
+
`border-card`, switch those to `border-card`.
|
|
60
|
+
|
|
61
|
+
### The Sidebar's divider was a full-contrast line, and is now a hairline
|
|
62
|
+
|
|
63
|
+
`Sidebar` had a `border-r` with no colour utility. Tailwind 4 leaves an
|
|
64
|
+
uncoloured border at `currentColor` rather than defaulting it to grey, so it
|
|
65
|
+
inherited the text colour and drew at **12.69:1 in light and 15.44:1 in dark**
|
|
66
|
+
where `surface-border` (1.23:1 / 1.47:1) was intended.
|
|
67
|
+
|
|
68
|
+
This is the one place an upgrade might *remove* something you had come to rely
|
|
69
|
+
on. If you overrode the sidebar edge downstream to tame it, drop the override.
|
|
70
|
+
|
|
71
|
+
### Raised surfaces gain an edge in dark
|
|
72
|
+
|
|
73
|
+
`--shadow-edge-ring` is deliberately swapped to a light ring under `.dark`,
|
|
74
|
+
because a dark ring cannot be seen on a dark ground. Only the larger shadows
|
|
75
|
+
consumed it, so `shadow-raised` and `shadow-raised-hover` kept a near-black ring
|
|
76
|
+
measuring 1.01:1 — no edge at all. `Sidebar variant="floating"`, `Card
|
|
77
|
+
variant="elevated"`, `Menubar` and the keyboard caps had no visible boundary in
|
|
78
|
+
dark. They now measure 1.21:1, still quieter than a floating overlay's 1.42:1.
|
|
79
|
+
|
|
80
|
+
### Colour is a role now, not a variant
|
|
81
|
+
|
|
82
|
+
The palette layer landed in the same release. Twelve components stopped encoding
|
|
83
|
+
colour as a cross-product of variants and now resolve it through
|
|
84
|
+
`[data-palette]`. Existing `color="…"` values all still type-check — the union
|
|
85
|
+
widened rather than narrowed — and the visual result is unchanged for the six
|
|
86
|
+
built-in palettes. The gain is that a colour we do not ship can now be
|
|
87
|
+
registered in CSS.
|
|
88
|
+
|
|
89
|
+
### Also in this release
|
|
90
|
+
|
|
91
|
+
Segmented control and Tabs: the selected pill was *darker* than the groove it
|
|
92
|
+
sat in, in dark (1.028:1, inverted). Read-only Input and Textarea, DataTable
|
|
93
|
+
pinned columns and expanded rows, code blocks in RichTextEditor, ContentCard's
|
|
94
|
+
default variant and AI message bubbles all stopped painting themselves in their
|
|
95
|
+
own background colour. Full measurements in
|
|
96
|
+
`docs/audits/2026-08-28-surface-model-audit.md`.
|
|
97
|
+
|
|
7
98
|
## v0.57.0 — one token removed, one renamed, and a colour change you will see
|
|
8
99
|
|
|
9
100
|
The surface model was rebuilt. Almost all of it is aliased, so `tsc` and your
|
|
@@ -1,142 +1,28 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Slot as e } from "./primitives-internal.js";
|
|
3
3
|
import { durations as t, springs as n } from "../ui/lib/motion.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
4
|
+
import { MotionPreference as r } from "./motion-preference.js";
|
|
5
|
+
import { cn as i } from "../ui/lib/utils.js";
|
|
6
|
+
import { Icon as a } from "../ui/icon.js";
|
|
7
|
+
import { Dot as o } from "../ui/dot.js";
|
|
8
|
+
import { normalizeIcon as s } from "./normalize-icon.js";
|
|
9
|
+
import { BadgeIndicator as c } from "../ui/badge-indicator.js";
|
|
10
|
+
import * as l from "react";
|
|
11
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
12
|
+
import { IconCheck as f, IconX as p } from "@tabler/icons-react";
|
|
13
|
+
import { AnimatePresence as m, motion as h } from "framer-motion";
|
|
14
|
+
import { cva as g } from "class-variance-authority";
|
|
14
15
|
//#region src/ui/badge.tsx
|
|
15
|
-
var g = {
|
|
16
|
-
default: {
|
|
17
|
-
bg: "bg-surface-panel-hover",
|
|
18
|
-
softBg: "bg-surface-panel-hover",
|
|
19
|
-
fg: "text-surface-fg-muted",
|
|
20
|
-
border: "border-surface-border-strong",
|
|
21
|
-
solid: "bg-neutral-5",
|
|
22
|
-
solidFg: "text-surface-fg"
|
|
23
|
-
},
|
|
24
|
-
accent: {
|
|
25
|
-
bg: "bg-accent-2",
|
|
26
|
-
softBg: "bg-accent-3",
|
|
27
|
-
fg: "text-accent-11",
|
|
28
|
-
border: "border-accent-4",
|
|
29
|
-
solid: "bg-accent-9",
|
|
30
|
-
solidFg: "text-accent-fg"
|
|
31
|
-
},
|
|
32
|
-
error: {
|
|
33
|
-
bg: "bg-error-2",
|
|
34
|
-
softBg: "bg-error-3",
|
|
35
|
-
fg: "text-error-11",
|
|
36
|
-
border: "border-error-4",
|
|
37
|
-
solid: "bg-error-9",
|
|
38
|
-
solidFg: "text-error-fg"
|
|
39
|
-
},
|
|
40
|
-
success: {
|
|
41
|
-
bg: "bg-success-2",
|
|
42
|
-
softBg: "bg-success-3",
|
|
43
|
-
fg: "text-success-11",
|
|
44
|
-
border: "border-success-4",
|
|
45
|
-
solid: "bg-success-9",
|
|
46
|
-
solidFg: "text-success-fg"
|
|
47
|
-
},
|
|
48
|
-
warning: {
|
|
49
|
-
bg: "bg-warning-2",
|
|
50
|
-
softBg: "bg-warning-3",
|
|
51
|
-
fg: "text-warning-11",
|
|
52
|
-
border: "border-warning-4",
|
|
53
|
-
solid: "bg-warning-9",
|
|
54
|
-
solidFg: "text-warning-fg"
|
|
55
|
-
},
|
|
56
|
-
info: {
|
|
57
|
-
bg: "bg-info-2",
|
|
58
|
-
softBg: "bg-info-3",
|
|
59
|
-
fg: "text-info-11",
|
|
60
|
-
border: "border-info-4",
|
|
61
|
-
solid: "bg-info-9",
|
|
62
|
-
solidFg: "text-info-fg"
|
|
63
|
-
},
|
|
64
|
-
neutral: {
|
|
65
|
-
bg: "bg-surface-panel-hover",
|
|
66
|
-
softBg: "bg-surface-panel-hover",
|
|
67
|
-
fg: "text-surface-fg-muted",
|
|
68
|
-
border: "border-surface-border-strong",
|
|
69
|
-
solid: "bg-neutral-5",
|
|
70
|
-
solidFg: "text-surface-fg"
|
|
71
|
-
},
|
|
72
|
-
teal: {
|
|
73
|
-
bg: "bg-category-teal-2",
|
|
74
|
-
softBg: "bg-category-teal-3",
|
|
75
|
-
fg: "text-category-teal-11",
|
|
76
|
-
border: "border-category-teal-4",
|
|
77
|
-
solid: "bg-category-teal-9",
|
|
78
|
-
solidFg: "text-category-fg"
|
|
79
|
-
},
|
|
80
|
-
amber: {
|
|
81
|
-
bg: "bg-category-amber-2",
|
|
82
|
-
softBg: "bg-category-amber-3",
|
|
83
|
-
fg: "text-category-amber-11",
|
|
84
|
-
border: "border-category-amber-4",
|
|
85
|
-
solid: "bg-category-amber-9",
|
|
86
|
-
solidFg: "text-category-fg"
|
|
87
|
-
},
|
|
88
|
-
slate: {
|
|
89
|
-
bg: "bg-category-slate-2",
|
|
90
|
-
softBg: "bg-category-slate-3",
|
|
91
|
-
fg: "text-category-slate-11",
|
|
92
|
-
border: "border-category-slate-4",
|
|
93
|
-
solid: "bg-category-slate-9",
|
|
94
|
-
solidFg: "text-category-fg"
|
|
95
|
-
},
|
|
96
|
-
indigo: {
|
|
97
|
-
bg: "bg-category-indigo-2",
|
|
98
|
-
softBg: "bg-category-indigo-3",
|
|
99
|
-
fg: "text-category-indigo-11",
|
|
100
|
-
border: "border-category-indigo-4",
|
|
101
|
-
solid: "bg-category-indigo-9",
|
|
102
|
-
solidFg: "text-category-fg"
|
|
103
|
-
},
|
|
104
|
-
cyan: {
|
|
105
|
-
bg: "bg-category-cyan-2",
|
|
106
|
-
softBg: "bg-category-cyan-3",
|
|
107
|
-
fg: "text-category-cyan-11",
|
|
108
|
-
border: "border-category-cyan-4",
|
|
109
|
-
solid: "bg-category-cyan-9",
|
|
110
|
-
solidFg: "text-category-fg"
|
|
111
|
-
},
|
|
112
|
-
orange: {
|
|
113
|
-
bg: "bg-category-orange-2",
|
|
114
|
-
softBg: "bg-category-orange-3",
|
|
115
|
-
fg: "text-category-orange-11",
|
|
116
|
-
border: "border-category-orange-4",
|
|
117
|
-
solid: "bg-category-orange-9",
|
|
118
|
-
solidFg: "text-category-fg"
|
|
119
|
-
},
|
|
120
|
-
emerald: {
|
|
121
|
-
bg: "bg-category-emerald-2",
|
|
122
|
-
softBg: "bg-category-emerald-3",
|
|
123
|
-
fg: "text-category-emerald-11",
|
|
124
|
-
border: "border-category-emerald-4",
|
|
125
|
-
solid: "bg-category-emerald-9",
|
|
126
|
-
solidFg: "text-category-fg"
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
16
|
function _(e, t) {
|
|
130
17
|
if (t === "custom") return "";
|
|
131
|
-
let n = g[t];
|
|
132
18
|
switch (e) {
|
|
133
|
-
case "subtle": return
|
|
134
|
-
case "solid": return
|
|
135
|
-
case "outline": return
|
|
136
|
-
case "soft": return
|
|
19
|
+
case "subtle": return "bg-palette-subtle text-palette-text border-palette-border";
|
|
20
|
+
case "solid": return "bg-palette-solid text-palette-fg border-transparent";
|
|
21
|
+
case "outline": return "bg-transparent text-palette-text border-palette-border";
|
|
22
|
+
case "soft": return "bg-palette-soft text-palette-text border-transparent";
|
|
137
23
|
}
|
|
138
24
|
}
|
|
139
|
-
var v =
|
|
25
|
+
var v = g("relative inline-flex items-center rounded-pill font-sans font-medium overflow-hidden isolate transition-[color,background-color,border-color,padding] duration-fast-02 ease-productive-standard select-none [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]", {
|
|
140
26
|
variants: {
|
|
141
27
|
variant: {
|
|
142
28
|
subtle: "border",
|
|
@@ -170,67 +56,68 @@ var v = h("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
170
56
|
sm: "pr-ds-02",
|
|
171
57
|
md: "pr-ds-02",
|
|
172
58
|
lg: "pr-ds-02b"
|
|
173
|
-
}, S =
|
|
174
|
-
let
|
|
175
|
-
...
|
|
59
|
+
}, S = l.forwardRef(({ className: c, variant: l, color: g, size: S, asChild: C, startIcon: w, endIcon: T, dot: E, dotPulse: D, onDismiss: O, onClick: k, selected: A, disabled: j, maxWidth: M, truncate: N, circle: P, children: F, style: I, ...L }, R) => {
|
|
60
|
+
let z = l ?? "subtle", B = g ?? "default", V = S ?? "md", H = C ? e : k && O ? "div" : k ? "button" : "span", U = B === "custom" ? {
|
|
61
|
+
...z === "subtle" && {
|
|
176
62
|
backgroundColor: "color-mix(in oklch, var(--badge-color) 15%, transparent)",
|
|
177
63
|
color: "var(--badge-color)",
|
|
178
64
|
borderColor: "color-mix(in oklch, var(--badge-color) 40%, transparent)"
|
|
179
65
|
},
|
|
180
|
-
...
|
|
66
|
+
...z === "solid" && {
|
|
181
67
|
backgroundColor: "var(--badge-color)",
|
|
182
68
|
color: "var(--badge-fg-color, white)",
|
|
183
69
|
borderColor: "transparent"
|
|
184
70
|
},
|
|
185
|
-
...
|
|
71
|
+
...z === "outline" && {
|
|
186
72
|
backgroundColor: "transparent",
|
|
187
73
|
color: "var(--badge-color)",
|
|
188
74
|
borderColor: "color-mix(in oklch, var(--badge-color) 50%, transparent)"
|
|
189
75
|
},
|
|
190
|
-
...
|
|
76
|
+
...z === "soft" && {
|
|
191
77
|
backgroundColor: "color-mix(in oklch, var(--badge-color) 12%, transparent)",
|
|
192
78
|
color: "var(--badge-color)",
|
|
193
79
|
borderColor: "transparent"
|
|
194
80
|
}
|
|
195
|
-
} : void 0,
|
|
196
|
-
(e.key === "Enter" || e.key === " ") && (e.preventDefault(),
|
|
197
|
-
} :
|
|
198
|
-
return /* @__PURE__ */ u(
|
|
199
|
-
ref:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
81
|
+
} : void 0, W = k && O ? (e) => {
|
|
82
|
+
(e.key === "Enter" || e.key === " ") && (e.preventDefault(), j || k(e)), L.onKeyDown?.(e);
|
|
83
|
+
} : L.onKeyDown, G = !!(E || w || k && A && !w && !E), K = !!(O || T);
|
|
84
|
+
return /* @__PURE__ */ u(r, { children: /* @__PURE__ */ d(H, {
|
|
85
|
+
ref: R,
|
|
86
|
+
"data-palette": B === "custom" ? void 0 : B,
|
|
87
|
+
className: i(v({
|
|
88
|
+
variant: z,
|
|
89
|
+
size: V
|
|
90
|
+
}), _(z, B), G && b[V], K && x[V], k && "cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]", A && "ring-1 ring-current/20 transition-shadow duration-fast-02", j && "opacity-action-disabled pointer-events-none saturate-[0.3]", P && "justify-center px-0 aspect-square", c),
|
|
204
91
|
style: {
|
|
205
|
-
...
|
|
206
|
-
...
|
|
207
|
-
...
|
|
92
|
+
...I,
|
|
93
|
+
...U,
|
|
94
|
+
...M ? { maxWidth: M } : void 0
|
|
208
95
|
},
|
|
209
|
-
onClick:
|
|
210
|
-
onKeyDown:
|
|
211
|
-
...
|
|
212
|
-
...
|
|
213
|
-
...
|
|
96
|
+
onClick: j ? void 0 : k,
|
|
97
|
+
onKeyDown: W,
|
|
98
|
+
...H === "button" && { type: "button" },
|
|
99
|
+
...H === "button" && j ? { disabled: !0 } : {},
|
|
100
|
+
...H === "div" && k ? {
|
|
214
101
|
role: "button",
|
|
215
102
|
tabIndex: 0
|
|
216
103
|
} : {},
|
|
217
|
-
...
|
|
104
|
+
...L,
|
|
218
105
|
children: [
|
|
219
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ u(m, { children: E && /* @__PURE__ */ u(h.span, {
|
|
220
107
|
initial: { scale: 0 },
|
|
221
108
|
animate: { scale: 1 },
|
|
222
109
|
exit: { scale: 0 },
|
|
223
110
|
transition: n.snappy,
|
|
224
111
|
className: "inline-flex shrink-0",
|
|
225
|
-
children: /* @__PURE__ */
|
|
112
|
+
children: /* @__PURE__ */ u(o, {
|
|
226
113
|
color: "current",
|
|
227
114
|
size: "sm",
|
|
228
|
-
pulse:
|
|
115
|
+
pulse: D
|
|
229
116
|
})
|
|
230
117
|
}, "dot") }),
|
|
231
|
-
|
|
118
|
+
k && !w && !E && /* @__PURE__ */ u(h.span, {
|
|
232
119
|
initial: !1,
|
|
233
|
-
animate:
|
|
120
|
+
animate: A ? {
|
|
234
121
|
opacity: 1,
|
|
235
122
|
scale: 1,
|
|
236
123
|
width: "auto",
|
|
@@ -252,60 +139,60 @@ var v = h("relative inline-flex items-center rounded-pill font-sans font-medium
|
|
|
252
139
|
]
|
|
253
140
|
},
|
|
254
141
|
className: "inline-flex shrink-0 overflow-hidden",
|
|
255
|
-
"aria-hidden": !
|
|
256
|
-
children: /* @__PURE__ */
|
|
257
|
-
icon:
|
|
142
|
+
"aria-hidden": !A,
|
|
143
|
+
children: /* @__PURE__ */ u(a, {
|
|
144
|
+
icon: f,
|
|
258
145
|
size: "xs"
|
|
259
146
|
})
|
|
260
147
|
}),
|
|
261
|
-
|
|
262
|
-
className:
|
|
263
|
-
children:
|
|
148
|
+
w && /* @__PURE__ */ u("span", {
|
|
149
|
+
className: i("shrink-0", y[V]),
|
|
150
|
+
children: s(w)
|
|
264
151
|
}),
|
|
265
|
-
|
|
152
|
+
N || M ? /* @__PURE__ */ u("span", {
|
|
266
153
|
className: "truncate",
|
|
267
|
-
title: typeof
|
|
268
|
-
children:
|
|
269
|
-
}) :
|
|
270
|
-
|
|
271
|
-
className:
|
|
272
|
-
children:
|
|
154
|
+
title: typeof F == "string" ? F : void 0,
|
|
155
|
+
children: F
|
|
156
|
+
}) : F,
|
|
157
|
+
T && /* @__PURE__ */ u("span", {
|
|
158
|
+
className: i("shrink-0", y[V]),
|
|
159
|
+
children: s(T)
|
|
273
160
|
}),
|
|
274
|
-
|
|
161
|
+
O && /* @__PURE__ */ u("button", {
|
|
275
162
|
type: "button",
|
|
276
163
|
onClick: (e) => {
|
|
277
|
-
e.stopPropagation(),
|
|
164
|
+
e.stopPropagation(), O();
|
|
278
165
|
},
|
|
279
|
-
className:
|
|
280
|
-
"aria-label": `Remove ${typeof
|
|
281
|
-
children: /* @__PURE__ */
|
|
282
|
-
icon:
|
|
166
|
+
className: i("shrink-0 rounded-pill text-current/60 hover:text-current hover:bg-current/10 transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-accent-9", V === "xs" ? "p-0 -mr-0.5 min-w-ds-05 min-h-ds-05" : "p-px"),
|
|
167
|
+
"aria-label": `Remove ${typeof F == "string" ? F : ""}`.trim() || "Remove",
|
|
168
|
+
children: /* @__PURE__ */ u(a, {
|
|
169
|
+
icon: p,
|
|
283
170
|
size: "xs"
|
|
284
171
|
})
|
|
285
172
|
})
|
|
286
173
|
]
|
|
287
|
-
});
|
|
174
|
+
}) });
|
|
288
175
|
});
|
|
289
176
|
S.displayName = "Badge";
|
|
290
177
|
var C = Object.assign(S, {
|
|
291
|
-
Indicator:
|
|
178
|
+
Indicator: c,
|
|
292
179
|
Group: T
|
|
293
180
|
}), w = {
|
|
294
181
|
tight: "gap-1",
|
|
295
182
|
default: "gap-1.5",
|
|
296
183
|
loose: "gap-2"
|
|
297
|
-
}, T =
|
|
298
|
-
let
|
|
299
|
-
return /* @__PURE__ */
|
|
300
|
-
ref:
|
|
301
|
-
className:
|
|
184
|
+
}, T = l.forwardRef(function({ max: e, gap: t = "default", size: n, onOverflowClick: r, className: a, children: o, ...s }, c) {
|
|
185
|
+
let u = l.Children.toArray(o), f = u.length, p = e !== void 0 && f > e, m = p ? u.slice(0, e) : u, h = p ? f - e : 0;
|
|
186
|
+
return /* @__PURE__ */ d("div", {
|
|
187
|
+
ref: c,
|
|
188
|
+
className: i("flex flex-wrap items-center", w[t], a),
|
|
302
189
|
...s,
|
|
303
|
-
children: [m, p && /* @__PURE__ */
|
|
190
|
+
children: [m, p && /* @__PURE__ */ d(C, {
|
|
304
191
|
variant: "outline",
|
|
305
192
|
color: "neutral",
|
|
306
193
|
size: n ?? "sm",
|
|
307
|
-
onClick:
|
|
308
|
-
"aria-label":
|
|
194
|
+
onClick: r,
|
|
195
|
+
"aria-label": r ? `Show ${h} more` : void 0,
|
|
309
196
|
children: ["+", h]
|
|
310
197
|
})]
|
|
311
198
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"badge-group.js","names":[],"sources":["../../src/ui/badge.tsx","../../src/ui/badge-group.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconCheck, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Dot } from './dot'\nimport { Icon } from './icon'\nimport type { IconInput } from './lib/icon-input'\nimport { durations,springs } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n// ── Color map — single source of truth for all badge color × variant combos ──\nconst colorMap = {\n default: { bg: 'bg-surface-panel-hover', softBg: 'bg-surface-panel-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n accent: { bg: 'bg-accent-2', softBg: 'bg-accent-3', fg: 'text-accent-11', border: 'border-accent-4', solid: 'bg-accent-9', solidFg: 'text-accent-fg' },\n error: { bg: 'bg-error-2', softBg: 'bg-error-3', fg: 'text-error-11', border: 'border-error-4', solid: 'bg-error-9', solidFg: 'text-error-fg' },\n success: { bg: 'bg-success-2', softBg: 'bg-success-3', fg: 'text-success-11', border: 'border-success-4', solid: 'bg-success-9', solidFg: 'text-success-fg' },\n warning: { bg: 'bg-warning-2', softBg: 'bg-warning-3', fg: 'text-warning-11', border: 'border-warning-4', solid: 'bg-warning-9', solidFg: 'text-warning-fg' },\n info: { bg: 'bg-info-2', softBg: 'bg-info-3', fg: 'text-info-11', border: 'border-info-4', solid: 'bg-info-9', solidFg: 'text-info-fg' },\n neutral: { bg: 'bg-surface-panel-hover', softBg: 'bg-surface-panel-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n teal: { bg: 'bg-category-teal-2', softBg: 'bg-category-teal-3', fg: 'text-category-teal-11', border: 'border-category-teal-4', solid: 'bg-category-teal-9', solidFg: 'text-category-fg' },\n amber: { bg: 'bg-category-amber-2', softBg: 'bg-category-amber-3', fg: 'text-category-amber-11', border: 'border-category-amber-4', solid: 'bg-category-amber-9', solidFg: 'text-category-fg' },\n slate: { bg: 'bg-category-slate-2', softBg: 'bg-category-slate-3', fg: 'text-category-slate-11', border: 'border-category-slate-4', solid: 'bg-category-slate-9', solidFg: 'text-category-fg' },\n indigo: { bg: 'bg-category-indigo-2', softBg: 'bg-category-indigo-3', fg: 'text-category-indigo-11', border: 'border-category-indigo-4', solid: 'bg-category-indigo-9', solidFg: 'text-category-fg' },\n cyan: { bg: 'bg-category-cyan-2', softBg: 'bg-category-cyan-3', fg: 'text-category-cyan-11', border: 'border-category-cyan-4', solid: 'bg-category-cyan-9', solidFg: 'text-category-fg' },\n orange: { bg: 'bg-category-orange-2', softBg: 'bg-category-orange-3', fg: 'text-category-orange-11', border: 'border-category-orange-4', solid: 'bg-category-orange-9', solidFg: 'text-category-fg' },\n emerald: { bg: 'bg-category-emerald-2', softBg: 'bg-category-emerald-3', fg: 'text-category-emerald-11', border: 'border-category-emerald-4', solid: 'bg-category-emerald-9', solidFg: 'text-category-fg' },\n} as const\n\ntype BadgeColor = keyof typeof colorMap | 'custom'\n\n/** Derive color classes for a given variant + color pair */\nfunction getColorClasses(variant: 'subtle' | 'solid' | 'outline' | 'soft', color: BadgeColor): string {\n if (color === 'custom') return ''\n const c = colorMap[color]\n switch (variant) {\n case 'subtle': return cn(c.bg, c.fg, c.border)\n case 'solid': return cn(c.solid, c.solidFg, 'border-transparent')\n case 'outline': return cn('bg-transparent', c.fg, c.border)\n // soft keeps the original step-3 fill. subtle moved to step 2; soft did not,\n // so the two cannot share one key (design call, Yogin/Goutham 2026-08-24).\n case 'soft': return cn(c.softBg, c.fg, 'border-transparent')\n }\n}\n\nconst badgeVariants = cva(\n 'relative inline-flex items-center rounded-pill font-sans font-medium overflow-hidden isolate transition-[color,background-color,border-color,padding] duration-fast-02 ease-productive-standard select-none [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]',\n {\n variants: {\n variant: {\n subtle: 'border',\n solid: 'border border-transparent',\n outline: 'border',\n soft: 'border border-transparent',\n },\n size: {\n xs: 'h-4 px-ds-02b text-body-xs gap-ds-02',\n sm: 'h-5 px-ds-03 text-body-xs gap-ds-02',\n md: 'h-6 px-2.5 text-body-xs gap-ds-02b', /* px-2.5=10px — no exact DS token */\n lg: 'h-7 px-ds-04 text-body-sm gap-ds-02b',\n },\n },\n defaultVariants: {\n variant: 'subtle',\n size: 'md',\n },\n },\n)\n\n/** Icon sizing per badge size */\nconst iconSizeMap: Record<string, string> = {\n xs: '[&>svg]:h-2.5 [&>svg]:w-2.5',\n sm: '[&>svg]:h-3 [&>svg]:w-3',\n md: '[&>svg]:h-3 [&>svg]:w-3',\n lg: '[&>svg]:h-3.5 [&>svg]:w-3.5',\n}\n\n/** Reduced left padding when leading content (icon/dot/selected) is present */\nconst paddingLeftWithIcon: Record<string, string> = {\n xs: 'pl-ds-02',\n sm: 'pl-ds-02b',\n md: 'pl-ds-03',\n lg: 'pl-2.5', /* 10px — no exact DS token */\n}\n\n/** Reduced right padding when trailing content (dismiss/endIcon) is present */\nconst paddingRightWithTrailing: Record<string, string> = {\n xs: 'pr-ds-01',\n sm: 'pr-ds-02',\n md: 'pr-ds-02',\n lg: 'pr-ds-02b',\n}\n\n/**\n * Badge — a compact inline label with a two-axis variant system.\n *\n * **Two axes:**\n * - `variant` controls **visual style**: `\"subtle\"` | `\"solid\"` | `\"outline\"` | `\"soft\"`\n * - `color` controls **semantic intent/category**: 16 built-in colors + `\"custom\"` (CSS variable)\n *\n * **Interactive:** Pass `onClick` to make it a button. Pass `selected` for toggle state.\n * **Dismissible:** Pass `onDismiss` to show a dismiss button.\n * **Custom colors:** Set `color=\"custom\"` and CSS variable `--badge-color` on a parent or via `style`.\n * For light custom colors on solid variant, set `--badge-fg-color` to a dark value.\n *\n * @example\n * <Badge color=\"success\">Active</Badge>\n *\n * @example\n * <Badge variant=\"solid\" size=\"sm\" dot>3 new</Badge>\n *\n * @example\n * <Badge color=\"custom\" style={{ '--badge-color': '#8b5cf6' } as React.CSSProperties}>\n * Custom\n * </Badge>\n */\ninterface BadgeProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n VariantProps<typeof badgeVariants> {\n /** Semantic intent or category color. Use `\"custom\"` with `--badge-color` CSS variable. */\n color?: BadgeColor\n asChild?: boolean\n startIcon?: IconInput\n endIcon?: IconInput\n dot?: boolean\n /** Pulse the status dot (opt-in; static by default). @default false */\n dotPulse?: boolean\n onDismiss?: () => void\n selected?: boolean\n disabled?: boolean\n maxWidth?: number\n /**\n * Truncate children with ellipsis when they overflow the badge width.\n * Use with a fixed width (e.g. `className=\"w-20\"`) or `maxWidth` for\n * constrained pill badges. Always adds a title tooltip on the full text.\n */\n truncate?: boolean\n circle?: boolean\n}\n\nconst Badge = React.forwardRef<HTMLElement, BadgeProps>(\n (\n {\n className,\n variant,\n color,\n size,\n asChild,\n startIcon,\n endIcon,\n dot,\n dotPulse,\n onDismiss,\n onClick,\n selected,\n disabled,\n maxWidth,\n truncate,\n circle,\n children,\n style,\n ...props\n },\n ref,\n ) => {\n const resolvedVariant = variant ?? 'subtle'\n const resolvedColor = color ?? 'default'\n const resolvedSize = size ?? 'md'\n\n // When both onClick + onDismiss, use div with role=\"button\" to avoid nested <button>\n const Comp = asChild\n ? Slot\n : onClick && onDismiss\n ? 'div'\n : onClick\n ? 'button'\n : 'span'\n\n // Custom color inline styles via CSS variable\n const customStyles =\n resolvedColor === 'custom'\n ? {\n ...(resolvedVariant === 'subtle' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 15%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 40%, transparent)',\n }),\n ...(resolvedVariant === 'solid' && {\n backgroundColor: 'var(--badge-color)',\n color: 'var(--badge-fg-color, white)',\n borderColor: 'transparent',\n }),\n ...(resolvedVariant === 'outline' && {\n backgroundColor: 'transparent',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 50%, transparent)',\n }),\n ...(resolvedVariant === 'soft' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 12%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'transparent',\n }),\n }\n : undefined\n\n // Keyboard handler for div[role=\"button\"] (onClick + onDismiss case)\n const handleKeyDown =\n onClick && onDismiss\n ? (e: React.KeyboardEvent<HTMLElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (!disabled) onClick(e as unknown as React.MouseEvent<HTMLElement>)\n }\n props.onKeyDown?.(e)\n }\n : props.onKeyDown\n\n const hasLeading = !!(dot || startIcon || (onClick && selected && !startIcon && !dot))\n const hasTrailing = !!(onDismiss || endIcon)\n\n return (\n <Comp\n ref={ref as React.Ref<never>}\n className={cn(\n badgeVariants({ variant: resolvedVariant, size: resolvedSize }),\n getColorClasses(resolvedVariant, resolvedColor),\n hasLeading && paddingLeftWithIcon[resolvedSize],\n hasTrailing && paddingRightWithTrailing[resolvedSize],\n onClick &&\n 'cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]',\n selected && 'ring-1 ring-current/20 transition-shadow duration-fast-02',\n disabled && 'opacity-action-disabled pointer-events-none saturate-[0.3]',\n circle && 'justify-center px-0 aspect-square',\n className,\n )}\n style={{ ...style, ...customStyles, ...(maxWidth ? { maxWidth } : undefined) }}\n onClick={disabled ? undefined : (onClick as React.MouseEventHandler<HTMLElement>)}\n onKeyDown={handleKeyDown}\n {...(Comp === 'button' && { type: 'button' as const })}\n {...(Comp === 'button' && disabled ? { disabled: true } : {})}\n {...(Comp === 'div' && onClick ? { role: 'button' as const, tabIndex: 0 } : {})}\n {...props}\n >\n {/* Dot indicator — animated entrance, uses the shared <Dot> (current colour + pulse) */}\n <AnimatePresence>\n {dot && (\n <motion.span\n key=\"dot\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n exit={{ scale: 0 }}\n transition={springs.snappy}\n className=\"inline-flex shrink-0\"\n >\n <Dot color=\"current\" size=\"sm\" pulse={dotPulse} />\n </motion.span>\n )}\n </AnimatePresence>\n\n {/* Selected check icon — always mounted for interactive badges */}\n {onClick && !startIcon && !dot && (\n <motion.span\n initial={false}\n animate={selected\n ? { opacity: 1, scale: 1, width: 'auto', marginRight: 0 }\n : { opacity: 0, scale: 0.5, width: 0, marginRight: -4 }\n }\n transition={{ type: 'tween', duration: durations.moderate01, ease: [0.2, 0, 0.38, 0.9] }} /* ease-productive-standard */\n className=\"inline-flex shrink-0 overflow-hidden\"\n aria-hidden={!selected}\n >\n <Icon icon={IconCheck} size=\"xs\" />\n </motion.span>\n )}\n\n {/* Start icon */}\n {startIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(startIcon)}</span>\n )}\n\n {/* Children — with optional truncation */}\n {truncate || maxWidth ? (\n <span\n className=\"truncate\"\n title={typeof children === 'string' ? children : undefined}\n >\n {children}\n </span>\n ) : (\n children\n )}\n\n {/* End icon */}\n {endIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(endIcon)}</span>\n )}\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n onDismiss()\n }}\n className={cn(\n 'shrink-0 rounded-pill text-current/60 hover:text-current hover:bg-current/10 transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-accent-9',\n resolvedSize === 'xs'\n ? 'p-0 -mr-0.5 min-w-ds-05 min-h-ds-05'\n : 'p-px',\n )}\n aria-label={\n `Remove ${typeof children === 'string' ? children : ''}`.trim() || 'Remove'\n }\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n )}\n </Comp>\n )\n },\n)\nBadge.displayName = 'Badge'\n\nimport { BadgeGroup } from './badge-group'\nimport { BadgeIndicator } from './badge-indicator'\n\nconst BadgeCompound = Object.assign(Badge, {\n Indicator: BadgeIndicator,\n Group: BadgeGroup,\n})\n\nexport { BadgeCompound as Badge, type BadgeColor,type BadgeProps, badgeVariants }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Badge, type BadgeProps } from './badge'\nimport { cn } from './lib/utils'\n\nconst GAP_CLASSES = {\n tight: 'gap-1',\n default: 'gap-1.5',\n loose: 'gap-2',\n} as const\n\nexport interface BadgeGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n children: React.ReactNode\n}\n\nexport const BadgeGroup = React.forwardRef<HTMLDivElement, BadgeGroupProps>(function BadgeGroup(\n { max, gap = 'default', size, onOverflowClick, className, children, ...rest },\n ref,\n) {\n const childArray = React.Children.toArray(children)\n const total = childArray.length\n const hasOverflow = max !== undefined && total > max\n const visible = hasOverflow ? childArray.slice(0, max) : childArray\n const overflowCount = hasOverflow ? total - max! : 0\n\n return (\n <div\n ref={ref}\n className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}\n {...rest}\n >\n {visible}\n {hasOverflow && (\n // With onClick, Badge renders a real, keyboard-reachable <button>; add a\n // label since \"+N\" alone isn't descriptive to a screen reader.\n <Badge\n variant=\"outline\"\n color=\"neutral\"\n size={size ?? 'sm'}\n onClick={onOverflowClick}\n aria-label={onOverflowClick ? `Show ${overflowCount} more` : undefined}\n >\n +{overflowCount}\n </Badge>\n )}\n </div>\n )\n})\n\nBadgeGroup.displayName = 'BadgeGroup'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"badge-group.js","names":[],"sources":["../../src/ui/badge.tsx","../../src/ui/badge-group.tsx"],"sourcesContent":["'use client'\n\nimport { Slot } from '@primitives/react-slot'\nimport { IconCheck, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { MotionPreference } from '../motion/motion-preference'\nimport { Dot } from './dot'\nimport { Icon } from './icon'\nimport type { IconInput } from './lib/icon-input'\nimport { durations,springs } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\n\n// ── Color map — single source of truth for all badge color × variant combos ──\nconst colorMap = {\n default: { bg: 'bg-surface-panel-hover', softBg: 'bg-surface-panel-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n accent: { bg: 'bg-accent-2', softBg: 'bg-accent-3', fg: 'text-accent-11', border: 'border-accent-4', solid: 'bg-accent-9', solidFg: 'text-accent-fg' },\n error: { bg: 'bg-error-2', softBg: 'bg-error-3', fg: 'text-error-11', border: 'border-error-4', solid: 'bg-error-9', solidFg: 'text-error-fg' },\n success: { bg: 'bg-success-2', softBg: 'bg-success-3', fg: 'text-success-11', border: 'border-success-4', solid: 'bg-success-9', solidFg: 'text-success-fg' },\n warning: { bg: 'bg-warning-2', softBg: 'bg-warning-3', fg: 'text-warning-11', border: 'border-warning-4', solid: 'bg-warning-9', solidFg: 'text-warning-fg' },\n info: { bg: 'bg-info-2', softBg: 'bg-info-3', fg: 'text-info-11', border: 'border-info-4', solid: 'bg-info-9', solidFg: 'text-info-fg' },\n neutral: { bg: 'bg-surface-panel-hover', softBg: 'bg-surface-panel-hover', fg: 'text-surface-fg-muted', border: 'border-surface-border-strong', solid: 'bg-neutral-5', solidFg: 'text-surface-fg' },\n teal: { bg: 'bg-category-teal-2', softBg: 'bg-category-teal-3', fg: 'text-category-teal-11', border: 'border-category-teal-4', solid: 'bg-category-teal-9', solidFg: 'text-category-fg' },\n amber: { bg: 'bg-category-amber-2', softBg: 'bg-category-amber-3', fg: 'text-category-amber-11', border: 'border-category-amber-4', solid: 'bg-category-amber-9', solidFg: 'text-category-fg' },\n slate: { bg: 'bg-category-slate-2', softBg: 'bg-category-slate-3', fg: 'text-category-slate-11', border: 'border-category-slate-4', solid: 'bg-category-slate-9', solidFg: 'text-category-fg' },\n indigo: { bg: 'bg-category-indigo-2', softBg: 'bg-category-indigo-3', fg: 'text-category-indigo-11', border: 'border-category-indigo-4', solid: 'bg-category-indigo-9', solidFg: 'text-category-fg' },\n cyan: { bg: 'bg-category-cyan-2', softBg: 'bg-category-cyan-3', fg: 'text-category-cyan-11', border: 'border-category-cyan-4', solid: 'bg-category-cyan-9', solidFg: 'text-category-fg' },\n orange: { bg: 'bg-category-orange-2', softBg: 'bg-category-orange-3', fg: 'text-category-orange-11', border: 'border-category-orange-4', solid: 'bg-category-orange-9', solidFg: 'text-category-fg' },\n emerald: { bg: 'bg-category-emerald-2', softBg: 'bg-category-emerald-3', fg: 'text-category-emerald-11', border: 'border-category-emerald-4', solid: 'bg-category-emerald-9', solidFg: 'text-category-fg' },\n} as const\n\n/**\n * A palette name. These fourteen ship with the design system; any palette\n * registered in CSS (`[data-palette='…']`) works too, which is why the type\n * stays open. `custom` is the older escape hatch — it drives colour through\n * inline styles from a `--badge-color` variable and is superseded by\n * registering a palette, but still works.\n */\ntype BadgeColor = keyof typeof colorMap | 'custom' | (string & {})\n\n/**\n * Colour classes per variant. Four lines instead of a 14 × 6 map — the hue\n * arrives via `data-palette` on the element.\n *\n * `subtle` and `soft` map to two different roles on purpose. subtle moved to\n * step 2 and soft stayed at step 3 (design call, Yogin/Goutham 2026-08-24), and\n * the palette contract keeps them as separate roles precisely so that decision\n * survives rather than being averaged away.\n */\nfunction getColorClasses(variant: 'subtle' | 'solid' | 'outline' | 'soft', color: BadgeColor): string {\n if (color === 'custom') return ''\n switch (variant) {\n case 'subtle': return 'bg-palette-subtle text-palette-text border-palette-border'\n case 'solid': return 'bg-palette-solid text-palette-fg border-transparent'\n case 'outline': return 'bg-transparent text-palette-text border-palette-border'\n case 'soft': return 'bg-palette-soft text-palette-text border-transparent'\n }\n}\n\nconst badgeVariants = cva(\n 'relative inline-flex items-center rounded-pill font-sans font-medium overflow-hidden isolate transition-[color,background-color,border-color,padding] duration-fast-02 ease-productive-standard select-none [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]',\n {\n variants: {\n variant: {\n subtle: 'border',\n solid: 'border border-transparent',\n outline: 'border',\n soft: 'border border-transparent',\n },\n size: {\n xs: 'h-4 px-ds-02b text-body-xs gap-ds-02',\n sm: 'h-5 px-ds-03 text-body-xs gap-ds-02',\n md: 'h-6 px-2.5 text-body-xs gap-ds-02b', /* px-2.5=10px — no exact DS token */\n lg: 'h-7 px-ds-04 text-body-sm gap-ds-02b',\n },\n },\n defaultVariants: {\n variant: 'subtle',\n size: 'md',\n },\n },\n)\n\n/** Icon sizing per badge size */\nconst iconSizeMap: Record<string, string> = {\n xs: '[&>svg]:h-2.5 [&>svg]:w-2.5',\n sm: '[&>svg]:h-3 [&>svg]:w-3',\n md: '[&>svg]:h-3 [&>svg]:w-3',\n lg: '[&>svg]:h-3.5 [&>svg]:w-3.5',\n}\n\n/** Reduced left padding when leading content (icon/dot/selected) is present */\nconst paddingLeftWithIcon: Record<string, string> = {\n xs: 'pl-ds-02',\n sm: 'pl-ds-02b',\n md: 'pl-ds-03',\n lg: 'pl-2.5', /* 10px — no exact DS token */\n}\n\n/** Reduced right padding when trailing content (dismiss/endIcon) is present */\nconst paddingRightWithTrailing: Record<string, string> = {\n xs: 'pr-ds-01',\n sm: 'pr-ds-02',\n md: 'pr-ds-02',\n lg: 'pr-ds-02b',\n}\n\n/**\n * Badge — a compact inline label with a two-axis variant system.\n *\n * **Two axes:**\n * - `variant` controls **visual style**: `\"subtle\"` | `\"solid\"` | `\"outline\"` | `\"soft\"`\n * - `color` controls **semantic intent/category**: 16 built-in colors + `\"custom\"` (CSS variable)\n *\n * **Interactive:** Pass `onClick` to make it a button. Pass `selected` for toggle state.\n * **Dismissible:** Pass `onDismiss` to show a dismiss button.\n * **Custom colors:** Set `color=\"custom\"` and CSS variable `--badge-color` on a parent or via `style`.\n * For light custom colors on solid variant, set `--badge-fg-color` to a dark value.\n *\n * @example\n * <Badge color=\"success\">Active</Badge>\n *\n * @example\n * <Badge variant=\"solid\" size=\"sm\" dot>3 new</Badge>\n *\n * @example\n * <Badge color=\"custom\" style={{ '--badge-color': '#8b5cf6' } as React.CSSProperties}>\n * Custom\n * </Badge>\n */\ninterface BadgeProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>,\n VariantProps<typeof badgeVariants> {\n /** Semantic intent or category color. Use `\"custom\"` with `--badge-color` CSS variable. */\n color?: BadgeColor\n asChild?: boolean\n startIcon?: IconInput\n endIcon?: IconInput\n dot?: boolean\n /** Pulse the status dot (opt-in; static by default). @default false */\n dotPulse?: boolean\n onDismiss?: () => void\n selected?: boolean\n disabled?: boolean\n maxWidth?: number\n /**\n * Truncate children with ellipsis when they overflow the badge width.\n * Use with a fixed width (e.g. `className=\"w-20\"`) or `maxWidth` for\n * constrained pill badges. Always adds a title tooltip on the full text.\n */\n truncate?: boolean\n circle?: boolean\n}\n\nconst Badge = React.forwardRef<HTMLElement, BadgeProps>(\n (\n {\n className,\n variant,\n color,\n size,\n asChild,\n startIcon,\n endIcon,\n dot,\n dotPulse,\n onDismiss,\n onClick,\n selected,\n disabled,\n maxWidth,\n truncate,\n circle,\n children,\n style,\n ...props\n },\n ref,\n ) => {\n const resolvedVariant = variant ?? 'subtle'\n const resolvedColor = color ?? 'default'\n const resolvedSize = size ?? 'md'\n\n // When both onClick + onDismiss, use div with role=\"button\" to avoid nested <button>\n const Comp = asChild\n ? Slot\n : onClick && onDismiss\n ? 'div'\n : onClick\n ? 'button'\n : 'span'\n\n // Custom color inline styles via CSS variable\n const customStyles =\n resolvedColor === 'custom'\n ? {\n ...(resolvedVariant === 'subtle' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 15%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 40%, transparent)',\n }),\n ...(resolvedVariant === 'solid' && {\n backgroundColor: 'var(--badge-color)',\n color: 'var(--badge-fg-color, white)',\n borderColor: 'transparent',\n }),\n ...(resolvedVariant === 'outline' && {\n backgroundColor: 'transparent',\n color: 'var(--badge-color)',\n borderColor: 'color-mix(in oklch, var(--badge-color) 50%, transparent)',\n }),\n ...(resolvedVariant === 'soft' && {\n backgroundColor: 'color-mix(in oklch, var(--badge-color) 12%, transparent)',\n color: 'var(--badge-color)',\n borderColor: 'transparent',\n }),\n }\n : undefined\n\n // Keyboard handler for div[role=\"button\"] (onClick + onDismiss case)\n const handleKeyDown =\n onClick && onDismiss\n ? (e: React.KeyboardEvent<HTMLElement>) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (!disabled) onClick(e as unknown as React.MouseEvent<HTMLElement>)\n }\n props.onKeyDown?.(e)\n }\n : props.onKeyDown\n\n const hasLeading = !!(dot || startIcon || (onClick && selected && !startIcon && !dot))\n const hasTrailing = !!(onDismiss || endIcon)\n\n return (\n <MotionPreference>\n <Comp\n ref={ref as React.Ref<never>}\n // `custom` keeps driving colour through inline styles from\n // `--badge-color`; every other value is a palette name.\n data-palette={resolvedColor === 'custom' ? undefined : resolvedColor}\n className={cn(\n badgeVariants({ variant: resolvedVariant, size: resolvedSize }),\n getColorClasses(resolvedVariant, resolvedColor),\n hasLeading && paddingLeftWithIcon[resolvedSize],\n hasTrailing && paddingRightWithTrailing[resolvedSize],\n onClick &&\n 'cursor-pointer hover:brightness-[0.97] focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-1 transition-[color,background-color,border-color,transform,filter] duration-moderate-01 ease-productive-exit hover:duration-fast-02 hover:ease-productive-entrance active:scale-[0.95] active:brightness-[0.92] active:duration-[0ms]',\n selected && 'ring-1 ring-current/20 transition-shadow duration-fast-02',\n disabled && 'opacity-action-disabled pointer-events-none saturate-[0.3]',\n circle && 'justify-center px-0 aspect-square',\n className,\n )}\n style={{ ...style, ...customStyles, ...(maxWidth ? { maxWidth } : undefined) }}\n onClick={disabled ? undefined : (onClick as React.MouseEventHandler<HTMLElement>)}\n onKeyDown={handleKeyDown}\n {...(Comp === 'button' && { type: 'button' as const })}\n {...(Comp === 'button' && disabled ? { disabled: true } : {})}\n {...(Comp === 'div' && onClick ? { role: 'button' as const, tabIndex: 0 } : {})}\n {...props}\n >\n {/* Dot indicator — animated entrance, uses the shared <Dot> (current colour + pulse) */}\n <AnimatePresence>\n {dot && (\n <motion.span\n key=\"dot\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n exit={{ scale: 0 }}\n transition={springs.snappy}\n className=\"inline-flex shrink-0\"\n >\n <Dot color=\"current\" size=\"sm\" pulse={dotPulse} />\n </motion.span>\n )}\n </AnimatePresence>\n\n {/* Selected check icon — always mounted for interactive badges */}\n {onClick && !startIcon && !dot && (\n <motion.span\n initial={false}\n animate={selected\n ? { opacity: 1, scale: 1, width: 'auto', marginRight: 0 }\n : { opacity: 0, scale: 0.5, width: 0, marginRight: -4 }\n }\n transition={{ type: 'tween', duration: durations.moderate01, ease: [0.2, 0, 0.38, 0.9] }} /* ease-productive-standard */\n className=\"inline-flex shrink-0 overflow-hidden\"\n aria-hidden={!selected}\n >\n <Icon icon={IconCheck} size=\"xs\" />\n </motion.span>\n )}\n\n {/* Start icon */}\n {startIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(startIcon)}</span>\n )}\n\n {/* Children — with optional truncation */}\n {truncate || maxWidth ? (\n <span\n className=\"truncate\"\n title={typeof children === 'string' ? children : undefined}\n >\n {children}\n </span>\n ) : (\n children\n )}\n\n {/* End icon */}\n {endIcon && (\n <span className={cn('shrink-0', iconSizeMap[resolvedSize])}>{normalizeIcon(endIcon)}</span>\n )}\n\n {/* Dismiss button */}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n onDismiss()\n }}\n className={cn(\n 'shrink-0 rounded-pill text-current/60 hover:text-current hover:bg-current/10 transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-accent-9',\n resolvedSize === 'xs'\n ? 'p-0 -mr-0.5 min-w-ds-05 min-h-ds-05'\n : 'p-px',\n )}\n aria-label={\n `Remove ${typeof children === 'string' ? children : ''}`.trim() || 'Remove'\n }\n >\n <Icon icon={IconX} size=\"xs\" />\n </button>\n )}\n </Comp>\n </MotionPreference>\n )\n },\n)\nBadge.displayName = 'Badge'\n\nimport { BadgeGroup } from './badge-group'\nimport { BadgeIndicator } from './badge-indicator'\n\nconst BadgeCompound = Object.assign(Badge, {\n Indicator: BadgeIndicator,\n Group: BadgeGroup,\n})\n\nexport { BadgeCompound as Badge, type BadgeColor,type BadgeProps, badgeVariants }\n","'use client'\n\nimport * as React from 'react'\n\nimport { Badge, type BadgeProps } from './badge'\nimport { cn } from './lib/utils'\n\nconst GAP_CLASSES = {\n tight: 'gap-1',\n default: 'gap-1.5',\n loose: 'gap-2',\n} as const\n\nexport interface BadgeGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n max?: number\n gap?: keyof typeof GAP_CLASSES\n size?: BadgeProps['size']\n onOverflowClick?: () => void\n children: React.ReactNode\n}\n\nexport const BadgeGroup = React.forwardRef<HTMLDivElement, BadgeGroupProps>(function BadgeGroup(\n { max, gap = 'default', size, onOverflowClick, className, children, ...rest },\n ref,\n) {\n const childArray = React.Children.toArray(children)\n const total = childArray.length\n const hasOverflow = max !== undefined && total > max\n const visible = hasOverflow ? childArray.slice(0, max) : childArray\n const overflowCount = hasOverflow ? total - max! : 0\n\n return (\n <div\n ref={ref}\n className={cn('flex flex-wrap items-center', GAP_CLASSES[gap], className)}\n {...rest}\n >\n {visible}\n {hasOverflow && (\n // With onClick, Badge renders a real, keyboard-reachable <button>; add a\n // label since \"+N\" alone isn't descriptive to a screen reader.\n <Badge\n variant=\"outline\"\n color=\"neutral\"\n size={size ?? 'sm'}\n onClick={onOverflowClick}\n aria-label={onOverflowClick ? `Show ${overflowCount} more` : undefined}\n >\n +{overflowCount}\n </Badge>\n )}\n </div>\n )\n})\n\nBadgeGroup.displayName = 'BadgeGroup'\n"],"mappings":"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"}
|