@inui/design-system 0.0.0-stage → 1.22.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/README.md +360 -2
- package/dist/components/ui/accordion.d.ts +44 -0
- package/dist/components/ui/accordion.d.ts.map +1 -0
- package/dist/components/ui/accordion.js +86 -0
- package/dist/components/ui/accordion.js.map +1 -0
- package/dist/components/ui/ai-avatar.d.ts +46 -0
- package/dist/components/ui/ai-avatar.d.ts.map +1 -0
- package/dist/components/ui/ai-avatar.js +43 -0
- package/dist/components/ui/ai-avatar.js.map +1 -0
- package/dist/components/ui/ai-label.d.ts +118 -0
- package/dist/components/ui/ai-label.d.ts.map +1 -0
- package/dist/components/ui/ai-label.js +184 -0
- package/dist/components/ui/ai-label.js.map +1 -0
- package/dist/components/ui/ai-sparkle.d.ts +91 -0
- package/dist/components/ui/ai-sparkle.d.ts.map +1 -0
- package/dist/components/ui/ai-sparkle.js +200 -0
- package/dist/components/ui/ai-sparkle.js.map +1 -0
- package/dist/components/ui/alert-dialog.d.ts +79 -0
- package/dist/components/ui/alert-dialog.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.js +147 -0
- package/dist/components/ui/alert-dialog.js.map +1 -0
- package/dist/components/ui/alert.d.ts +71 -0
- package/dist/components/ui/alert.d.ts.map +1 -0
- package/dist/components/ui/alert.js +108 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/aspect-ratio.d.ts +30 -0
- package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.js +40 -0
- package/dist/components/ui/aspect-ratio.js.map +1 -0
- package/dist/components/ui/attachment.d.ts +74 -0
- package/dist/components/ui/attachment.d.ts.map +1 -0
- package/dist/components/ui/attachment.js +142 -0
- package/dist/components/ui/attachment.js.map +1 -0
- package/dist/components/ui/avatar.d.ts +82 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/avatar.js +123 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.d.ts +130 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +226 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +43 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.js +98 -0
- package/dist/components/ui/breadcrumb.js.map +1 -0
- package/dist/components/ui/browser-tabs.d.ts +218 -0
- package/dist/components/ui/browser-tabs.d.ts.map +1 -0
- package/dist/components/ui/browser-tabs.js +528 -0
- package/dist/components/ui/browser-tabs.js.map +1 -0
- package/dist/components/ui/bubble.d.ts +80 -0
- package/dist/components/ui/bubble.d.ts.map +1 -0
- package/dist/components/ui/bubble.js +235 -0
- package/dist/components/ui/bubble.js.map +1 -0
- package/dist/components/ui/button-group.d.ts +60 -0
- package/dist/components/ui/button-group.d.ts.map +1 -0
- package/dist/components/ui/button-group.js +89 -0
- package/dist/components/ui/button-group.js.map +1 -0
- package/dist/components/ui/button.d.ts +157 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +144 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/calendar.d.ts +57 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/calendar.js +163 -0
- package/dist/components/ui/calendar.js.map +1 -0
- package/dist/components/ui/card.d.ts +96 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/card.js +131 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/carousel.d.ts +86 -0
- package/dist/components/ui/carousel.d.ts.map +1 -0
- package/dist/components/ui/carousel.js +207 -0
- package/dist/components/ui/carousel.js.map +1 -0
- package/dist/components/ui/checkbox.d.ts +54 -0
- package/dist/components/ui/checkbox.d.ts.map +1 -0
- package/dist/components/ui/checkbox.js +78 -0
- package/dist/components/ui/checkbox.js.map +1 -0
- package/dist/components/ui/collapsible.d.ts +45 -0
- package/dist/components/ui/collapsible.d.ts.map +1 -0
- package/dist/components/ui/collapsible.js +65 -0
- package/dist/components/ui/collapsible.js.map +1 -0
- package/dist/components/ui/combobox.d.ts +111 -0
- package/dist/components/ui/combobox.d.ts.map +1 -0
- package/dist/components/ui/combobox.js +264 -0
- package/dist/components/ui/combobox.js.map +1 -0
- package/dist/components/ui/command.d.ts +71 -0
- package/dist/components/ui/command.d.ts.map +1 -0
- package/dist/components/ui/command.js +133 -0
- package/dist/components/ui/command.js.map +1 -0
- package/dist/components/ui/context-menu.d.ts +70 -0
- package/dist/components/ui/context-menu.d.ts.map +1 -0
- package/dist/components/ui/context-menu.js +163 -0
- package/dist/components/ui/context-menu.js.map +1 -0
- package/dist/components/ui/count-badge.d.ts +40 -0
- package/dist/components/ui/count-badge.d.ts.map +1 -0
- package/dist/components/ui/count-badge.js +43 -0
- package/dist/components/ui/count-badge.js.map +1 -0
- package/dist/components/ui/data-table.d.ts +1026 -0
- package/dist/components/ui/data-table.d.ts.map +1 -0
- package/dist/components/ui/data-table.js +3423 -0
- package/dist/components/ui/data-table.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +73 -0
- package/dist/components/ui/dialog.d.ts.map +1 -0
- package/dist/components/ui/dialog.js +145 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/ui/direction.d.ts +35 -0
- package/dist/components/ui/direction.d.ts.map +1 -0
- package/dist/components/ui/direction.js +35 -0
- package/dist/components/ui/direction.js.map +1 -0
- package/dist/components/ui/drawer.d.ts +53 -0
- package/dist/components/ui/drawer.d.ts.map +1 -0
- package/dist/components/ui/drawer.js +115 -0
- package/dist/components/ui/drawer.js.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +75 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.js +173 -0
- package/dist/components/ui/dropdown-menu.js.map +1 -0
- package/dist/components/ui/dropzone.d.ts +141 -0
- package/dist/components/ui/dropzone.d.ts.map +1 -0
- package/dist/components/ui/dropzone.js +257 -0
- package/dist/components/ui/dropzone.js.map +1 -0
- package/dist/components/ui/empty.d.ts +94 -0
- package/dist/components/ui/empty.d.ts.map +1 -0
- package/dist/components/ui/empty.js +149 -0
- package/dist/components/ui/empty.js.map +1 -0
- package/dist/components/ui/field.d.ts +122 -0
- package/dist/components/ui/field.d.ts.map +1 -0
- package/dist/components/ui/field.js +254 -0
- package/dist/components/ui/field.js.map +1 -0
- package/dist/components/ui/hover-card.d.ts +51 -0
- package/dist/components/ui/hover-card.d.ts.map +1 -0
- package/dist/components/ui/hover-card.js +101 -0
- package/dist/components/ui/hover-card.js.map +1 -0
- package/dist/components/ui/input-group.d.ts +62 -0
- package/dist/components/ui/input-group.d.ts.map +1 -0
- package/dist/components/ui/input-group.js +115 -0
- package/dist/components/ui/input-group.js.map +1 -0
- package/dist/components/ui/input-otp.d.ts +52 -0
- package/dist/components/ui/input-otp.d.ts.map +1 -0
- package/dist/components/ui/input-otp.js +89 -0
- package/dist/components/ui/input-otp.js.map +1 -0
- package/dist/components/ui/input.d.ts +47 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +47 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/item.d.ts +74 -0
- package/dist/components/ui/item.d.ts.map +1 -0
- package/dist/components/ui/item.js +176 -0
- package/dist/components/ui/item.js.map +1 -0
- package/dist/components/ui/kbd.d.ts +41 -0
- package/dist/components/ui/kbd.d.ts.map +1 -0
- package/dist/components/ui/kbd.js +58 -0
- package/dist/components/ui/kbd.js.map +1 -0
- package/dist/components/ui/key-value-pair.d.ts +56 -0
- package/dist/components/ui/key-value-pair.d.ts.map +1 -0
- package/dist/components/ui/key-value-pair.js +110 -0
- package/dist/components/ui/key-value-pair.js.map +1 -0
- package/dist/components/ui/label.d.ts +83 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +85 -0
- package/dist/components/ui/label.js.map +1 -0
- package/dist/components/ui/marker.d.ts +54 -0
- package/dist/components/ui/marker.d.ts.map +1 -0
- package/dist/components/ui/marker.js +79 -0
- package/dist/components/ui/marker.js.map +1 -0
- package/dist/components/ui/menubar.d.ts +72 -0
- package/dist/components/ui/menubar.d.ts.map +1 -0
- package/dist/components/ui/menubar.js +174 -0
- package/dist/components/ui/menubar.js.map +1 -0
- package/dist/components/ui/message-scroller.d.ts +53 -0
- package/dist/components/ui/message-scroller.d.ts.map +1 -0
- package/dist/components/ui/message-scroller.js +95 -0
- package/dist/components/ui/message-scroller.js.map +1 -0
- package/dist/components/ui/message.d.ts +63 -0
- package/dist/components/ui/message.d.ts.map +1 -0
- package/dist/components/ui/message.js +92 -0
- package/dist/components/ui/message.js.map +1 -0
- package/dist/components/ui/meta-list.d.ts +55 -0
- package/dist/components/ui/meta-list.d.ts.map +1 -0
- package/dist/components/ui/meta-list.js +75 -0
- package/dist/components/ui/meta-list.js.map +1 -0
- package/dist/components/ui/native-select.d.ts +51 -0
- package/dist/components/ui/native-select.d.ts.map +1 -0
- package/dist/components/ui/native-select.js +75 -0
- package/dist/components/ui/native-select.js.map +1 -0
- package/dist/components/ui/navigation-menu.d.ts +56 -0
- package/dist/components/ui/navigation-menu.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.js +116 -0
- package/dist/components/ui/navigation-menu.js.map +1 -0
- package/dist/components/ui/page-header.d.ts +223 -0
- package/dist/components/ui/page-header.d.ts.map +1 -0
- package/dist/components/ui/page-header.js +233 -0
- package/dist/components/ui/page-header.js.map +1 -0
- package/dist/components/ui/pagination.d.ts +68 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/pagination.js +145 -0
- package/dist/components/ui/pagination.js.map +1 -0
- package/dist/components/ui/popover.d.ts +61 -0
- package/dist/components/ui/popover.d.ts.map +1 -0
- package/dist/components/ui/popover.js +144 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/progress.d.ts +35 -0
- package/dist/components/ui/progress.d.ts.map +1 -0
- package/dist/components/ui/progress.js +46 -0
- package/dist/components/ui/progress.js.map +1 -0
- package/dist/components/ui/questionnaire.d.ts +92 -0
- package/dist/components/ui/questionnaire.d.ts.map +1 -0
- package/dist/components/ui/questionnaire.js +277 -0
- package/dist/components/ui/questionnaire.js.map +1 -0
- package/dist/components/ui/radio-group.d.ts +50 -0
- package/dist/components/ui/radio-group.d.ts.map +1 -0
- package/dist/components/ui/radio-group.js +65 -0
- package/dist/components/ui/radio-group.js.map +1 -0
- package/dist/components/ui/resizable.d.ts +44 -0
- package/dist/components/ui/resizable.d.ts.map +1 -0
- package/dist/components/ui/resizable.js +73 -0
- package/dist/components/ui/resizable.js.map +1 -0
- package/dist/components/ui/scroll-area.d.ts +55 -0
- package/dist/components/ui/scroll-area.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.js +72 -0
- package/dist/components/ui/scroll-area.js.map +1 -0
- package/dist/components/ui/select.d.ts +274 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +609 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/separator.d.ts +31 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/separator.js +38 -0
- package/dist/components/ui/separator.js.map +1 -0
- package/dist/components/ui/sheet.d.ts +59 -0
- package/dist/components/ui/sheet.d.ts.map +1 -0
- package/dist/components/ui/sheet.js +128 -0
- package/dist/components/ui/sheet.js.map +1 -0
- package/dist/components/ui/sidebar.d.ts +166 -0
- package/dist/components/ui/sidebar.d.ts.map +1 -0
- package/dist/components/ui/sidebar.js +512 -0
- package/dist/components/ui/sidebar.js.map +1 -0
- package/dist/components/ui/skeleton.d.ts +35 -0
- package/dist/components/ui/skeleton.d.ts.map +1 -0
- package/dist/components/ui/skeleton.js +46 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/components/ui/slider.d.ts +39 -0
- package/dist/components/ui/slider.d.ts.map +1 -0
- package/dist/components/ui/slider.js +75 -0
- package/dist/components/ui/slider.js.map +1 -0
- package/dist/components/ui/sonner.d.ts +56 -0
- package/dist/components/ui/sonner.d.ts.map +1 -0
- package/dist/components/ui/sonner.js +96 -0
- package/dist/components/ui/sonner.js.map +1 -0
- package/dist/components/ui/spinner.d.ts +37 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/components/ui/spinner.js +51 -0
- package/dist/components/ui/spinner.js.map +1 -0
- package/dist/components/ui/stepper.d.ts +84 -0
- package/dist/components/ui/stepper.d.ts.map +1 -0
- package/dist/components/ui/stepper.js +145 -0
- package/dist/components/ui/stepper.js.map +1 -0
- package/dist/components/ui/switch.d.ts +36 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/components/ui/switch.js +44 -0
- package/dist/components/ui/switch.js.map +1 -0
- package/dist/components/ui/table.d.ts +80 -0
- package/dist/components/ui/table.d.ts.map +1 -0
- package/dist/components/ui/table.js +130 -0
- package/dist/components/ui/table.js.map +1 -0
- package/dist/components/ui/tabs.d.ts +87 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/tabs.js +128 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/textarea.d.ts +35 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/textarea.js +38 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/components/ui/time-picker.d.ts +58 -0
- package/dist/components/ui/time-picker.d.ts.map +1 -0
- package/dist/components/ui/time-picker.js +188 -0
- package/dist/components/ui/time-picker.js.map +1 -0
- package/dist/components/ui/toggle-group.d.ts +52 -0
- package/dist/components/ui/toggle-group.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.js +94 -0
- package/dist/components/ui/toggle-group.js.map +1 -0
- package/dist/components/ui/toggle.d.ts +50 -0
- package/dist/components/ui/toggle.d.ts.map +1 -0
- package/dist/components/ui/toggle.js +70 -0
- package/dist/components/ui/toggle.js.map +1 -0
- package/dist/components/ui/tooltip.d.ts +51 -0
- package/dist/components/ui/tooltip.d.ts.map +1 -0
- package/dist/components/ui/tooltip.js +78 -0
- package/dist/components/ui/tooltip.js.map +1 -0
- package/dist/hooks/use-dark-mode.d.ts +2 -0
- package/dist/hooks/use-dark-mode.d.ts.map +1 -0
- package/dist/hooks/use-dark-mode.js +36 -0
- package/dist/hooks/use-dark-mode.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +20 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +77 -0
- package/dist/lib/scope.d.ts +64 -0
- package/dist/lib/scope.d.ts.map +1 -0
- package/dist/lib/scope.js +74 -0
- package/dist/lib/scope.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +11 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/theme-tokens.css +537 -0
- package/dist/theme.css +417 -0
- package/package.json +103 -3
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
import { jsx } from "react/jsx-runtime";
|
|
5
|
+
import { cva } from "class-variance-authority";
|
|
6
|
+
//#region src/components/ui/badge.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Badge — inline status/category/count label.
|
|
9
|
+
*
|
|
10
|
+
* cva-driven span, non-interactive by default. Styled on two axes — `tone`
|
|
11
|
+
* (what it means) × `emphasis` (how loudly it's drawn) — with the old single
|
|
12
|
+
* `variant` list kept as a deprecated alias.
|
|
13
|
+
*/
|
|
14
|
+
var badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
|
|
15
|
+
variants: {
|
|
16
|
+
tone: {
|
|
17
|
+
default: "",
|
|
18
|
+
secondary: "",
|
|
19
|
+
destructive: ""
|
|
20
|
+
},
|
|
21
|
+
emphasis: {
|
|
22
|
+
filled: "",
|
|
23
|
+
outline: "",
|
|
24
|
+
ghost: ""
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
compoundVariants: [
|
|
28
|
+
{
|
|
29
|
+
tone: "default",
|
|
30
|
+
emphasis: "filled",
|
|
31
|
+
class: "bg-primary text-primary-foreground [a]:hover:bg-primary-hover [a]:active:bg-primary-active"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
tone: "secondary",
|
|
35
|
+
emphasis: "filled",
|
|
36
|
+
class: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
tone: "destructive",
|
|
40
|
+
emphasis: "filled",
|
|
41
|
+
class: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
tone: "default",
|
|
45
|
+
emphasis: "outline",
|
|
46
|
+
class: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
tone: "secondary",
|
|
50
|
+
emphasis: "outline",
|
|
51
|
+
class: "border-border text-muted-foreground [a]:hover:bg-muted"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
tone: "destructive",
|
|
55
|
+
emphasis: "outline",
|
|
56
|
+
class: "border-destructive/40 text-destructive focus-visible:ring-destructive/20 [a]:hover:bg-destructive/10"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
tone: "default",
|
|
60
|
+
emphasis: "ghost",
|
|
61
|
+
class: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
tone: "secondary",
|
|
65
|
+
emphasis: "ghost",
|
|
66
|
+
class: "text-muted-foreground hover:bg-muted dark:hover:bg-muted/50"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
tone: "destructive",
|
|
70
|
+
emphasis: "ghost",
|
|
71
|
+
class: "text-destructive hover:bg-destructive/10 dark:hover:bg-destructive/20"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
defaultVariants: {
|
|
75
|
+
tone: "default",
|
|
76
|
+
emphasis: "filled"
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
var LEGACY_VARIANT = {
|
|
80
|
+
default: {
|
|
81
|
+
tone: "default",
|
|
82
|
+
emphasis: "filled"
|
|
83
|
+
},
|
|
84
|
+
secondary: {
|
|
85
|
+
tone: "secondary",
|
|
86
|
+
emphasis: "filled"
|
|
87
|
+
},
|
|
88
|
+
destructive: {
|
|
89
|
+
tone: "destructive",
|
|
90
|
+
emphasis: "filled"
|
|
91
|
+
},
|
|
92
|
+
outline: {
|
|
93
|
+
tone: "default",
|
|
94
|
+
emphasis: "outline"
|
|
95
|
+
},
|
|
96
|
+
ghost: {
|
|
97
|
+
tone: "default",
|
|
98
|
+
emphasis: "ghost"
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
function Badge({ className, tone, emphasis, variant, asChild = false, truncate = false, maxWidth, style, children, title, ...props }) {
|
|
102
|
+
const Comp = asChild ? Slot.Root : "span";
|
|
103
|
+
const legacy = variant && variant !== "link" ? LEGACY_VARIANT[variant] : void 0;
|
|
104
|
+
const resolvedTone = tone ?? legacy?.tone ?? "default";
|
|
105
|
+
const resolvedEmphasis = emphasis ?? legacy?.emphasis ?? (variant === "link" ? "ghost" : "filled");
|
|
106
|
+
const truncating = !asChild && (truncate || maxWidth !== void 0);
|
|
107
|
+
const content = truncating ? React.Children.map(children, (child) => typeof child === "string" || typeof child === "number" ? /* @__PURE__ */ jsx("span", {
|
|
108
|
+
className: "min-w-0 truncate",
|
|
109
|
+
children: child
|
|
110
|
+
}) : child) : children;
|
|
111
|
+
const fullLabel = title ?? (truncating ? React.Children.toArray(children).filter((c) => typeof c === "string" || typeof c === "number").join("") || void 0 : void 0);
|
|
112
|
+
return /* @__PURE__ */ jsx(Comp, {
|
|
113
|
+
"data-slot": "badge",
|
|
114
|
+
"data-tone": resolvedTone,
|
|
115
|
+
"data-emphasis": resolvedEmphasis,
|
|
116
|
+
"data-variant": variant,
|
|
117
|
+
className: cn(badgeVariants({
|
|
118
|
+
tone: resolvedTone,
|
|
119
|
+
emphasis: resolvedEmphasis
|
|
120
|
+
}), variant === "link" && "text-primary underline-offset-4 hover:bg-transparent hover:text-primary hover:underline", truncating && "max-w-full min-w-0", className),
|
|
121
|
+
style: maxWidth !== void 0 ? {
|
|
122
|
+
maxWidth,
|
|
123
|
+
...style
|
|
124
|
+
} : style,
|
|
125
|
+
title: fullLabel,
|
|
126
|
+
...props,
|
|
127
|
+
children: content
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* WHEN TO USE
|
|
132
|
+
* - A status, category, count, or tag shown inline with other content
|
|
133
|
+
* (row status, list tag, small metadata chip).
|
|
134
|
+
* - An operational-status indicator (active, failed, expiring, pending) —
|
|
135
|
+
* emphasis="outline" with a small colored icon, not a filled badge. This
|
|
136
|
+
* is Badge's status-indicator convention; there's no separate component
|
|
137
|
+
* for it.
|
|
138
|
+
*
|
|
139
|
+
* NOT WHEN
|
|
140
|
+
* - Interactive filters or removable tags — those need their own
|
|
141
|
+
* click/remove handling, which Badge doesn't provide.
|
|
142
|
+
* - An action — use Button.
|
|
143
|
+
* - Long text — Badge is sized and padded for short labels only. When a user-supplied label might run long anyway (a role or tag name), cap it with `maxWidth` / `truncate`.
|
|
144
|
+
*
|
|
145
|
+
* KEY RULES
|
|
146
|
+
* - `truncate` / `maxWidth` ellipsize a long label and show the full text as a native `title`; icons are untouched. They don't apply with `asChild`.
|
|
147
|
+
* - Non-interactive by default; pass `asChild` to render as an `<a>` when
|
|
148
|
+
* the badge itself needs to link somewhere.
|
|
149
|
+
* - Two axes, not one list. tone: default | secondary | destructive — what the
|
|
150
|
+
* label means. emphasis: filled | outline | ghost — how loudly it's drawn.
|
|
151
|
+
* Every tone×emphasis pair is styled; omit both for a filled default badge.
|
|
152
|
+
* The old single `variant` prop (default, secondary, destructive, outline,
|
|
153
|
+
* ghost, link) still renders identically but is deprecated — it folded the
|
|
154
|
+
* two axes into one list. `link` has no new-axis equivalent: a Badge is
|
|
155
|
+
* non-interactive, so an underlined link look belongs on Button/anchor.
|
|
156
|
+
* - Custom semantic colors (success/warning/alert/info) aren't separate
|
|
157
|
+
* variants — apply the token utility directly, using each status's
|
|
158
|
+
* subtle `-light`/`-text` pair (not the solid `-foreground` pairing,
|
|
159
|
+
* which reads too loud for an inline tag), e.g. `className="bg-success-light
|
|
160
|
+
* text-success-text"`.
|
|
161
|
+
* - Status-indicator convention: emphasis="outline" + a leading icon colored
|
|
162
|
+
* with the matching semantic token, `data-icon="inline-start"`. Fixed
|
|
163
|
+
* icon/color pairing, don't substitute other icons for these:
|
|
164
|
+
* success -> CheckIcon text-success
|
|
165
|
+
* alert -> XIcon text-alert (text-destructive for a true error, not just "alert")
|
|
166
|
+
* warning -> TriangleAlertIcon text-warning
|
|
167
|
+
* info -> InfoIcon text-info
|
|
168
|
+
* default -> PenLineIcon text-muted-foreground
|
|
169
|
+
* - Flush status-indicator variant: the same icon/color pairing above, but
|
|
170
|
+
* `emphasis="ghost"` (no border, no fill) plus
|
|
171
|
+
* `className="px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent"`
|
|
172
|
+
* — the padding overrides zero out what `emphasis="outline"` needs for
|
|
173
|
+
* its own chip look but this doesn't, and `hover:bg-transparent` drops
|
|
174
|
+
* `ghost`'s subtle hover highlight (meant for when Badge is `asChild` as
|
|
175
|
+
* a real link), which a flush, non-interactive status doesn't need. For
|
|
176
|
+
* a status that needs to sit flush against other plain content instead
|
|
177
|
+
* of reading as its own separate chip: a `KeyValuePairValue` slot, a
|
|
178
|
+
* table cell (especially one with a `MetaList` underneath, where a
|
|
179
|
+
* padded chip would misalign against the MetaList's own flush left/right
|
|
180
|
+
* edges), or right-aligned in a flex row next to one.
|
|
181
|
+
* - An AI-assigned status/tag is a plain composition, not a variant: keep the Badge exactly
|
|
182
|
+
* as the status calls for and put `AILabel` (size="sm" — never the opt-in icon-only "xs" by
|
|
183
|
+
* default) beside it in an `inline-flex` span. Never restyle the Badge itself
|
|
184
|
+
* with the AI gradient — that would be indistinguishable from Button's AI Chip
|
|
185
|
+
* (variant="ai" rounded-full), and the two must read apart: the Chip is an action, a Badge
|
|
186
|
+
* is not. See AI/Badge.
|
|
187
|
+
*
|
|
188
|
+
* USAGE
|
|
189
|
+
* <Badge>Default</Badge>
|
|
190
|
+
* <Badge tone="destructive">Overdue</Badge>
|
|
191
|
+
* <Badge tone="secondary" emphasis="ghost">Draft</Badge>
|
|
192
|
+
* <Badge className="bg-success-light text-success-text">Success</Badge>
|
|
193
|
+
* <Badge><CheckIcon />Verified</Badge>
|
|
194
|
+
* <Badge maxWidth={120}>Regional Clinical Operations Lead</Badge>
|
|
195
|
+
*
|
|
196
|
+
* // Status indicator convention
|
|
197
|
+
* <Badge emphasis="outline">
|
|
198
|
+
* <CheckIcon className="text-success" data-icon="inline-start" />
|
|
199
|
+
* Active
|
|
200
|
+
* </Badge>
|
|
201
|
+
* <Badge emphasis="outline">
|
|
202
|
+
* <XIcon className="text-alert" data-icon="inline-start" />
|
|
203
|
+
* Failed
|
|
204
|
+
* </Badge>
|
|
205
|
+
* <Badge emphasis="outline">
|
|
206
|
+
* <TriangleAlertIcon className="text-warning" data-icon="inline-start" />
|
|
207
|
+
* Expiring soon
|
|
208
|
+
* </Badge>
|
|
209
|
+
* <Badge emphasis="outline">
|
|
210
|
+
* <PenLineIcon className="text-muted-foreground" data-icon="inline-start" />
|
|
211
|
+
* Draft
|
|
212
|
+
* </Badge>
|
|
213
|
+
*
|
|
214
|
+
* // Flush status indicator — KVP value, table cell, or right-aligned next to a MetaList
|
|
215
|
+
* <Badge
|
|
216
|
+
* emphasis="ghost"
|
|
217
|
+
* className="px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent"
|
|
218
|
+
* >
|
|
219
|
+
* <CheckIcon className="text-success" data-icon="inline-start" />
|
|
220
|
+
* Active
|
|
221
|
+
* </Badge>
|
|
222
|
+
*/
|
|
223
|
+
//#endregion
|
|
224
|
+
export { Badge, badgeVariants };
|
|
225
|
+
|
|
226
|
+
//# sourceMappingURL=badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"badge.js","names":[],"sources":["../../../src/components/ui/badge.tsx"],"sourcesContent":["/**\n * Badge — inline status/category/count label.\n *\n * cva-driven span, non-interactive by default. Styled on two axes — `tone`\n * (what it means) × `emphasis` (how loudly it's drawn) — with the old single\n * `variant` list kept as a deprecated alias.\n */\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst badgeVariants = cva(\n \"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-colors focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!\",\n {\n // Two axes, not one list: `tone` is what the label means (neutral\n // primary, quieter secondary, destructive), `emphasis` is how loudly\n // it's drawn (filled surface, outlined, or bare text). Every\n // combination is defined below so the two never collide.\n variants: {\n tone: {\n default: \"\",\n secondary: \"\",\n destructive: \"\",\n },\n emphasis: {\n filled: \"\",\n outline: \"\",\n ghost: \"\",\n },\n },\n compoundVariants: [\n {\n tone: \"default\",\n emphasis: \"filled\",\n class:\n \"bg-primary text-primary-foreground [a]:hover:bg-primary-hover [a]:active:bg-primary-active\",\n },\n {\n tone: \"secondary\",\n emphasis: \"filled\",\n class:\n \"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80\",\n },\n {\n tone: \"destructive\",\n emphasis: \"filled\",\n class:\n \"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20\",\n },\n {\n tone: \"default\",\n emphasis: \"outline\",\n class:\n \"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground\",\n },\n {\n tone: \"secondary\",\n emphasis: \"outline\",\n class: \"border-border text-muted-foreground [a]:hover:bg-muted\",\n },\n {\n tone: \"destructive\",\n emphasis: \"outline\",\n class:\n \"border-destructive/40 text-destructive focus-visible:ring-destructive/20 [a]:hover:bg-destructive/10\",\n },\n {\n tone: \"default\",\n emphasis: \"ghost\",\n class:\n \"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50\",\n },\n {\n tone: \"secondary\",\n emphasis: \"ghost\",\n class: \"text-muted-foreground hover:bg-muted dark:hover:bg-muted/50\",\n },\n {\n tone: \"destructive\",\n emphasis: \"ghost\",\n class:\n \"text-destructive hover:bg-destructive/10 dark:hover:bg-destructive/20\",\n },\n ],\n defaultVariants: {\n tone: \"default\",\n emphasis: \"filled\",\n },\n }\n)\n\ntype BadgeTone = NonNullable<VariantProps<typeof badgeVariants>[\"tone\"]>\ntype BadgeEmphasis = NonNullable<VariantProps<typeof badgeVariants>[\"emphasis\"]>\n/**\n * @deprecated The single `variant` list mixed two axes (what the badge means\n * and how loudly it's drawn). Use `tone` + `emphasis` instead. Still accepted\n * so existing consumers render unchanged: default -> filled default,\n * secondary -> filled secondary, destructive -> filled destructive,\n * outline -> outline default, ghost -> ghost default. `link` (an interaction\n * affordance on a non-interactive label) has no new-axis equivalent and just\n * keeps its old underline look.\n */\ntype BadgeLegacyVariant =\n \"default\" | \"secondary\" | \"destructive\" | \"outline\" | \"ghost\" | \"link\"\n\nconst LEGACY_VARIANT: Record<\n Exclude<BadgeLegacyVariant, \"link\">,\n { tone: BadgeTone; emphasis: BadgeEmphasis }\n> = {\n default: { tone: \"default\", emphasis: \"filled\" },\n secondary: { tone: \"secondary\", emphasis: \"filled\" },\n destructive: { tone: \"destructive\", emphasis: \"filled\" },\n outline: { tone: \"default\", emphasis: \"outline\" },\n ghost: { tone: \"default\", emphasis: \"ghost\" },\n}\n\nfunction Badge({\n className,\n tone,\n emphasis,\n variant,\n asChild = false,\n truncate = false,\n maxWidth,\n style,\n children,\n title,\n ...props\n}: React.ComponentProps<\"span\"> &\n VariantProps<typeof badgeVariants> & {\n asChild?: boolean\n /** Cuts a label that's too long for its space off with an ellipsis instead of overflowing. Pair with `maxWidth` (or a width from the parent) — without one the badge just sizes to its text. Not applied with `asChild`. */\n truncate?: boolean\n /** Caps the badge's width (a number is px, or any CSS size) and implies `truncate`. */\n maxWidth?: number | string\n /** @deprecated use `tone` + `emphasis` */\n variant?: BadgeLegacyVariant\n }) {\n const Comp = asChild ? Slot.Root : \"span\"\n const legacy =\n variant && variant !== \"link\" ? LEGACY_VARIANT[variant] : undefined\n const resolvedTone = tone ?? legacy?.tone ?? \"default\"\n const resolvedEmphasis =\n emphasis ?? legacy?.emphasis ?? (variant === \"link\" ? \"ghost\" : \"filled\")\n\n const truncating = !asChild && (truncate || maxWidth !== undefined)\n // A flex container can't ellipsize its own bare text — each text run gets\n // its own `truncate` span, while icons (elements) keep their size.\n const content = truncating\n ? React.Children.map(children, (child) =>\n typeof child === \"string\" || typeof child === \"number\" ? (\n <span className=\"min-w-0 truncate\">{child}</span>\n ) : (\n child\n )\n )\n : children\n // Surfaces the full label on hover once it may be cut off.\n const fullLabel =\n title ??\n (truncating\n ? React.Children.toArray(children)\n .filter((c) => typeof c === \"string\" || typeof c === \"number\")\n .join(\"\") || undefined\n : undefined)\n\n return (\n <Comp\n data-slot=\"badge\"\n data-tone={resolvedTone}\n data-emphasis={resolvedEmphasis}\n data-variant={variant}\n className={cn(\n badgeVariants({ tone: resolvedTone, emphasis: resolvedEmphasis }),\n variant === \"link\" &&\n \"text-primary underline-offset-4 hover:bg-transparent hover:text-primary hover:underline\",\n truncating && \"max-w-full min-w-0\",\n className\n )}\n style={maxWidth !== undefined ? { maxWidth, ...style } : style}\n title={fullLabel}\n {...props}\n >\n {content}\n </Comp>\n )\n}\n\nexport { Badge, badgeVariants }\nexport type { BadgeTone, BadgeEmphasis }\n\n/**\n * WHEN TO USE\n * - A status, category, count, or tag shown inline with other content\n * (row status, list tag, small metadata chip).\n * - An operational-status indicator (active, failed, expiring, pending) —\n * emphasis=\"outline\" with a small colored icon, not a filled badge. This\n * is Badge's status-indicator convention; there's no separate component\n * for it.\n *\n * NOT WHEN\n * - Interactive filters or removable tags — those need their own\n * click/remove handling, which Badge doesn't provide.\n * - An action — use Button.\n * - Long text — Badge is sized and padded for short labels only. When a user-supplied label might run long anyway (a role or tag name), cap it with `maxWidth` / `truncate`.\n *\n * KEY RULES\n * - `truncate` / `maxWidth` ellipsize a long label and show the full text as a native `title`; icons are untouched. They don't apply with `asChild`.\n * - Non-interactive by default; pass `asChild` to render as an `<a>` when\n * the badge itself needs to link somewhere.\n * - Two axes, not one list. tone: default | secondary | destructive — what the\n * label means. emphasis: filled | outline | ghost — how loudly it's drawn.\n * Every tone×emphasis pair is styled; omit both for a filled default badge.\n * The old single `variant` prop (default, secondary, destructive, outline,\n * ghost, link) still renders identically but is deprecated — it folded the\n * two axes into one list. `link` has no new-axis equivalent: a Badge is\n * non-interactive, so an underlined link look belongs on Button/anchor.\n * - Custom semantic colors (success/warning/alert/info) aren't separate\n * variants — apply the token utility directly, using each status's\n * subtle `-light`/`-text` pair (not the solid `-foreground` pairing,\n * which reads too loud for an inline tag), e.g. `className=\"bg-success-light\n * text-success-text\"`.\n * - Status-indicator convention: emphasis=\"outline\" + a leading icon colored\n * with the matching semantic token, `data-icon=\"inline-start\"`. Fixed\n * icon/color pairing, don't substitute other icons for these:\n * success -> CheckIcon text-success\n * alert -> XIcon text-alert (text-destructive for a true error, not just \"alert\")\n * warning -> TriangleAlertIcon text-warning\n * info -> InfoIcon text-info\n * default -> PenLineIcon text-muted-foreground\n * - Flush status-indicator variant: the same icon/color pairing above, but\n * `emphasis=\"ghost\"` (no border, no fill) plus\n * `className=\"px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent\"`\n * — the padding overrides zero out what `emphasis=\"outline\"` needs for\n * its own chip look but this doesn't, and `hover:bg-transparent` drops\n * `ghost`'s subtle hover highlight (meant for when Badge is `asChild` as\n * a real link), which a flush, non-interactive status doesn't need. For\n * a status that needs to sit flush against other plain content instead\n * of reading as its own separate chip: a `KeyValuePairValue` slot, a\n * table cell (especially one with a `MetaList` underneath, where a\n * padded chip would misalign against the MetaList's own flush left/right\n * edges), or right-aligned in a flex row next to one.\n * - An AI-assigned status/tag is a plain composition, not a variant: keep the Badge exactly\n * as the status calls for and put `AILabel` (size=\"sm\" — never the opt-in icon-only \"xs\" by\n * default) beside it in an `inline-flex` span. Never restyle the Badge itself\n * with the AI gradient — that would be indistinguishable from Button's AI Chip\n * (variant=\"ai\" rounded-full), and the two must read apart: the Chip is an action, a Badge\n * is not. See AI/Badge.\n *\n * USAGE\n * <Badge>Default</Badge>\n * <Badge tone=\"destructive\">Overdue</Badge>\n * <Badge tone=\"secondary\" emphasis=\"ghost\">Draft</Badge>\n * <Badge className=\"bg-success-light text-success-text\">Success</Badge>\n * <Badge><CheckIcon />Verified</Badge>\n * <Badge maxWidth={120}>Regional Clinical Operations Lead</Badge>\n *\n * // Status indicator convention\n * <Badge emphasis=\"outline\">\n * <CheckIcon className=\"text-success\" data-icon=\"inline-start\" />\n * Active\n * </Badge>\n * <Badge emphasis=\"outline\">\n * <XIcon className=\"text-alert\" data-icon=\"inline-start\" />\n * Failed\n * </Badge>\n * <Badge emphasis=\"outline\">\n * <TriangleAlertIcon className=\"text-warning\" data-icon=\"inline-start\" />\n * Expiring soon\n * </Badge>\n * <Badge emphasis=\"outline\">\n * <PenLineIcon className=\"text-muted-foreground\" data-icon=\"inline-start\" />\n * Draft\n * </Badge>\n *\n * // Flush status indicator — KVP value, table cell, or right-aligned next to a MetaList\n * <Badge\n * emphasis=\"ghost\"\n * className=\"px-0 has-data-[icon=inline-start]:pl-0 has-data-[icon=inline-end]:pr-0 hover:bg-transparent\"\n * >\n * <CheckIcon className=\"text-success\" data-icon=\"inline-start\" />\n * Active\n * </Badge>\n */\n"],"mappings":";;;;;;;;;;;;;AAcA,IAAM,gBAAgB,IACpB,ifACA;CAKE,UAAU;EACR,MAAM;GACJ,SAAS;GACT,WAAW;GACX,aAAa;EACf;EACA,UAAU;GACR,QAAQ;GACR,SAAS;GACT,OAAO;EACT;CACF;CACA,kBAAkB;EAChB;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;EACA;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;EACA;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;EACA;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;EACA;GACE,MAAM;GACN,UAAU;GACV,OAAO;EACT;EACA;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;EACA;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;EACA;GACE,MAAM;GACN,UAAU;GACV,OAAO;EACT;EACA;GACE,MAAM;GACN,UAAU;GACV,OACE;EACJ;CACF;CACA,iBAAiB;EACf,MAAM;EACN,UAAU;CACZ;AACF,CACF;AAgBA,IAAM,iBAGF;CACF,SAAS;EAAE,MAAM;EAAW,UAAU;CAAS;CAC/C,WAAW;EAAE,MAAM;EAAa,UAAU;CAAS;CACnD,aAAa;EAAE,MAAM;EAAe,UAAU;CAAS;CACvD,SAAS;EAAE,MAAM;EAAW,UAAU;CAAU;CAChD,OAAO;EAAE,MAAM;EAAW,UAAU;CAAQ;AAC9C;AAEA,SAAS,MAAM,EACb,WACA,MACA,UACA,SACA,UAAU,OACV,WAAW,OACX,UACA,OACA,UACA,OACA,GAAG,SAUA;CACH,MAAM,OAAO,UAAU,KAAK,OAAO;CACnC,MAAM,SACJ,WAAW,YAAY,SAAS,eAAe,WAAW,KAAA;CAC5D,MAAM,eAAe,QAAQ,QAAQ,QAAQ;CAC7C,MAAM,mBACJ,YAAY,QAAQ,aAAa,YAAY,SAAS,UAAU;CAElE,MAAM,aAAa,CAAC,YAAY,YAAY,aAAa,KAAA;CAGzD,MAAM,UAAU,aACZ,MAAM,SAAS,IAAI,WAAW,UAC5B,OAAO,UAAU,YAAY,OAAO,UAAU,WAC5C,oBAAC,QAAD;EAAM,WAAU;EAAoB,UAAA;CAAY,CAAA,IAEhD,KAEJ,IACA;CAEJ,MAAM,YACJ,UACC,aACG,MAAM,SAAS,QAAQ,QAAQ,CAAC,CAC7B,QAAQ,MAAM,OAAO,MAAM,YAAY,OAAO,MAAM,QAAQ,CAAC,CAC7D,KAAK,EAAE,KAAK,KAAA,IACf,KAAA;CAEN,OACE,oBAAC,MAAD;EACE,aAAU;EACV,aAAW;EACX,iBAAe;EACf,gBAAc;EACd,WAAW,GACT,cAAc;GAAE,MAAM;GAAc,UAAU;EAAiB,CAAC,GAChE,YAAY,UACV,2FACF,cAAc,sBACd,SACF;EACA,OAAO,aAAa,KAAA,IAAY;GAAE;GAAU,GAAG;EAAM,IAAI;EACzD,OAAO;EACP,GAAI;EAEH,UAAA;CACG,CAAA;AAEV"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Breadcrumb — hierarchical location trail, plain markup (not a Radix primitive).
|
|
3
|
+
*
|
|
4
|
+
* An <ol> of BreadcrumbItem, ancestors as BreadcrumbLink and the current
|
|
5
|
+
* page as a non-interactive BreadcrumbPage.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
declare function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">): React.JSX.Element;
|
|
9
|
+
declare function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">): React.JSX.Element;
|
|
10
|
+
declare function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">): React.JSX.Element;
|
|
11
|
+
declare function BreadcrumbLink({ asChild, className, ...props }: React.ComponentProps<"a"> & {
|
|
12
|
+
asChild?: boolean;
|
|
13
|
+
}): React.JSX.Element;
|
|
14
|
+
declare function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
15
|
+
declare function BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<"li">): React.JSX.Element;
|
|
16
|
+
declare function BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
|
|
17
|
+
export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, };
|
|
18
|
+
/**
|
|
19
|
+
* WHEN TO USE
|
|
20
|
+
* - Showing position in a hierarchy at least two levels deep (e.g. Patients
|
|
21
|
+
* › James Wilson), typically placed above a PageHeader title
|
|
22
|
+
*
|
|
23
|
+
* NOT WHEN
|
|
24
|
+
* - Flat navigation with no hierarchy
|
|
25
|
+
* - As a substitute for Tabs
|
|
26
|
+
*
|
|
27
|
+
* KEY RULES
|
|
28
|
+
* - The current page is BreadcrumbPage — plain text, not a link
|
|
29
|
+
* (aria-current="page", aria-disabled)
|
|
30
|
+
* - BreadcrumbEllipsis collapses a long trail; pair it with a
|
|
31
|
+
* BreadcrumbSeparator on each side like any other item
|
|
32
|
+
* - BreadcrumbLink supports asChild to render a router Link instead of <a>
|
|
33
|
+
*
|
|
34
|
+
* USAGE
|
|
35
|
+
* <Breadcrumb>
|
|
36
|
+
* <BreadcrumbList>
|
|
37
|
+
* <BreadcrumbItem><BreadcrumbLink href="/patients">Patients</BreadcrumbLink></BreadcrumbItem>
|
|
38
|
+
* <BreadcrumbSeparator />
|
|
39
|
+
* <BreadcrumbItem><BreadcrumbPage>James Wilson</BreadcrumbPage></BreadcrumbItem>
|
|
40
|
+
* </BreadcrumbList>
|
|
41
|
+
* </Breadcrumb>
|
|
42
|
+
*/
|
|
43
|
+
//# sourceMappingURL=breadcrumb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"breadcrumb.d.ts","sourceRoot":"","sources":["../../../src/components/ui/breadcrumb.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBASvE;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,qBAW1E;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,qBAQ1E;AAED,iBAAS,cAAc,CAAC,EACtB,OAAO,EACP,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,qBAUA;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAW5E;AAED,iBAAS,mBAAmB,CAAC,EAC3B,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,qBAY5B;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,qBAgB9B;AAED,OAAO,EACL,UAAU,EACV,cAAc,EACd,cAAc,EACd,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,kBAAkB,GACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { cn } from "../../lib/utils.js";
|
|
2
|
+
import "react";
|
|
3
|
+
import { Slot } from "radix-ui";
|
|
4
|
+
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
//#region src/components/ui/breadcrumb.tsx
|
|
7
|
+
function Breadcrumb({ className, ...props }) {
|
|
8
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
9
|
+
"aria-label": "breadcrumb",
|
|
10
|
+
"data-slot": "breadcrumb",
|
|
11
|
+
className: cn(className),
|
|
12
|
+
...props
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function BreadcrumbList({ className, ...props }) {
|
|
16
|
+
return /* @__PURE__ */ jsx("ol", {
|
|
17
|
+
"data-slot": "breadcrumb-list",
|
|
18
|
+
className: cn("flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground", className),
|
|
19
|
+
...props
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function BreadcrumbItem({ className, ...props }) {
|
|
23
|
+
return /* @__PURE__ */ jsx("li", {
|
|
24
|
+
"data-slot": "breadcrumb-item",
|
|
25
|
+
className: cn("inline-flex items-center gap-1", className),
|
|
26
|
+
...props
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function BreadcrumbLink({ asChild, className, ...props }) {
|
|
30
|
+
const Comp = asChild ? Slot.Root : "a";
|
|
31
|
+
return /* @__PURE__ */ jsx(Comp, {
|
|
32
|
+
"data-slot": "breadcrumb-link",
|
|
33
|
+
className: cn("transition-colors hover:text-foreground", className),
|
|
34
|
+
...props
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function BreadcrumbPage({ className, ...props }) {
|
|
38
|
+
return /* @__PURE__ */ jsx("span", {
|
|
39
|
+
"data-slot": "breadcrumb-page",
|
|
40
|
+
role: "link",
|
|
41
|
+
"aria-disabled": "true",
|
|
42
|
+
"aria-current": "page",
|
|
43
|
+
className: cn("font-normal text-foreground", className),
|
|
44
|
+
...props
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function BreadcrumbSeparator({ children, className, ...props }) {
|
|
48
|
+
return /* @__PURE__ */ jsx("li", {
|
|
49
|
+
"data-slot": "breadcrumb-separator",
|
|
50
|
+
role: "presentation",
|
|
51
|
+
"aria-hidden": "true",
|
|
52
|
+
className: cn("[&>svg]:size-3.5", className),
|
|
53
|
+
...props,
|
|
54
|
+
children: children ?? /* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
function BreadcrumbEllipsis({ className, ...props }) {
|
|
58
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
59
|
+
"data-slot": "breadcrumb-ellipsis",
|
|
60
|
+
role: "presentation",
|
|
61
|
+
"aria-hidden": "true",
|
|
62
|
+
className: cn("flex size-5 items-center justify-center [&>svg]:size-4", className),
|
|
63
|
+
...props,
|
|
64
|
+
children: [/* @__PURE__ */ jsx(MoreHorizontalIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
65
|
+
className: "sr-only",
|
|
66
|
+
children: "More"
|
|
67
|
+
})]
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* WHEN TO USE
|
|
72
|
+
* - Showing position in a hierarchy at least two levels deep (e.g. Patients
|
|
73
|
+
* › James Wilson), typically placed above a PageHeader title
|
|
74
|
+
*
|
|
75
|
+
* NOT WHEN
|
|
76
|
+
* - Flat navigation with no hierarchy
|
|
77
|
+
* - As a substitute for Tabs
|
|
78
|
+
*
|
|
79
|
+
* KEY RULES
|
|
80
|
+
* - The current page is BreadcrumbPage — plain text, not a link
|
|
81
|
+
* (aria-current="page", aria-disabled)
|
|
82
|
+
* - BreadcrumbEllipsis collapses a long trail; pair it with a
|
|
83
|
+
* BreadcrumbSeparator on each side like any other item
|
|
84
|
+
* - BreadcrumbLink supports asChild to render a router Link instead of <a>
|
|
85
|
+
*
|
|
86
|
+
* USAGE
|
|
87
|
+
* <Breadcrumb>
|
|
88
|
+
* <BreadcrumbList>
|
|
89
|
+
* <BreadcrumbItem><BreadcrumbLink href="/patients">Patients</BreadcrumbLink></BreadcrumbItem>
|
|
90
|
+
* <BreadcrumbSeparator />
|
|
91
|
+
* <BreadcrumbItem><BreadcrumbPage>James Wilson</BreadcrumbPage></BreadcrumbItem>
|
|
92
|
+
* </BreadcrumbList>
|
|
93
|
+
* </Breadcrumb>
|
|
94
|
+
*/
|
|
95
|
+
//#endregion
|
|
96
|
+
export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator };
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=breadcrumb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"breadcrumb.js","names":[],"sources":["../../../src/components/ui/breadcrumb.tsx"],"sourcesContent":["/**\n * Breadcrumb — hierarchical location trail, plain markup (not a Radix primitive).\n *\n * An <ol> of BreadcrumbItem, ancestors as BreadcrumbLink and the current\n * page as a non-interactive BreadcrumbPage.\n */\n\nimport * as React from \"react\"\nimport { Slot } from \"radix-ui\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ChevronRightIcon, MoreHorizontalIcon } from \"lucide-react\"\n\nfunction Breadcrumb({ className, ...props }: React.ComponentProps<\"nav\">) {\n return (\n <nav\n aria-label=\"breadcrumb\"\n data-slot=\"breadcrumb\"\n className={cn(className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbList({ className, ...props }: React.ComponentProps<\"ol\">) {\n return (\n <ol\n data-slot=\"breadcrumb-list\"\n className={cn(\n \"flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground\",\n className\n )}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbItem({ className, ...props }: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-item\"\n className={cn(\"inline-flex items-center gap-1\", className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbLink({\n asChild,\n className,\n ...props\n}: React.ComponentProps<\"a\"> & {\n asChild?: boolean\n}) {\n const Comp = asChild ? Slot.Root : \"a\"\n\n return (\n <Comp\n data-slot=\"breadcrumb-link\"\n className={cn(\"transition-colors hover:text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbPage({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn(\"font-normal text-foreground\", className)}\n {...props}\n />\n )\n}\n\nfunction BreadcrumbSeparator({\n children,\n className,\n ...props\n}: React.ComponentProps<\"li\">) {\n return (\n <li\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\"[&>svg]:size-3.5\", className)}\n {...props}\n >\n {children ?? <ChevronRightIcon />}\n </li>\n )\n}\n\nfunction BreadcrumbEllipsis({\n className,\n ...props\n}: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn(\n \"flex size-5 items-center justify-center [&>svg]:size-4\",\n className\n )}\n {...props}\n >\n <MoreHorizontalIcon />\n <span className=\"sr-only\">More</span>\n </span>\n )\n}\n\nexport {\n Breadcrumb,\n BreadcrumbList,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbPage,\n BreadcrumbSeparator,\n BreadcrumbEllipsis,\n}\n\n/**\n * WHEN TO USE\n * - Showing position in a hierarchy at least two levels deep (e.g. Patients\n * › James Wilson), typically placed above a PageHeader title\n *\n * NOT WHEN\n * - Flat navigation with no hierarchy\n * - As a substitute for Tabs\n *\n * KEY RULES\n * - The current page is BreadcrumbPage — plain text, not a link\n * (aria-current=\"page\", aria-disabled)\n * - BreadcrumbEllipsis collapses a long trail; pair it with a\n * BreadcrumbSeparator on each side like any other item\n * - BreadcrumbLink supports asChild to render a router Link instead of <a>\n *\n * USAGE\n * <Breadcrumb>\n * <BreadcrumbList>\n * <BreadcrumbItem><BreadcrumbLink href=\"/patients\">Patients</BreadcrumbLink></BreadcrumbItem>\n * <BreadcrumbSeparator />\n * <BreadcrumbItem><BreadcrumbPage>James Wilson</BreadcrumbPage></BreadcrumbItem>\n * </BreadcrumbList>\n * </Breadcrumb>\n */\n"],"mappings":";;;;;;AAaA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,oBAAC,OAAD;EACE,cAAW;EACX,aAAU;EACV,WAAW,GAAG,SAAS;EACvB,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAqC;CAC3E,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,qFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAqC;CAC3E,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GAAG,kCAAkC,SAAS;EACzD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EACtB,SACA,WACA,GAAG,SAGF;CACD,MAAM,OAAO,UAAU,KAAK,OAAO;CAEnC,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;CAC7E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,MAAK;EACL,iBAAc;EACd,gBAAa;EACb,WAAW,GAAG,+BAA+B,SAAS;EACtD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAC3B,UACA,WACA,GAAG,SAC0B;CAC7B,OACE,oBAAC,MAAD;EACE,aAAU;EACV,MAAK;EACL,eAAY;EACZ,WAAW,GAAG,oBAAoB,SAAS;EAC3C,GAAI;EAEH,UAAA,YAAY,oBAAC,kBAAD,CAAmB,CAAA;CAC9B,CAAA;AAER;AAEA,SAAS,mBAAmB,EAC1B,WACA,GAAG,SAC4B;CAC/B,OACE,qBAAC,QAAD;EACE,aAAU;EACV,MAAK;EACL,eAAY;EACZ,WAAW,GACT,0DACA,SACF;EACA,GAAI;EARN,UAAA,CAUE,oBAAC,oBAAD,CAAqB,CAAA,GACrB,oBAAC,QAAD;GAAM,WAAU;GAAU,UAAA;EAAU,CAAA,CAChC;;AAEV"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BrowserTabs — persistent, closable document tabs, browser-style.
|
|
3
|
+
*
|
|
4
|
+
* The same Radix Tabs primitive `tabs.tsx` wraps, plus Popover for the "+"
|
|
5
|
+
* menu, Tooltip for truncated names, and Button for the per-tab close
|
|
6
|
+
* action — a different visual/interaction language from Tabs, not a
|
|
7
|
+
* variant of it: Tabs switches between named views of one entity (2-6 fixed
|
|
8
|
+
* tabs); this is for many independent, closable documents/views open at
|
|
9
|
+
* once (an IDE's editor tabs, a browser's own tab strip) — always
|
|
10
|
+
* horizontal, and always the topmost chrome of whatever surface it sits on.
|
|
11
|
+
* Each tab floats as a rounded pill on the strip's own bg-secondary track,
|
|
12
|
+
* flush against its bottom edge — the active tab's bg-card fill then
|
|
13
|
+
* touches the card content's own bg-card directly beneath it with no grey
|
|
14
|
+
* left in between, merging the two Chrome-style, rather than reading as a
|
|
15
|
+
* colored/selected state the way Tabs' own default variant does. Pinned
|
|
16
|
+
* tabs render icon-only — a fixed favicon-size square, falling back to a
|
|
17
|
+
* generic FileIcon when the tab itself has none — same as a real browser's
|
|
18
|
+
* own pinned tabs, and never part of the overflow behavior below. Once
|
|
19
|
+
* unpinned tabs stop fitting, they shrink together down to a floor, then
|
|
20
|
+
* the strip scrolls that pool horizontally past that — the same overflow
|
|
21
|
+
* model a real browser's own tab strip uses, not a "More" menu hiding the
|
|
22
|
+
* rest.
|
|
23
|
+
* An optional "+" pill at the strip's end, outside the scrolling region
|
|
24
|
+
* (`addViews` on BrowserTabsList) opens a popover of product-defined views
|
|
25
|
+
* the user can open as new tabs — a worklist's saved filters, for
|
|
26
|
+
* instance. `addTrigger`/`renderAddContent` swap its trigger or its
|
|
27
|
+
* popover content for something fully custom.
|
|
28
|
+
*/
|
|
29
|
+
import * as React from "react";
|
|
30
|
+
import { Tabs as TabsPrimitive } from "radix-ui";
|
|
31
|
+
import { TabsContent as BrowserTabsContent } from "../../components/ui/tabs";
|
|
32
|
+
declare function BrowserTabs({ className, value, defaultValue, onValueChange, ...props }: React.ComponentProps<typeof TabsPrimitive.Root>): React.JSX.Element;
|
|
33
|
+
/** One entry in the "+" popover — a product-defined view the user can open as a new tab. */
|
|
34
|
+
type BrowserTabsAddView = {
|
|
35
|
+
id: string;
|
|
36
|
+
label: string;
|
|
37
|
+
/** A leading icon, same convention as BrowserTab's own `icon`. */
|
|
38
|
+
icon?: React.ComponentType<{
|
|
39
|
+
className?: string;
|
|
40
|
+
}>;
|
|
41
|
+
/** A muted line of secondary metadata under the label — a description, a count, a last-modified date. Same convention as DataTable's `FilterOption.description`. */
|
|
42
|
+
description?: string;
|
|
43
|
+
disabled?: boolean;
|
|
44
|
+
/** A hint that this view should open as a pinned tab (`"user"`/`"product"`, same meaning as `BrowserTab`'s own `pin`) — shown here as a small pin icon trailing the label. Purely informational: this component doesn't open tabs itself, so acting on it (passing the matching `pin` to the `BrowserTab` you add in `onAddView`) is the consumer's job. */
|
|
45
|
+
pin?: "user" | "product";
|
|
46
|
+
};
|
|
47
|
+
declare function BrowserTabsList({ className, children, addViews, onAddView, addLabel, addTrigger, renderAddContent, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }: React.ComponentProps<typeof TabsPrimitive.List> & {
|
|
48
|
+
/** Product-defined views the user can open as new tabs — rendered in the "+" pill's default popover list. Omit entirely (with `renderAddContent` covering the "+" pill's content instead) for a fully custom popover. Opening is the consumer's job — `onAddView` only reports the pick; add the tab to your own list (or, if that view is already open, just activate it). A view's own `pin` is a hint for *that*: open it pinned (`"user"`/`"product"`, same meaning as `BrowserTab`'s own `pin`) rather than as a regular tab — shown as a small pin icon next to it here, not enforced by this component. */
|
|
49
|
+
addViews?: BrowserTabsAddView[];
|
|
50
|
+
/** Fires with the picked view; the popover closes itself. */
|
|
51
|
+
onAddView?: (view: BrowserTabsAddView) => void;
|
|
52
|
+
/** Accessible name of the "+" pill (it's icon-only). Defaults to "Open a view in a new tab". Ignored when `addTrigger` is given — that node is responsible for its own accessible name. */
|
|
53
|
+
addLabel?: string;
|
|
54
|
+
/** A custom trigger in place of the default icon-only "+" pill — still opens the same popover (`addViews`' list, or `renderAddContent`). Needs its own accessible name (a plain icon button still needs `aria-label`, same as any custom Popover trigger). */
|
|
55
|
+
addTrigger?: React.ReactNode;
|
|
56
|
+
/** Replaces the "+" popover's default views list with fully custom content — a search box, a grouped menu, anything. Called with `close` to dismiss the popover from inside it (the default list's own item clicks do this automatically; custom content must call it itself). Takes over the popover entirely: `addViews`/`onAddView` don't render alongside it. */
|
|
57
|
+
renderAddContent?: (close: () => void) => React.ReactNode;
|
|
58
|
+
}): React.JSX.Element;
|
|
59
|
+
type BrowserTabProps = {
|
|
60
|
+
value: string;
|
|
61
|
+
/** A leading icon (e.g. a favicon-style entity icon) — rendered outside the truncating label, so it's never clipped. */
|
|
62
|
+
icon?: React.ComponentType<{
|
|
63
|
+
className?: string;
|
|
64
|
+
}>;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
/** Groups this tab into the strip's pinned section, ahead of a divider from the rest. "user" tabs were pinned by the user and can still take `onClose` (closing is how the user unpins/removes them); "product" tabs are pinned by the product and never render a close button, regardless of `onClose`. */
|
|
67
|
+
pin?: "user" | "product";
|
|
68
|
+
/** Omit to render this tab with no close button — e.g. a pinned tab that can't be dismissed. Ignored when `pin="product"`. The close button is hover/focus-revealed over the end of the name (which truncates underneath it), so the tab is content-width at rest and never changes width on hover; it's also offered as "Close" in the tab's right-click menu. */
|
|
69
|
+
onClose?: () => void;
|
|
70
|
+
/** Accessible label for the close button. Defaults to "Close {children}" when `children` is a plain string; pass this explicitly when it isn't (an icon, a custom node). */
|
|
71
|
+
closeLabel?: string;
|
|
72
|
+
/** Enables "Pin tab" / "Unpin tab" in this tab's right-click menu (the item is always shown, disabled without a handler or on a `pin="product"` tab). Fires regardless of direction; read the tab's own current `pin` to decide whether you're pinning or unpinning it, then move it into (or to the front of) the appropriate section — BrowserTabs only renders what you give it, it doesn't reorder your list. There is no visible pin button on the tab itself. */
|
|
73
|
+
onPinToggle?: () => void;
|
|
74
|
+
/** Enables "Close other tabs" in this tab's right-click menu (the item is always shown, disabled without a handler). Like `onClose`, it only reports the intent — close every other UNPINNED tab in your own list and keep this one active. Pinned tabs (`pin="user"` or `"product"`) are never closed by "close others"; the user pinned them precisely so they'd survive that. */
|
|
75
|
+
onCloseOthers?: () => void;
|
|
76
|
+
className?: string;
|
|
77
|
+
children: React.ReactNode;
|
|
78
|
+
};
|
|
79
|
+
declare function BrowserTab(props: BrowserTabProps): React.JSX.Element;
|
|
80
|
+
export { BrowserTabs, BrowserTabsList, BrowserTab, BrowserTabsContent };
|
|
81
|
+
export type { BrowserTabsAddView };
|
|
82
|
+
/**
|
|
83
|
+
* WHEN TO USE
|
|
84
|
+
* - Many independent, addable/closable documents or views open at once —
|
|
85
|
+
* an IDE's editor tabs, a browser's own tab strip, a multi-record
|
|
86
|
+
* workspace where each record opens in its own tab.
|
|
87
|
+
* - Always as the topmost chrome of whatever surface hosts it (a Card,
|
|
88
|
+
* a page shell) — it's edge-to-edge and expects to sit flush at that
|
|
89
|
+
* surface's top.
|
|
90
|
+
*
|
|
91
|
+
* NOT WHEN
|
|
92
|
+
* - Switching between a fixed 2-6 named views of *one* entity (an
|
|
93
|
+
* Overview/History/Notes split) — use Tabs instead; it reads as
|
|
94
|
+
* neutral navigation, not as separate closable documents.
|
|
95
|
+
* - Vertical tab placement — not supported; always horizontal.
|
|
96
|
+
*
|
|
97
|
+
* KEY RULES
|
|
98
|
+
* - Composition mirrors Tabs: `BrowserTabs` (Root, controlled or
|
|
99
|
+
* uncontrolled via `value`/`onValueChange`/`defaultValue`) wraps
|
|
100
|
+
* `BrowserTabsList` (the strip) and one `BrowserTabsContent` per tab
|
|
101
|
+
* (re-exported directly from Tabs — same primitive, nothing about it
|
|
102
|
+
* is strip-specific).
|
|
103
|
+
* - `pin`: omit for a normal tab, `"user"` for one the user pinned
|
|
104
|
+
* (closable — closing is how they unpin it), `"product"` for one the
|
|
105
|
+
* product configured (never closable, no close button rendered even if
|
|
106
|
+
* `onClose` is passed). Pinned tabs of either kind render first, in a
|
|
107
|
+
* section separated from the rest by a divider, and are never subject
|
|
108
|
+
* to the overflow behavior below.
|
|
109
|
+
* - Pinned tabs render icon-only — a fixed favicon-size square, same as a
|
|
110
|
+
* real browser's own pinned tabs — falling back to `FileIcon`
|
|
111
|
+
* when the tab itself has no `icon`, so a pinned tab is never blank.
|
|
112
|
+
* The full name still surfaces via Tooltip on hover/focus; there's no
|
|
113
|
+
* hover-revealed close button at that width, so unpinning/closing goes
|
|
114
|
+
* through the right-click menu or Delete/Backspace on the focused tab.
|
|
115
|
+
* - Every tab has the same three-item right-click menu (ContextMenu):
|
|
116
|
+
* "Pin tab"/"Unpin tab", "Close", and "Close other tabs" — always
|
|
117
|
+
* visible, each disabled when the tab wasn't given the matching
|
|
118
|
+
* handler. `onPinToggle` drives the first (read the tab's current `pin`
|
|
119
|
+
* to know the direction, then move it into — or, unpinning, to the
|
|
120
|
+
* front of — the right section in your own list; always disabled on
|
|
121
|
+
* `pin="product"`), `onClose` the second, `onCloseOthers` the third
|
|
122
|
+
* (close every other UNPINNED tab yourself and keep this one active —
|
|
123
|
+
* "close others" never closes a pinned tab of either kind; pinning is
|
|
124
|
+
* exactly the promise that a tab survives bulk closing).
|
|
125
|
+
* No visible pin button on the tab; pinning is menu-only, and pinned
|
|
126
|
+
* tabs are identified by sitting in the pinned section ahead of the
|
|
127
|
+
* divider.
|
|
128
|
+
* - Each `BrowserTab` needs its own `onClose` to get a close button at
|
|
129
|
+
* all — omit it for a tab that can't be dismissed. A tab is exactly as
|
|
130
|
+
* wide as its name at rest (nothing reserved on the right); on hover
|
|
131
|
+
* the close button appears over the end of the name, which truncates
|
|
132
|
+
* underneath it, so the tab's width never changes between rest and
|
|
133
|
+
* hover. That button is pointer-only (a focusable control can't sit
|
|
134
|
+
* inside a `role="tab"`): keyboard users press Delete or Backspace on
|
|
135
|
+
* the focused tab, or use the right-click menu's "Close".
|
|
136
|
+
* - Closing a tab is entirely the consumer's responsibility: `onClose`
|
|
137
|
+
* only reports the intent. Removing it from whatever list backs your
|
|
138
|
+
* tabs, and deciding which tab becomes active next, is app logic this
|
|
139
|
+
* component has no way to know on its own.
|
|
140
|
+
* - Overflow is browser-style, not a "More" menu: once unpinned tabs stop
|
|
141
|
+
* fitting the available width, they shrink together (flex-shrink) down
|
|
142
|
+
* to `min-w-16` (64px) each; past that floor the strip scrolls that
|
|
143
|
+
* pool horizontally instead of shrinking further. Pinned tabs are
|
|
144
|
+
* already fixed-size icon-only squares (see above), so they never
|
|
145
|
+
* shrink, grow, or join the scrolling region. The active tab scrolls
|
|
146
|
+
* into view
|
|
147
|
+
* automatically whenever it changes, so switching tabs never leaves the
|
|
148
|
+
* newly-active one scrolled out of sight. Only the "+" pill is truly
|
|
149
|
+
* fixed-size, living outside the shrink pool entirely. A soft inset
|
|
150
|
+
* shadow fades in on
|
|
151
|
+
* whichever edge(s) still have more tabs scrolled past them (both at
|
|
152
|
+
* once, mid-strip) and disappears once there's nothing left that way —
|
|
153
|
+
* a direction-aware cue, not a static "this can scroll" marker.
|
|
154
|
+
* - A tab's name overflowing `max-w-52` is truncated in the strip but
|
|
155
|
+
* shown in full in a Tooltip on hover/focus.
|
|
156
|
+
* - `addViews` on `BrowserTabsList` adds a "+" pill that opens a popover of
|
|
157
|
+
* product-defined views the user can open as new tabs — a worklist's
|
|
158
|
+
* saved filters, a set of report layouts — `{ id, label, icon?,
|
|
159
|
+
* description?, disabled?, pin? }` each. Sits immediately after the
|
|
160
|
+
* last tab at rest; pins to the strip's own right edge once the tabs
|
|
161
|
+
* overflow into their shrink/scroll region instead, same as a real
|
|
162
|
+
* browser's "+" button. Each is the same full-width tab pill (icon +
|
|
163
|
+
* label) it will become as a tab; `description` grows that row to a
|
|
164
|
+
* second, muted line underneath (a filter's own scope, a last-modified
|
|
165
|
+
* date). Past `ADD_VIEWS_SEARCH_THRESHOLD` (6) views the popover grows
|
|
166
|
+
* a search box filtering by label and description. A `pin` hint renders
|
|
167
|
+
* a small pin icon trailing the label (purely visual — opening it
|
|
168
|
+
* pinned is still your own `onAddView` handler's job). `onAddView` only
|
|
169
|
+
* reports the pick: add a tab for that view to your own list and make
|
|
170
|
+
* it active — or, if that view is already open, just activate the
|
|
171
|
+
* existing tab instead of opening a duplicate. Icon-only by default;
|
|
172
|
+
* `addLabel` names it for assistive tech (default "Open a view in a new
|
|
173
|
+
* tab"). `addTrigger` swaps in a custom trigger node in place of the
|
|
174
|
+
* default "+" pill (still needs its own `aria-label`). `renderAddContent`
|
|
175
|
+
* replaces the *entire* popover body — search box, view list, and all —
|
|
176
|
+
* with something fully custom (a grouped menu, anything) — called with
|
|
177
|
+
* a `close` function to dismiss the popover
|
|
178
|
+
* from inside it; `addViews`/`onAddView` don't render alongside it.
|
|
179
|
+
* - Each `BrowserTab` floats as a rounded pill inset from the strip's
|
|
180
|
+
* `bg-secondary` track. Unlike Tabs' own default variant (a translucent
|
|
181
|
+
* `bg-primary/10` fill), the active tab here reads as merged into the
|
|
182
|
+
* card below it, Chrome-style: `bg-card`/`text-card-foreground` (matching
|
|
183
|
+
* the content surface exactly) plus squared-off bottom corners, sitting
|
|
184
|
+
* flush against the track's own bottom edge with nothing grey left
|
|
185
|
+
* between tab and content. Inactive tabs just fill `bg-muted` on hover
|
|
186
|
+
* and otherwise float clear of the track's edges.
|
|
187
|
+
* - A leading icon uses `icon`, not the `data-icon="inline-start"` slot
|
|
188
|
+
* convention Button/Tabs use — it needs to sit outside the label's own
|
|
189
|
+
* truncation, which a plain child node sharing that flex row wouldn't.
|
|
190
|
+
*
|
|
191
|
+
* USAGE
|
|
192
|
+
* <BrowserTabs value={activeId} onValueChange={setActiveId}>
|
|
193
|
+
* <BrowserTabsList
|
|
194
|
+
* addViews={worklistViews} // [{ id: "overdue", label: "Overdue", icon: ClockIcon }, ...]
|
|
195
|
+
* onAddView={(view) => openViewTab(view)} // add to openDocs (or activate if already open)
|
|
196
|
+
* >
|
|
197
|
+
* <BrowserTab value="home" pin="product">Home</BrowserTab>
|
|
198
|
+
* {openDocs.map((doc) => (
|
|
199
|
+
* <BrowserTab
|
|
200
|
+
* key={doc.id}
|
|
201
|
+
* value={doc.id}
|
|
202
|
+
* icon={doc.icon}
|
|
203
|
+
* pin={doc.pinnedByUser ? "user" : undefined}
|
|
204
|
+
* onClose={() => closeDoc(doc.id)}
|
|
205
|
+
* >
|
|
206
|
+
* {doc.title}
|
|
207
|
+
* </BrowserTab>
|
|
208
|
+
* ))}
|
|
209
|
+
* </BrowserTabsList>
|
|
210
|
+
* <BrowserTabsContent value="home">...</BrowserTabsContent>
|
|
211
|
+
* {openDocs.map((doc) => (
|
|
212
|
+
* <BrowserTabsContent key={doc.id} value={doc.id}>
|
|
213
|
+
* <DocView doc={doc} />
|
|
214
|
+
* </BrowserTabsContent>
|
|
215
|
+
* ))}
|
|
216
|
+
* </BrowserTabs>
|
|
217
|
+
*/
|
|
218
|
+
//# sourceMappingURL=browser-tabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-tabs.d.ts","sourceRoot":"","sources":["../../../src/components/ui/browser-tabs.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,IAAI,IAAI,aAAa,EAAE,MAAM,UAAU,CAAA;AA8BhD,OAAO,EAAE,WAAW,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AAYxE,iBAAS,WAAW,CAAC,EACnB,SAAS,EACT,KAAK,EACL,YAAY,EACZ,aAAa,EACb,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC,qBAyBjD;AAgCD,4FAA4F;AAC5F,KAAK,kBAAkB,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,kEAAkE;IAClE,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClD,oKAAoK;IACpK,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,4VAA4V;IAC5V,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACzB,CAAA;AAoBD,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAqC,EACrC,UAAU,EACV,gBAAgB,EAChB,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,aAAa,CAAC,IAAI,CAAC,GAAG;IACnD,klBAAklB;IACllB,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC/B,6DAA6D;IAC7D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAC9C,2LAA2L;IAC3L,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8PAA8P;IAC9P,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC5B,qWAAqW;IACrW,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC,SAAS,CAAA;CAC1D,qBA2QA;AAkJD,KAAK,eAAe,GAAG;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,wHAAwH;IACxH,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,4SAA4S;IAC5S,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,mWAAmW;IACnW,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,4KAA4K;IAC5K,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,ucAAuc;IACvc,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB,oXAAoX;IACpX,aAAa,CAAC,EAAE,MAAM,IAAI,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,CAAA;AAqXD,iBAAS,UAAU,CAAC,KAAK,EAAE,eAAe,qBAazC;AAED,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAA;AACvE,YAAY,EAAE,kBAAkB,EAAE,CAAA;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuIG"}
|