banhaten 0.1.1 → 0.1.2

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.
Files changed (37) hide show
  1. package/README.md +20 -8
  2. package/package.json +8 -2
  3. package/registry/components/autocomplete.tsx +637 -0
  4. package/registry/components/avatar.tsx +258 -22
  5. package/registry/components/badge.tsx +97 -35
  6. package/registry/components/date-picker-state.ts +253 -0
  7. package/registry/components/date-picker.tsx +115 -158
  8. package/registry/components/expanded/EmptyState.tsx +155 -0
  9. package/registry/components/expanded/emptyState.css +111 -0
  10. package/registry/components/expanded/slideout.css +1 -0
  11. package/registry/components/expanded/table.css +1 -0
  12. package/registry/components/input-otp.tsx +574 -0
  13. package/registry/components/input.tsx +21 -11
  14. package/registry/components/menu.tsx +371 -8
  15. package/registry/components/popover.tsx +840 -0
  16. package/registry/components/select.tsx +4 -0
  17. package/registry/components/skeleton.css +57 -0
  18. package/registry/components/skeleton.tsx +482 -0
  19. package/registry/components/spinner.tsx +79 -11
  20. package/registry/components/textarea.tsx +1 -1
  21. package/registry/components/tooltip.tsx +4 -0
  22. package/registry/examples/autocomplete-demo.tsx +109 -0
  23. package/registry/examples/avatar-demo.tsx +102 -47
  24. package/registry/examples/badge-demo.tsx +16 -0
  25. package/registry/examples/expanded/command-bar-demo.tsx +236 -0
  26. package/registry/examples/expanded/empty-state-demo.tsx +39 -0
  27. package/registry/examples/input-demo.tsx +1 -1
  28. package/registry/examples/input-otp-demo.tsx +72 -0
  29. package/registry/examples/menu-demo.tsx +101 -88
  30. package/registry/examples/popover-demo.tsx +546 -0
  31. package/registry/examples/select-demo.tsx +1 -1
  32. package/registry/examples/skeleton-demo.tsx +56 -0
  33. package/registry/examples/spinner-demo.tsx +23 -1
  34. package/registry/examples/textarea-demo.tsx +1 -1
  35. package/registry/index.json +240 -8
  36. package/registry/styles/globals.css +88 -0
  37. package/src/cli/index.js +997 -62
@@ -24,6 +24,8 @@ const defaultTooltipSupportText =
24
24
  // Radix sideOffset requires numbers; these mirror the tooltip spacing aliases.
25
25
  const TOOLTIP_POINTER_SIDE_OFFSET_PX = 7
26
26
  const TOOLTIP_POINTERLESS_SIDE_OFFSET_PX = 6
27
+ // Radix collisionPadding requires a number; this mirrors --bh-space-md-8.
28
+ const TOOLTIP_COLLISION_PADDING_PX = 8
27
29
 
28
30
  const tooltipContentVariants = cva(
29
31
  [
@@ -87,6 +89,7 @@ const TooltipContent = React.forwardRef<
87
89
  children,
88
90
  className,
89
91
  closeLabel,
92
+ collisionPadding = TOOLTIP_COLLISION_PADDING_PX,
90
93
  onCloseClick,
91
94
  pointerPosition = "top-left",
92
95
  shortcut,
@@ -127,6 +130,7 @@ const TooltipContent = React.forwardRef<
127
130
  ref={ref}
128
131
  side={side ?? placement.side}
129
132
  align={align ?? placement.align}
133
+ collisionPadding={collisionPadding}
130
134
  sideOffset={
131
135
  sideOffset ??
132
136
  (shouldShowPointer
@@ -0,0 +1,109 @@
1
+ import { Autocomplete } from "@/components/ui/autocomplete"
2
+
3
+ const peopleOptions = [
4
+ {
5
+ value: "ahmed",
6
+ label: "Ahmed Galal",
7
+ addonText: "Design system",
8
+ itemType: "avatar" as const,
9
+ keywords: ["foundations", "tokens"],
10
+ },
11
+ {
12
+ value: "nora",
13
+ label: "Nora Ali",
14
+ addonText: "Product",
15
+ itemType: "avatar" as const,
16
+ keywords: ["roadmap", "research"],
17
+ },
18
+ {
19
+ value: "layla",
20
+ label: "Layla Hassan",
21
+ addonText: "Engineering",
22
+ itemType: "avatar" as const,
23
+ keywords: ["frontend", "platform"],
24
+ },
25
+ {
26
+ value: "omar",
27
+ label: "Omar Saleh",
28
+ addonText: "Unavailable",
29
+ itemType: "avatar" as const,
30
+ disabled: true,
31
+ },
32
+ ]
33
+
34
+ const projectOptions = [
35
+ { value: "tokens", label: "Token audit", addonText: "In review", itemType: "dot" as const },
36
+ { value: "inputs", label: "Input system", addonText: "Ready", itemType: "dot" as const },
37
+ { value: "tables", label: "Table promotion", addonText: "Planned", itemType: "dot" as const },
38
+ { value: "forms", label: "Form patterns", addonText: "Discovery", itemType: "dot" as const },
39
+ ]
40
+
41
+ const rtlOptions = [
42
+ {
43
+ value: "ahmed",
44
+ label: "أحمد جلال",
45
+ addonText: "النظام",
46
+ itemType: "avatar" as const,
47
+ },
48
+ {
49
+ value: "nora",
50
+ label: "نورا علي",
51
+ addonText: "المنتج",
52
+ itemType: "avatar" as const,
53
+ },
54
+ {
55
+ value: "layla",
56
+ label: "ليلى حسن",
57
+ addonText: "الهندسة",
58
+ itemType: "avatar" as const,
59
+ },
60
+ ]
61
+
62
+ export function AutocompleteDemo() {
63
+ return (
64
+ <div className="grid w-full gap-5 lg:grid-cols-2">
65
+ <div className="grid min-w-0 content-start gap-5">
66
+ <Autocomplete
67
+ className="mb-[var(--bh-space-13xl-160)]"
68
+ defaultOpen
69
+ defaultValue="ahmed"
70
+ helperText="Search by name, team, or keyword."
71
+ label="Owner"
72
+ options={peopleOptions}
73
+ placeholder="Search people"
74
+ />
75
+
76
+ <Autocomplete
77
+ defaultValue={["tokens", "inputs"]}
78
+ helperText="Selected values render with the Tag component."
79
+ label="Related work"
80
+ options={projectOptions}
81
+ placeholder="Add projects"
82
+ selectionMode="multiple"
83
+ />
84
+ </div>
85
+
86
+ <div className="grid min-w-0 content-start gap-5">
87
+ <Autocomplete
88
+ label="Project"
89
+ options={projectOptions}
90
+ placeholder="Search projects"
91
+ variant="soft"
92
+ />
93
+
94
+ <div dir="rtl" className="min-w-0">
95
+ <Autocomplete
96
+ className="pb-[var(--bh-space-13xl-160)] lg:pb-0"
97
+ defaultOpen
98
+ defaultValue="nora"
99
+ dir="rtl"
100
+ helperText="ابحث بالاسم أو الفريق."
101
+ label="المالك"
102
+ options={rtlOptions}
103
+ placeholder="ابحث عن شخص"
104
+ />
105
+ </div>
106
+ </div>
107
+ </div>
108
+ )
109
+ }
@@ -1,73 +1,128 @@
1
- import { PlusIcon } from "lucide-react"
2
-
3
1
  import {
4
2
  Avatar,
5
- AvatarBadge,
3
+ AvatarAction,
6
4
  AvatarFallback,
7
5
  AvatarGroup,
8
6
  AvatarGroupCount,
7
+ AvatarIcon,
9
8
  AvatarImage,
9
+ AvatarStatus,
10
10
  } from "@/components/ui/avatar"
11
+ import { PlusIcon } from "lucide-react"
11
12
 
12
13
  const avatarUrl = new URL("../assets/avatars/avatar-01.jpg", import.meta.url).href
13
14
 
15
+ const statusColumns = [
16
+ "available",
17
+ "available",
18
+ "busy",
19
+ "away",
20
+ "blocked",
21
+ ] as const
22
+
23
+ const secondaryStatusColumns = [
24
+ "offline",
25
+ "available",
26
+ "busy",
27
+ "away",
28
+ "blocked",
29
+ ] as const
30
+
14
31
  export function AvatarDemo() {
15
32
  return (
16
- <div className="flex flex-col gap-6">
17
- <div className="flex flex-wrap items-center gap-4">
18
- <Avatar>
33
+ <div className="flex flex-col gap-7">
34
+ <div className="grid w-fit grid-cols-5 gap-x-4 gap-y-4">
35
+ {statusColumns.map((status, index) => (
36
+ <Avatar key={`icon-${status}-${index}`} size="2xl">
37
+ <AvatarIcon />
38
+ {index === 0 ? <AvatarAction type="edit" size="medium" /> : null}
39
+ <AvatarStatus status={status} size="small" />
40
+ </Avatar>
41
+ ))}
42
+
43
+ {secondaryStatusColumns.map((status) => (
44
+ <Avatar key={`initials-${status}`} size="2xl">
45
+ <AvatarFallback>AG</AvatarFallback>
46
+ <AvatarStatus status={status} size="small" />
47
+ </Avatar>
48
+ ))}
49
+
50
+ {secondaryStatusColumns.map((status) => (
51
+ <Avatar key={`image-${status}`} size="2xl">
52
+ <AvatarImage src={avatarUrl} alt="Profile portrait" />
53
+ <AvatarFallback>AG</AvatarFallback>
54
+ <AvatarStatus status={status} size="small" />
55
+ </Avatar>
56
+ ))}
57
+ </div>
58
+
59
+ <div className="flex flex-wrap items-center gap-5 ps-7">
60
+ <Avatar size="2xl">
19
61
  <AvatarImage src={avatarUrl} alt="Profile portrait" />
20
- <AvatarFallback>CN</AvatarFallback>
62
+ <AvatarFallback>AG</AvatarFallback>
63
+ <AvatarAction type="edit" size="medium" />
21
64
  </Avatar>
22
- <Avatar>
23
- <AvatarFallback>ER</AvatarFallback>
65
+ <Avatar size="2xl">
66
+ <AvatarImage src={avatarUrl} alt="Profile portrait" />
67
+ <AvatarFallback>AG</AvatarFallback>
68
+ <AvatarAction type="remove" size="medium" />
24
69
  </Avatar>
25
- <Avatar>
26
- <AvatarImage src="/missing-avatar.png" alt="Missing image" />
27
- <AvatarFallback>LR</AvatarFallback>
70
+ <Avatar size="2xl">
71
+ <AvatarImage src={avatarUrl} alt="Profile portrait" />
72
+ <AvatarFallback>AG</AvatarFallback>
73
+ <AvatarAction type="verified" size="medium" />
28
74
  </Avatar>
29
75
  </div>
30
76
 
31
- <div className="flex flex-wrap items-center gap-4">
32
- <Avatar>
33
- <AvatarImage src={avatarUrl} alt="Profile portrait" />
34
- <AvatarFallback>CN</AvatarFallback>
35
- <AvatarBadge />
36
- </Avatar>
37
- <Avatar>
38
- <AvatarFallback>PP</AvatarFallback>
39
- <AvatarBadge className="size-5 bg-success">
40
- <PlusIcon className="size-3" />
41
- </AvatarBadge>
77
+ <div className="flex items-center gap-3">
78
+ <AvatarGroup>
79
+ {Array.from({ length: 7 }).map((_, index) => (
80
+ <Avatar key={index} size="md">
81
+ <AvatarImage src={avatarUrl} alt="" />
82
+ <AvatarFallback>AG</AvatarFallback>
83
+ </Avatar>
84
+ ))}
85
+ <AvatarGroupCount size="md">+10</AvatarGroupCount>
86
+ </AvatarGroup>
87
+ <Avatar
88
+ aria-label="Add member"
89
+ className="border border-dashed border-[var(--bh-border-subtle)] bg-[var(--bh-bg-default)] text-[var(--bh-content-subtle)]"
90
+ size="md"
91
+ >
92
+ <PlusIcon aria-hidden="true" className="size-4" />
42
93
  </Avatar>
43
94
  </div>
44
95
 
45
- <AvatarGroup>
46
- <Avatar>
47
- <AvatarFallback>CN</AvatarFallback>
96
+ <div className="flex items-center gap-3">
97
+ <Avatar size="xl">
98
+ <AvatarImage src={avatarUrl} alt="John Doe" />
99
+ <AvatarFallback>JD</AvatarFallback>
100
+ <AvatarStatus status="available" size="small" />
48
101
  </Avatar>
49
- <Avatar>
50
- <AvatarFallback>LR</AvatarFallback>
51
- </Avatar>
52
- <Avatar>
53
- <AvatarFallback>ER</AvatarFallback>
54
- </Avatar>
55
- <AvatarGroupCount>+3</AvatarGroupCount>
56
- </AvatarGroup>
102
+ <div className="min-w-0">
103
+ <p className="text-sm font-semibold text-[var(--bh-content-default)]">
104
+ John Doe
105
+ </p>
106
+ <p className="text-sm text-[var(--bh-content-subtle)]">
107
+ johndoe@example.com
108
+ </p>
109
+ </div>
110
+ </div>
57
111
 
58
- <div dir="rtl">
59
- <AvatarGroup>
60
- <Avatar>
61
- <AvatarFallback>ح</AvatarFallback>
62
- </Avatar>
63
- <Avatar>
64
- <AvatarFallback>ن</AvatarFallback>
65
- </Avatar>
66
- <Avatar>
67
- <AvatarFallback>م</AvatarFallback>
68
- </Avatar>
69
- <AvatarGroupCount>+٣</AvatarGroupCount>
70
- </AvatarGroup>
112
+ <div className="flex items-center gap-3">
113
+ <Avatar size="md">
114
+ <AvatarImage src={avatarUrl} alt="John Doe" />
115
+ <AvatarFallback>JD</AvatarFallback>
116
+ <AvatarStatus status="available" size="tiny" />
117
+ </Avatar>
118
+ <div className="min-w-0">
119
+ <p className="text-sm font-semibold text-[var(--bh-content-default)]">
120
+ John Doe
121
+ </p>
122
+ <p className="text-xs text-[var(--bh-content-subtle)]">
123
+ johndoe@example.com
124
+ </p>
125
+ </div>
71
126
  </div>
72
127
  </div>
73
128
  )
@@ -2,6 +2,7 @@ import {
2
2
  ArrowUpRightIcon,
3
3
  BadgeCheckIcon,
4
4
  BookmarkIcon,
5
+ ChevronRightIcon,
5
6
  } from "lucide-react"
6
7
 
7
8
  import { Badge } from "@/components/ui/badge"
@@ -48,6 +49,21 @@ export function BadgeDemo() {
48
49
  <ArrowUpRightIcon data-icon="inline-end" data-rtl-flip="true" />
49
50
  </a>
50
51
  </Badge>
52
+ <Badge
53
+ asChild
54
+ color="blue"
55
+ splitAction
56
+ type="trailing-icon"
57
+ >
58
+ <a href="#badge">
59
+ In progress
60
+ <ChevronRightIcon
61
+ aria-hidden="true"
62
+ data-icon="inline-end"
63
+ data-rtl-flip="true"
64
+ />
65
+ </a>
66
+ </Badge>
51
67
  </div>
52
68
  )
53
69
  }
@@ -1,5 +1,101 @@
1
+ import * as React from "react"
2
+ import {
3
+ BoxIcon,
4
+ CheckIcon,
5
+ CloudIcon,
6
+ EyeIcon,
7
+ FileTextIcon,
8
+ GitPullRequestIcon,
9
+ LayoutGridIcon,
10
+ MessageSquareIcon,
11
+ PencilIcon,
12
+ RefreshCcwIcon,
13
+ SearchIcon,
14
+ Settings2Icon,
15
+ ShieldCheckIcon,
16
+ WorkflowIcon,
17
+ XIcon,
18
+ } from "lucide-react"
19
+
20
+ import { Avatar, AvatarIcon, AvatarStatus } from "@/components/ui/avatar"
21
+ import { Badge } from "@/components/ui/badge"
22
+ import { Button } from "@/components/ui/button"
23
+ import {
24
+ Menu,
25
+ MenuItem,
26
+ MenuItemDescription,
27
+ MenuItemText,
28
+ MenuItemTitle,
29
+ } from "@/components/ui/menu"
30
+ import { ModalBody, ModalHeader, ModalSurface } from "@/components/ui/modal"
31
+ import {
32
+ Toolbar,
33
+ ToolbarButton,
34
+ ToolbarSearch,
35
+ ToolbarSection,
36
+ } from "@/components/ui/toolbar"
1
37
  import { CommandBar } from "@/components/ui/expanded/CommandBar"
2
38
 
39
+ type ToolTone = "neutral" | "blue" | "green" | "amber" | "purple" | "sky"
40
+ type ToolIcon = React.ComponentType<React.SVGProps<SVGSVGElement>>
41
+
42
+ type ToolItem = {
43
+ added?: boolean
44
+ description?: string
45
+ icon: ToolIcon
46
+ title: string
47
+ tone?: ToolTone
48
+ }
49
+
50
+ const popularTools: ToolItem[] = [
51
+ {
52
+ added: true,
53
+ icon: EyeIcon,
54
+ title: "View repositories & issues",
55
+ tone: "green",
56
+ },
57
+ {
58
+ description: "Create, comment, update issues",
59
+ icon: PencilIcon,
60
+ title: "Create & update issues",
61
+ },
62
+ {
63
+ description: "Use commit and repo activity",
64
+ icon: RefreshCcwIcon,
65
+ title: "Sync commits and activity",
66
+ },
67
+ {
68
+ description: "Review and update pull requests",
69
+ icon: GitPullRequestIcon,
70
+ title: "Manage pull requests",
71
+ },
72
+ {
73
+ description: "Run GitHub workflows",
74
+ icon: WorkflowIcon,
75
+ title: "Trigger workflows & automations",
76
+ },
77
+ ]
78
+
79
+ const serverTools: ToolItem[] = [
80
+ { icon: BoxIcon, title: "Box", tone: "blue" },
81
+ { icon: CloudIcon, title: "Google Drive", tone: "green" },
82
+ { icon: Settings2Icon, title: "Hubspot", tone: "amber" },
83
+ { icon: MessageSquareIcon, title: "Intercom", tone: "sky" },
84
+ { icon: WorkflowIcon, title: "Jira", tone: "blue" },
85
+ { icon: FileTextIcon, title: "Notion" },
86
+ { icon: ShieldCheckIcon, title: "Okta" },
87
+ { icon: CloudIcon, title: "Salesforce", tone: "sky" },
88
+ ]
89
+
90
+ const toolToneClassNames: Record<ToolTone, string> = {
91
+ amber: "text-[var(--bh-content-accent-amber-default)]",
92
+ blue: "text-[var(--bh-content-accent-blue-default)]",
93
+ green: "text-[var(--bh-content-accent-green-default)]",
94
+ neutral: "text-[var(--bh-content-subtle)]",
95
+ purple: "text-[var(--bh-content-accent-purple-default)]",
96
+ sky: "text-[var(--bh-content-accent-sky-default)]",
97
+ }
98
+
3
99
  export function CommandBarDemo() {
4
100
  return (
5
101
  <div className="grid gap-6">
@@ -8,3 +104,143 @@ export function CommandBarDemo() {
8
104
  </div>
9
105
  )
10
106
  }
107
+
108
+ export function AddToolPickerExample() {
109
+ return (
110
+ <ModalSurface
111
+ aria-label="Add tool command example"
112
+ className={[
113
+ "[--bh-modal-width:calc(var(--bh-space-19xl-384)+var(--bh-space-18xl-320)+var(--bh-space-8xl-48))]",
114
+ "rounded-[var(--bh-radius-6xl-28)]",
115
+ ].join(" ")}
116
+ size="lg"
117
+ >
118
+ <ModalHeader className="items-start justify-between px-[var(--bh-space-5xl-24)] pb-[var(--bh-space-lg-10)] pe-[var(--bh-space-5xl-24)] pt-[var(--bh-space-5xl-24)]">
119
+ <h2 className="min-w-0 flex-1 text-start text-[length:var(--bh-text-heading-sm-semibold-font-size)] font-[var(--bh-text-heading-sm-semibold-font-weight)] leading-[var(--bh-text-heading-sm-semibold-line-height)] tracking-[var(--bh-text-heading-sm-semibold-letter-spacing)] text-[var(--bh-content-default)]">
120
+ Add tool
121
+ </h2>
122
+ <Button aria-label="Close add tool" size="icon" type="button" variant="ghost">
123
+ <XIcon aria-hidden="true" />
124
+ </Button>
125
+ </ModalHeader>
126
+
127
+ <ModalBody className="grid w-full gap-[var(--bh-space-4xl-20)] px-[var(--bh-space-5xl-24)] pb-[var(--bh-space-6xl-32)] pt-0">
128
+ <ToolbarSearch
129
+ aria-label="Search tools"
130
+ icon={<SearchIcon aria-hidden="true" />}
131
+ placeholder="Search..."
132
+ width="full"
133
+ />
134
+
135
+ <Toolbar aria-label="Tool source filters" className="overflow-x-auto" wrap>
136
+ <ToolbarSection wrap>
137
+ <ToolCategory icon={Settings2Icon}>All</ToolCategory>
138
+ <ToolCategory icon={LayoutGridIcon}>Apps</ToolCategory>
139
+ <ToolCategory active icon={LayoutGridIcon}>
140
+ MCP
141
+ </ToolCategory>
142
+ </ToolbarSection>
143
+ </Toolbar>
144
+
145
+ <ToolSection items={popularTools} title="Popular" />
146
+ <ToolSection items={serverTools} title="Servers" />
147
+ </ModalBody>
148
+ </ModalSurface>
149
+ )
150
+ }
151
+
152
+ function ToolCategory({
153
+ active = false,
154
+ children,
155
+ icon: Icon,
156
+ }: {
157
+ active?: boolean
158
+ children: React.ReactNode
159
+ icon: ToolIcon
160
+ }) {
161
+ return (
162
+ <ToolbarButton
163
+ aria-pressed={active}
164
+ className={[
165
+ "rounded-[var(--bh-radius-none)] border-b-[length:var(--bh-border-width-strong)] px-[var(--bh-space-xs-4)]",
166
+ active
167
+ ? "border-b-[var(--bh-border-accent-purple-strong)] text-[var(--bh-content-accent-purple-default)]"
168
+ : "border-b-transparent text-[var(--bh-content-subtle)]",
169
+ ].join(" ")}
170
+ size="sm"
171
+ type="button"
172
+ variant="ghost"
173
+ >
174
+ <Icon aria-hidden="true" data-icon="inline-start" />
175
+ {children}
176
+ </ToolbarButton>
177
+ )
178
+ }
179
+
180
+ function ToolSection({ items, title }: { items: ToolItem[]; title: string }) {
181
+ return (
182
+ <section className="grid gap-[var(--bh-space-xl-12)]" aria-label={title}>
183
+ <h3 className="text-start text-[length:var(--bh-text-body-md-medium-font-size)] font-[var(--bh-text-body-md-medium-font-weight)] leading-[var(--bh-text-body-md-medium-line-height)] tracking-[var(--bh-text-body-md-medium-letter-spacing)] text-[var(--bh-content-subtle)]">
184
+ {title}
185
+ </h3>
186
+ <div className="grid gap-[var(--bh-space-md-8)] sm:grid-cols-2">
187
+ {items.map((item) => (
188
+ <ToolRow item={item} key={item.title} />
189
+ ))}
190
+ </div>
191
+ </section>
192
+ )
193
+ }
194
+
195
+ function ToolRow({ item }: { item: ToolItem }) {
196
+ const Icon = item.icon
197
+ const tone = item.tone ?? "neutral"
198
+
199
+ return (
200
+ <Menu
201
+ aria-label={`${item.title} tool action`}
202
+ className="w-full bg-transparent p-0 shadow-none"
203
+ width="auto"
204
+ >
205
+ <MenuItem
206
+ aria-label={item.title}
207
+ className="min-h-[var(--bh-space-8xl-48)] px-[var(--bh-space-xs-4)] py-[var(--bh-space-xxs-2)]"
208
+ kind="multiline"
209
+ role="menuitem"
210
+ >
211
+ <Avatar shape="rounded" size="lg">
212
+ <AvatarIcon
213
+ className={[
214
+ "border border-[var(--bh-border-subtle)]",
215
+ "[&_svg]:size-[var(--bh-space-4xl-20)]",
216
+ toolToneClassNames[tone],
217
+ ].join(" ")}
218
+ size="lg"
219
+ >
220
+ <Icon aria-hidden="true" strokeWidth={2} />
221
+ </AvatarIcon>
222
+ {item.added ? <AvatarStatus size="small" status="available" /> : null}
223
+ </Avatar>
224
+ <MenuItemText>
225
+ <MenuItemTitle className="font-[var(--bh-text-body-md-medium-font-weight)]">
226
+ {item.title}
227
+ </MenuItemTitle>
228
+ {item.added ? (
229
+ <Badge
230
+ badgeStyle="light"
231
+ className="self-start"
232
+ color="green"
233
+ size="sm"
234
+ type="leading-icon"
235
+ >
236
+ <CheckIcon aria-hidden="true" />
237
+ Added
238
+ </Badge>
239
+ ) : item.description ? (
240
+ <MenuItemDescription>{item.description}</MenuItemDescription>
241
+ ) : null}
242
+ </MenuItemText>
243
+ </MenuItem>
244
+ </Menu>
245
+ )
246
+ }
@@ -0,0 +1,39 @@
1
+ import { InboxIcon, PlusIcon, SearchIcon } from "lucide-react"
2
+
3
+ import {
4
+ EmptyState,
5
+ type EmptyStateAction,
6
+ } from "@/components/ui/expanded/EmptyState"
7
+
8
+ const searchActions: EmptyStateAction[] = [
9
+ { label: "Reset filters", variant: "secondary" },
10
+ { label: "Create item" },
11
+ ]
12
+
13
+ const inboxActions: EmptyStateAction[] = [
14
+ {
15
+ icon: <PlusIcon data-icon="inline-start" />,
16
+ label: "Add record",
17
+ },
18
+ ]
19
+
20
+ export function EmptyStateDemo() {
21
+ return (
22
+ <div className="grid gap-6">
23
+ <EmptyState
24
+ actions={searchActions}
25
+ description="Try adjusting your search or filters"
26
+ icon={<SearchIcon />}
27
+ title="No results found"
28
+ />
29
+ <EmptyState
30
+ actions={inboxActions}
31
+ align="start"
32
+ description="Create a record to start tracking this workflow."
33
+ icon={<InboxIcon />}
34
+ size="compact"
35
+ title="Nothing here yet"
36
+ />
37
+ </div>
38
+ )
39
+ }
@@ -26,7 +26,7 @@ const demoRtlInputProps = {
26
26
  ...demoInputProps,
27
27
  errorMessage: "\u0631\u0633\u0627\u0644\u0629 \u062e\u0637\u0623",
28
28
  label: "\u0645\u0644\u0635\u0642",
29
- message: "\u0647\u0630\u0627 \u0646\u0635 \u062a\u0644\u0645\u064a\u062d.",
29
+ message: "\u0646\u0635 \u062a\u0648\u0636\u064a\u062d\u064a",
30
30
  optionalText: "(\u062e\u064a\u0627\u0631\u064a)",
31
31
  placeholder: "\u0627\u0644\u0646\u0635",
32
32
  valueText: "\u0646\u0635 \u0647\u0646\u0627",