agentic-ds-kit 0.1.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.
Files changed (345) hide show
  1. package/AGENTS.md +10 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +21 -0
  4. package/README.md +38 -0
  5. package/contracts/accordion.json +38 -0
  6. package/contracts/alert.json +57 -0
  7. package/contracts/alertdialog.json +89 -0
  8. package/contracts/appheader.json +140 -0
  9. package/contracts/appnav.json +72 -0
  10. package/contracts/avatar.json +63 -0
  11. package/contracts/avatargroup.json +83 -0
  12. package/contracts/badge.json +92 -0
  13. package/contracts/barchart.json +55 -0
  14. package/contracts/breadcrumb.json +76 -0
  15. package/contracts/button.json +120 -0
  16. package/contracts/buttongroup.json +48 -0
  17. package/contracts/calendar.json +93 -0
  18. package/contracts/card.json +123 -0
  19. package/contracts/carousel.json +98 -0
  20. package/contracts/cell.json +203 -0
  21. package/contracts/chat.json +131 -0
  22. package/contracts/checkbox.json +101 -0
  23. package/contracts/collapsible.json +66 -0
  24. package/contracts/command.json +84 -0
  25. package/contracts/datatable.json +126 -0
  26. package/contracts/datepicker.json +102 -0
  27. package/contracts/drawer.json +93 -0
  28. package/contracts/dropdownmenu.json +190 -0
  29. package/contracts/empty.json +79 -0
  30. package/contracts/field.json +49 -0
  31. package/contracts/fieldset.json +29 -0
  32. package/contracts/headercell.json +107 -0
  33. package/contracts/index.json +478 -0
  34. package/contracts/input.json +119 -0
  35. package/contracts/inputotp.json +119 -0
  36. package/contracts/insightcard.json +130 -0
  37. package/contracts/linechart.json +51 -0
  38. package/contracts/loadinganimation.json +33 -0
  39. package/contracts/modal.json +100 -0
  40. package/contracts/modalcard.json +88 -0
  41. package/contracts/navigationmenu.json +65 -0
  42. package/contracts/numbertransition.json +33 -0
  43. package/contracts/pageheader.json +101 -0
  44. package/contracts/pagination.json +85 -0
  45. package/contracts/patterns/activity.json +30 -0
  46. package/contracts/patterns/assistant-workspace.json +16 -0
  47. package/contracts/patterns/dashboard.json +12 -0
  48. package/contracts/patterns/empty-first-run.json +15 -0
  49. package/contracts/patterns/inbox.json +32 -0
  50. package/contracts/patterns/invite-members.json +14 -0
  51. package/contracts/patterns/list-detail.json +13 -0
  52. package/contracts/patterns/settings-form.json +13 -0
  53. package/contracts/piechart.json +68 -0
  54. package/contracts/progress.json +124 -0
  55. package/contracts/progresssteps.json +91 -0
  56. package/contracts/radiogroup.json +132 -0
  57. package/contracts/scoreboard.json +46 -0
  58. package/contracts/scorecard.json +124 -0
  59. package/contracts/section.json +97 -0
  60. package/contracts/select.json +130 -0
  61. package/contracts/shimmertext.json +33 -0
  62. package/contracts/sidenav.json +133 -0
  63. package/contracts/slider.json +81 -0
  64. package/contracts/spinner.json +52 -0
  65. package/contracts/switch.json +94 -0
  66. package/contracts/table.json +92 -0
  67. package/contracts/tabs.json +90 -0
  68. package/contracts/textarea.json +54 -0
  69. package/contracts/thinkinganimation.json +32 -0
  70. package/contracts/timeline.json +49 -0
  71. package/contracts/toast.json +104 -0
  72. package/contracts/tooltip.json +66 -0
  73. package/lib/tokens.css +637 -0
  74. package/package.json +60 -0
  75. package/skills/prototype-from-kit/SKILL.md +29 -0
  76. package/src/index.ts +71 -0
  77. package/tokens/tokens.json +725 -0
  78. package/ui/Accordion/Accordion.module.css +68 -0
  79. package/ui/Accordion/Accordion.tsx +51 -0
  80. package/ui/Accordion/Accordion.types.ts +10 -0
  81. package/ui/Accordion/index.ts +2 -0
  82. package/ui/Alert/Alert.module.css +62 -0
  83. package/ui/Alert/Alert.tsx +27 -0
  84. package/ui/Alert/Alert.types.ts +7 -0
  85. package/ui/Alert/index.ts +2 -0
  86. package/ui/AlertDialog/AlertDialog.module.css +71 -0
  87. package/ui/AlertDialog/AlertDialog.tsx +109 -0
  88. package/ui/AlertDialog/AlertDialog.types.ts +14 -0
  89. package/ui/AlertDialog/index.ts +6 -0
  90. package/ui/AppHeader/AppHeader.module.css +120 -0
  91. package/ui/AppHeader/AppHeader.tsx +70 -0
  92. package/ui/AppHeader/AppHeader.types.ts +28 -0
  93. package/ui/AppHeader/index.ts +2 -0
  94. package/ui/AppNav/AppNav.module.css +168 -0
  95. package/ui/AppNav/AppNav.tsx +137 -0
  96. package/ui/AppNav/AppNav.types.ts +24 -0
  97. package/ui/AppNav/index.ts +2 -0
  98. package/ui/Avatar/Avatar.module.css +52 -0
  99. package/ui/Avatar/Avatar.tsx +62 -0
  100. package/ui/Avatar/Avatar.types.ts +8 -0
  101. package/ui/Avatar/index.ts +2 -0
  102. package/ui/AvatarGroup/AvatarGroup.module.css +49 -0
  103. package/ui/AvatarGroup/AvatarGroup.tsx +29 -0
  104. package/ui/AvatarGroup/AvatarGroup.types.ts +16 -0
  105. package/ui/AvatarGroup/index.ts +2 -0
  106. package/ui/Badge/Badge.module.css +92 -0
  107. package/ui/Badge/Badge.tsx +43 -0
  108. package/ui/Badge/Badge.types.ts +11 -0
  109. package/ui/Badge/index.ts +2 -0
  110. package/ui/BarChart/BarChart.module.css +56 -0
  111. package/ui/BarChart/BarChart.tsx +380 -0
  112. package/ui/BarChart/BarChart.types.ts +18 -0
  113. package/ui/BarChart/index.ts +2 -0
  114. package/ui/Breadcrumb/Breadcrumb.module.css +64 -0
  115. package/ui/Breadcrumb/Breadcrumb.tsx +89 -0
  116. package/ui/Breadcrumb/Breadcrumb.types.ts +14 -0
  117. package/ui/Breadcrumb/index.ts +2 -0
  118. package/ui/Button/Button.module.css +101 -0
  119. package/ui/Button/Button.tsx +49 -0
  120. package/ui/Button/Button.types.ts +18 -0
  121. package/ui/Button/index.ts +2 -0
  122. package/ui/Button/lucideName.tsx +188 -0
  123. package/ui/ButtonGroup/ButtonGroup.module.css +31 -0
  124. package/ui/ButtonGroup/ButtonGroup.tsx +12 -0
  125. package/ui/ButtonGroup/ButtonGroup.types.ts +6 -0
  126. package/ui/ButtonGroup/index.ts +2 -0
  127. package/ui/Calendar/Calendar.module.css +146 -0
  128. package/ui/Calendar/Calendar.tsx +296 -0
  129. package/ui/Calendar/Calendar.types.ts +11 -0
  130. package/ui/Calendar/index.ts +2 -0
  131. package/ui/Card/Card.module.css +95 -0
  132. package/ui/Card/Card.tsx +69 -0
  133. package/ui/Card/Card.types.ts +23 -0
  134. package/ui/Card/index.ts +2 -0
  135. package/ui/Carousel/Carousel.module.css +114 -0
  136. package/ui/Carousel/Carousel.tsx +152 -0
  137. package/ui/Carousel/Carousel.types.ts +17 -0
  138. package/ui/Carousel/index.ts +7 -0
  139. package/ui/Cell/Cell.module.css +133 -0
  140. package/ui/Cell/Cell.tsx +300 -0
  141. package/ui/Cell/Cell.types.ts +69 -0
  142. package/ui/Cell/index.ts +11 -0
  143. package/ui/Chat/Chat.module.css +149 -0
  144. package/ui/Chat/Chat.tsx +175 -0
  145. package/ui/Chat/Chat.types.ts +39 -0
  146. package/ui/Chat/index.ts +2 -0
  147. package/ui/Checkbox/Checkbox.module.css +135 -0
  148. package/ui/Checkbox/Checkbox.tsx +70 -0
  149. package/ui/Checkbox/Checkbox.types.ts +15 -0
  150. package/ui/Checkbox/index.ts +2 -0
  151. package/ui/Collapsible/Collapsible.module.css +68 -0
  152. package/ui/Collapsible/Collapsible.tsx +59 -0
  153. package/ui/Collapsible/Collapsible.types.ts +9 -0
  154. package/ui/Collapsible/index.ts +2 -0
  155. package/ui/Command/Command.module.css +138 -0
  156. package/ui/Command/Command.tsx +152 -0
  157. package/ui/Command/Command.types.ts +20 -0
  158. package/ui/Command/index.ts +2 -0
  159. package/ui/DataTable/DataTable.module.css +211 -0
  160. package/ui/DataTable/DataTable.tsx +429 -0
  161. package/ui/DataTable/DataTable.types.ts +35 -0
  162. package/ui/DataTable/index.ts +8 -0
  163. package/ui/DatePicker/DatePicker.module.css +44 -0
  164. package/ui/DatePicker/DatePicker.tsx +123 -0
  165. package/ui/DatePicker/DatePicker.types.ts +15 -0
  166. package/ui/DatePicker/index.ts +2 -0
  167. package/ui/Drawer/Drawer.module.css +204 -0
  168. package/ui/Drawer/Drawer.tsx +112 -0
  169. package/ui/Drawer/Drawer.types.ts +14 -0
  170. package/ui/Drawer/index.ts +2 -0
  171. package/ui/DropdownMenu/DropdownMenu.module.css +319 -0
  172. package/ui/DropdownMenu/DropdownMenu.tsx +580 -0
  173. package/ui/DropdownMenu/DropdownMenu.types.ts +48 -0
  174. package/ui/DropdownMenu/index.ts +8 -0
  175. package/ui/Empty/Empty.module.css +68 -0
  176. package/ui/Empty/Empty.tsx +35 -0
  177. package/ui/Empty/Empty.types.ts +10 -0
  178. package/ui/Empty/index.ts +2 -0
  179. package/ui/Field/Field.module.css +66 -0
  180. package/ui/Field/Field.tsx +46 -0
  181. package/ui/Field/Field.types.ts +12 -0
  182. package/ui/Field/index.ts +2 -0
  183. package/ui/FieldSet/FieldSet.module.css +30 -0
  184. package/ui/FieldSet/FieldSet.tsx +14 -0
  185. package/ui/FieldSet/FieldSet.types.ts +7 -0
  186. package/ui/FieldSet/index.ts +2 -0
  187. package/ui/HeaderCell/HeaderCell.module.css +85 -0
  188. package/ui/HeaderCell/HeaderCell.tsx +71 -0
  189. package/ui/HeaderCell/HeaderCell.types.ts +18 -0
  190. package/ui/HeaderCell/index.ts +2 -0
  191. package/ui/Input/Input.module.css +59 -0
  192. package/ui/Input/Input.tsx +65 -0
  193. package/ui/Input/Input.types.ts +22 -0
  194. package/ui/Input/index.ts +2 -0
  195. package/ui/InputOTP/InputOTP.module.css +139 -0
  196. package/ui/InputOTP/InputOTP.tsx +136 -0
  197. package/ui/InputOTP/InputOTP.types.ts +19 -0
  198. package/ui/InputOTP/index.ts +2 -0
  199. package/ui/InsightCard/InsightCard.module.css +166 -0
  200. package/ui/InsightCard/InsightCard.tsx +90 -0
  201. package/ui/InsightCard/InsightCard.types.ts +20 -0
  202. package/ui/InsightCard/index.ts +7 -0
  203. package/ui/LineChart/LineChart.module.css +93 -0
  204. package/ui/LineChart/LineChart.tsx +424 -0
  205. package/ui/LineChart/LineChart.types.ts +19 -0
  206. package/ui/LineChart/index.ts +2 -0
  207. package/ui/LoadingAnimation/LoadingAnimation.module.css +66 -0
  208. package/ui/LoadingAnimation/LoadingAnimation.tsx +41 -0
  209. package/ui/LoadingAnimation/LoadingAnimation.types.ts +9 -0
  210. package/ui/LoadingAnimation/index.ts +6 -0
  211. package/ui/Modal/Modal.module.css +48 -0
  212. package/ui/Modal/Modal.tsx +114 -0
  213. package/ui/Modal/Modal.types.ts +15 -0
  214. package/ui/Modal/index.ts +2 -0
  215. package/ui/ModalCard/ModalCard.module.css +137 -0
  216. package/ui/ModalCard/ModalCard.tsx +58 -0
  217. package/ui/ModalCard/ModalCard.types.ts +15 -0
  218. package/ui/ModalCard/index.ts +2 -0
  219. package/ui/NavigationMenu/NavigationMenu.module.css +31 -0
  220. package/ui/NavigationMenu/NavigationMenu.tsx +57 -0
  221. package/ui/NavigationMenu/NavigationMenu.types.ts +22 -0
  222. package/ui/NavigationMenu/index.ts +7 -0
  223. package/ui/NumberTransition/NumberTransition.module.css +110 -0
  224. package/ui/NumberTransition/NumberTransition.tsx +78 -0
  225. package/ui/NumberTransition/NumberTransition.types.ts +9 -0
  226. package/ui/NumberTransition/index.ts +2 -0
  227. package/ui/PageHeader/PageHeader.module.css +57 -0
  228. package/ui/PageHeader/PageHeader.tsx +39 -0
  229. package/ui/PageHeader/PageHeader.types.ts +12 -0
  230. package/ui/PageHeader/index.ts +2 -0
  231. package/ui/Pagination/Pagination.module.css +19 -0
  232. package/ui/Pagination/Pagination.tsx +147 -0
  233. package/ui/Pagination/Pagination.types.ts +12 -0
  234. package/ui/Pagination/index.ts +2 -0
  235. package/ui/PieChart/PieChart.module.css +116 -0
  236. package/ui/PieChart/PieChart.tsx +293 -0
  237. package/ui/PieChart/PieChart.types.ts +22 -0
  238. package/ui/PieChart/index.ts +2 -0
  239. package/ui/Progress/Progress.module.css +226 -0
  240. package/ui/Progress/Progress.tsx +167 -0
  241. package/ui/Progress/Progress.types.ts +15 -0
  242. package/ui/Progress/index.ts +8 -0
  243. package/ui/ProgressSteps/ProgressSteps.module.css +210 -0
  244. package/ui/ProgressSteps/ProgressSteps.tsx +105 -0
  245. package/ui/ProgressSteps/ProgressSteps.types.ts +19 -0
  246. package/ui/ProgressSteps/index.ts +8 -0
  247. package/ui/RadioGroup/RadioGroup.module.css +284 -0
  248. package/ui/RadioGroup/RadioGroup.tsx +116 -0
  249. package/ui/RadioGroup/RadioGroup.types.ts +30 -0
  250. package/ui/RadioGroup/index.ts +8 -0
  251. package/ui/Scoreboard/Scoreboard.module.css +53 -0
  252. package/ui/Scoreboard/Scoreboard.tsx +41 -0
  253. package/ui/Scoreboard/Scoreboard.types.ts +7 -0
  254. package/ui/Scoreboard/index.ts +2 -0
  255. package/ui/Scorecard/Scorecard.module.css +150 -0
  256. package/ui/Scorecard/Scorecard.tsx +92 -0
  257. package/ui/Scorecard/Scorecard.types.ts +18 -0
  258. package/ui/Scorecard/index.ts +2 -0
  259. package/ui/Section/Section.module.css +104 -0
  260. package/ui/Section/Section.tsx +75 -0
  261. package/ui/Section/Section.types.ts +15 -0
  262. package/ui/Section/index.ts +2 -0
  263. package/ui/Select/Select.module.css +7 -0
  264. package/ui/Select/Select.tsx +113 -0
  265. package/ui/Select/Select.types.ts +26 -0
  266. package/ui/Select/index.ts +2 -0
  267. package/ui/ShimmerText/ShimmerText.module.css +46 -0
  268. package/ui/ShimmerText/ShimmerText.tsx +48 -0
  269. package/ui/ShimmerText/ShimmerText.types.ts +12 -0
  270. package/ui/ShimmerText/index.ts +2 -0
  271. package/ui/SideNav/SideNav.module.css +347 -0
  272. package/ui/SideNav/SideNav.tsx +222 -0
  273. package/ui/SideNav/SideNav.types.ts +42 -0
  274. package/ui/SideNav/index.ts +8 -0
  275. package/ui/Slider/Slider.module.css +105 -0
  276. package/ui/Slider/Slider.tsx +187 -0
  277. package/ui/Slider/Slider.types.ts +11 -0
  278. package/ui/Slider/index.ts +2 -0
  279. package/ui/Spinner/Spinner.module.css +58 -0
  280. package/ui/Spinner/Spinner.tsx +19 -0
  281. package/ui/Spinner/Spinner.types.ts +6 -0
  282. package/ui/Spinner/index.ts +2 -0
  283. package/ui/Switch/Switch.module.css +189 -0
  284. package/ui/Switch/Switch.tsx +65 -0
  285. package/ui/Switch/Switch.types.ts +12 -0
  286. package/ui/Switch/index.ts +2 -0
  287. package/ui/Table/Table.module.css +132 -0
  288. package/ui/Table/Table.tsx +108 -0
  289. package/ui/Table/Table.types.ts +26 -0
  290. package/ui/Table/index.ts +8 -0
  291. package/ui/Tabs/Tabs.module.css +162 -0
  292. package/ui/Tabs/Tabs.tsx +150 -0
  293. package/ui/Tabs/Tabs.types.ts +21 -0
  294. package/ui/Tabs/index.ts +2 -0
  295. package/ui/Textarea/Textarea.module.css +74 -0
  296. package/ui/Textarea/Textarea.tsx +38 -0
  297. package/ui/Textarea/Textarea.types.ts +14 -0
  298. package/ui/Textarea/index.ts +2 -0
  299. package/ui/ThinkingAnimation/ThinkingAnimation.module.css +75 -0
  300. package/ui/ThinkingAnimation/ThinkingAnimation.tsx +31 -0
  301. package/ui/ThinkingAnimation/ThinkingAnimation.types.ts +8 -0
  302. package/ui/ThinkingAnimation/index.ts +2 -0
  303. package/ui/Timeline/Timeline.module.css +99 -0
  304. package/ui/Timeline/Timeline.tsx +47 -0
  305. package/ui/Timeline/Timeline.types.ts +16 -0
  306. package/ui/Timeline/index.ts +2 -0
  307. package/ui/Toast/Toast.module.css +133 -0
  308. package/ui/Toast/Toast.tsx +89 -0
  309. package/ui/Toast/Toast.types.ts +17 -0
  310. package/ui/Toast/index.ts +2 -0
  311. package/ui/Tooltip/Tooltip.module.css +111 -0
  312. package/ui/Tooltip/Tooltip.tsx +101 -0
  313. package/ui/Tooltip/index.ts +2 -0
  314. package/ui/patterns/ActivityPattern/ActivityFeed.tsx +77 -0
  315. package/ui/patterns/ActivityPattern/ActivityPattern.tsx +120 -0
  316. package/ui/patterns/ActivityPattern/ActivityTasks.tsx +86 -0
  317. package/ui/patterns/ActivityPattern/TaskDrawer.module.css +39 -0
  318. package/ui/patterns/ActivityPattern/TaskDrawer.tsx +186 -0
  319. package/ui/patterns/ActivityPattern/index.ts +2 -0
  320. package/ui/patterns/AssistantWorkspacePattern/AssistantWorkspacePattern.module.css +16 -0
  321. package/ui/patterns/AssistantWorkspacePattern/AssistantWorkspacePattern.tsx +159 -0
  322. package/ui/patterns/AssistantWorkspacePattern/index.ts +2 -0
  323. package/ui/patterns/DashboardPattern/DashboardPattern.tsx +102 -0
  324. package/ui/patterns/DashboardPattern/index.ts +1 -0
  325. package/ui/patterns/DashboardPattern/patterns.module.css +6 -0
  326. package/ui/patterns/EmptyFirstRunPattern/EmptyFirstRunPattern.tsx +125 -0
  327. package/ui/patterns/EmptyFirstRunPattern/index.ts +2 -0
  328. package/ui/patterns/InboxPattern/InboxPattern.module.css +40 -0
  329. package/ui/patterns/InboxPattern/InboxPattern.tsx +192 -0
  330. package/ui/patterns/InboxPattern/InboxReplyDrawer.tsx +97 -0
  331. package/ui/patterns/InboxPattern/inbox-data.ts +101 -0
  332. package/ui/patterns/InboxPattern/index.ts +2 -0
  333. package/ui/patterns/InviteMembersPattern/InviteMembersPattern.tsx +148 -0
  334. package/ui/patterns/InviteMembersPattern/index.ts +2 -0
  335. package/ui/patterns/ListDetailPattern/ListDetailPattern.module.css +34 -0
  336. package/ui/patterns/ListDetailPattern/ListDetailPattern.tsx +145 -0
  337. package/ui/patterns/ListDetailPattern/index.ts +2 -0
  338. package/ui/patterns/SettingsFormPattern/SettingsFormPattern.module.css +12 -0
  339. package/ui/patterns/SettingsFormPattern/SettingsFormPattern.tsx +89 -0
  340. package/ui/patterns/SettingsFormPattern/index.ts +3 -0
  341. package/ui/shared/ChartFrame.module.css +295 -0
  342. package/ui/shared/ChartFrame.tsx +87 -0
  343. package/ui/shared/chartMath.ts +228 -0
  344. package/ui/shared/controls.module.css +48 -0
  345. package/ui/shared/useChartSize.ts +22 -0
@@ -0,0 +1,101 @@
1
+ "use client";
2
+
3
+ import {
4
+ cloneElement,
5
+ isValidElement,
6
+ useEffect,
7
+ useId,
8
+ useRef,
9
+ useState,
10
+ type ReactElement,
11
+ type ReactNode,
12
+ } from "react";
13
+ import styles from "./Tooltip.module.css";
14
+
15
+ export type TooltipPlacement = "top" | "bottom" | "left" | "right";
16
+
17
+ export interface TooltipProps {
18
+ content: string;
19
+ placement?: TooltipPlacement;
20
+ delay?: number;
21
+ open?: boolean;
22
+ disabled?: boolean;
23
+ children: ReactNode;
24
+ className?: string;
25
+ }
26
+
27
+ export function Tooltip({
28
+ content,
29
+ placement = "top",
30
+ delay = 150,
31
+ open: controlledOpen,
32
+ disabled = false,
33
+ children,
34
+ className = "",
35
+ }: TooltipProps) {
36
+ const tooltipId = useId();
37
+ const timerRef = useRef<number | null>(null);
38
+ const isControlled = controlledOpen !== undefined;
39
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
40
+ const open = !disabled && (isControlled ? controlledOpen : uncontrolledOpen);
41
+
42
+ function clearTimer() {
43
+ if (timerRef.current != null) {
44
+ window.clearTimeout(timerRef.current);
45
+ timerRef.current = null;
46
+ }
47
+ }
48
+
49
+ function show(immediate = false) {
50
+ if (disabled || isControlled) return;
51
+ clearTimer();
52
+ if (immediate || delay <= 0) {
53
+ setUncontrolledOpen(true);
54
+ return;
55
+ }
56
+ timerRef.current = window.setTimeout(() => setUncontrolledOpen(true), delay);
57
+ }
58
+
59
+ function hide() {
60
+ if (isControlled) return;
61
+ clearTimer();
62
+ setUncontrolledOpen(false);
63
+ }
64
+
65
+ useEffect(() => () => clearTimer(), []);
66
+
67
+ useEffect(() => {
68
+ if (!open) return undefined;
69
+ function handleKeyDown(event: KeyboardEvent) {
70
+ if (event.key === "Escape") hide();
71
+ }
72
+ document.addEventListener("keydown", handleKeyDown);
73
+ return () => document.removeEventListener("keydown", handleKeyDown);
74
+ }, [open]);
75
+
76
+ const trigger = isValidElement(children)
77
+ ? cloneElement(children as ReactElement<{ "aria-describedby"?: string }>, {
78
+ "aria-describedby": open ? tooltipId : undefined,
79
+ })
80
+ : children;
81
+
82
+ return (
83
+ <span
84
+ className={`${styles.wrapper} ${className}`.trim()}
85
+ onPointerEnter={() => show()}
86
+ onPointerLeave={hide}
87
+ onFocus={() => show(true)}
88
+ onBlur={hide}
89
+ >
90
+ {trigger}
91
+ <span
92
+ id={tooltipId}
93
+ role="tooltip"
94
+ className={`${styles.bubble} ${styles[placement]}${open ? ` ${styles.open}` : ""}`}
95
+ >
96
+ {content}
97
+ <span className={styles.arrow} aria-hidden="true" />
98
+ </span>
99
+ </span>
100
+ );
101
+ }
@@ -0,0 +1,2 @@
1
+ export type { TooltipProps, TooltipPlacement } from "./Tooltip";
2
+ export { Tooltip } from "./Tooltip";
@@ -0,0 +1,77 @@
1
+ import { DataTable } from "../../DataTable";
2
+ import type { DataTableColumn, DataTableRow } from "../../DataTable";
3
+
4
+ const EVENT_COLUMNS: DataTableColumn[] = [
5
+ { key: "actor", header: "Person", sortable: true },
6
+ { key: "event", header: "Event", sortable: true },
7
+ { key: "type", header: "Type", sortable: true },
8
+ { key: "when", header: "When", sortable: true },
9
+ ];
10
+
11
+ const EVENT_ROWS: DataTableRow[] = [
12
+ {
13
+ id: "comment-launch",
14
+ actor: { type: "avatar", label: "Maya Chen", name: "Maya Chen", src: "/faces/maya-chen.jpg" },
15
+ event: { type: "file", label: "Commented on Launch brief" },
16
+ type: { type: "badge", label: "Comment", tone: "info" },
17
+ when: "2h ago",
18
+ },
19
+ {
20
+ id: "blocked-qa",
21
+ actor: { type: "avatar", label: "Unassigned", name: "Unassigned" },
22
+ event: { type: "file", label: "QA checklist marked Blocked" },
23
+ type: { type: "badge", label: "Status", tone: "danger" },
24
+ when: "4h ago",
25
+ },
26
+ {
27
+ id: "macros-update",
28
+ actor: { type: "avatar", label: "Alex Rivera", name: "Alex Rivera", src: "/faces/alex-rivera.jpg" },
29
+ event: { type: "file", label: "Updated Support macros" },
30
+ type: { type: "badge", label: "Edit", tone: "neutral" },
31
+ when: "5h ago",
32
+ },
33
+ {
34
+ id: "ready-notes",
35
+ actor: { type: "avatar", label: "Jordan Lee", name: "Jordan Lee", src: "/faces/jordan-lee.jpg" },
36
+ event: { type: "file", label: "Moved Release notes to Ready" },
37
+ type: { type: "badge", label: "Status", tone: "success" },
38
+ when: "Yesterday",
39
+ },
40
+ {
41
+ id: "mention-launch",
42
+ actor: { type: "avatar", label: "Maya Chen", name: "Maya Chen", src: "/faces/maya-chen.jpg" },
43
+ event: { type: "file", label: "Mentioned you in Launch brief" },
44
+ type: { type: "badge", label: "Mention", tone: "brand" },
45
+ when: "Yesterday",
46
+ },
47
+ {
48
+ id: "macros-comment",
49
+ actor: { type: "avatar", label: "Alex Rivera", name: "Alex Rivera", src: "/faces/alex-rivera.jpg" },
50
+ event: { type: "file", label: "Replied on Support macros" },
51
+ type: { type: "badge", label: "Comment", tone: "info" },
52
+ when: "Mon",
53
+ },
54
+ ];
55
+
56
+ function rowsFor(tab: string): DataTableRow[] {
57
+ if (tab === "all") return EVENT_ROWS;
58
+ const label = tab === "comments" ? "Comment" : tab === "status" ? "Status" : "Mention";
59
+ return EVENT_ROWS.filter((row) => {
60
+ const cell = row.type;
61
+ return typeof cell === "object" && cell !== null && "label" in cell && cell.label === label;
62
+ });
63
+ }
64
+
65
+ export function ActivityFeed({ tab, caption }: { tab: string; caption: string }) {
66
+ return (
67
+ <DataTable
68
+ caption={caption}
69
+ toolbar
70
+ cellSize="sm"
71
+ searchPlaceholder="Search activity..."
72
+ emptyMessage="No activity in this filter."
73
+ columns={EVENT_COLUMNS}
74
+ rows={rowsFor(tab)}
75
+ />
76
+ );
77
+ }
@@ -0,0 +1,120 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { Button } from "../../Button";
5
+ import { ButtonGroup } from "../../ButtonGroup";
6
+ import { Empty } from "../../Empty";
7
+ import { PageHeader } from "../../PageHeader";
8
+ import type { PageHeaderProps } from "../../PageHeader";
9
+ import { Scoreboard } from "../../Scoreboard";
10
+ import { Section } from "../../Section";
11
+ import { Tabs } from "../../Tabs";
12
+ import { ActivityFeed } from "./ActivityFeed";
13
+ import { TaskCards, TaskList } from "./ActivityTasks";
14
+ import { TASK_INSIGHTS, TaskDrawer } from "./TaskDrawer";
15
+
16
+ type TaskView = "cards" | "list";
17
+
18
+ const ACTIVITY_METRICS = [
19
+ { label: "Today", value: "6", delta: "+2", trend: "up" as const, hint: "vs yesterday", size: "lg" as const, badge: "Live", badgeTone: "success" as const },
20
+ { label: "Comments", value: "5", delta: "+1", trend: "up" as const, hint: "this sprint", size: "lg" as const, badge: "Sprint", badgeTone: "info" as const },
21
+ { label: "Status changes", value: "4", delta: "0", trend: "flat" as const, hint: "this sprint", size: "lg" as const, badge: "Ship", badgeTone: "brand" as const },
22
+ { label: "Mentions", value: "2", delta: "+2", trend: "up" as const, hint: "need reply", size: "lg" as const, badge: "At risk", badgeTone: "danger" as const },
23
+ ];
24
+
25
+ export interface ActivityPatternProps {
26
+ breadcrumbs?: PageHeaderProps["breadcrumbs"];
27
+ }
28
+
29
+ export function ActivityPattern({ breadcrumbs }: ActivityPatternProps) {
30
+ const [dismissed, setDismissed] = useState<string[]>([]);
31
+ const [openTaskId, setOpenTaskId] = useState<string | null>(null);
32
+ const [taskView, setTaskView] = useState<TaskView>("cards");
33
+
34
+ const tasks = TASK_INSIGHTS.filter((task) => !dismissed.includes(task.id));
35
+ const openTask = TASK_INSIGHTS.find((task) => task.id === openTaskId) ?? null;
36
+ const taskCount =
37
+ tasks.length === 0
38
+ ? "All caught up"
39
+ : `${tasks.length} ${tasks.length === 1 ? "needs" : "need"} attention`;
40
+
41
+ function dismissTask(id: string) {
42
+ setDismissed((current) => [...current, id]);
43
+ setOpenTaskId((current) => (current === id ? null : current));
44
+ }
45
+
46
+ return (
47
+ <div className="layout-canvas layout-canvas--sticky-header">
48
+ <div className="layout-header">
49
+ <PageHeader
50
+ title="Activity"
51
+ subtitle="What the team shipped, blocked, and commented on."
52
+ breadcrumbs={breadcrumbs}
53
+ />
54
+ </div>
55
+ <div className="layout-content">
56
+ <Section title="This week">
57
+ <Scoreboard
58
+ className="layout-metrics layout-metrics--fixed-4"
59
+ aria-label="Activity this week"
60
+ items={ACTIVITY_METRICS}
61
+ />
62
+ </Section>
63
+ <Section
64
+ title="Tasks"
65
+ description={taskCount}
66
+ actions={
67
+ tasks.length > 0 ? (
68
+ <ButtonGroup ariaLabel="Task layout">
69
+ <Button
70
+ variant={taskView === "cards" ? "secondary" : "tertiary"}
71
+ size="sm"
72
+ onClick={() => setTaskView("cards")}
73
+ >
74
+ Cards
75
+ </Button>
76
+ <Button
77
+ variant={taskView === "list" ? "secondary" : "tertiary"}
78
+ size="sm"
79
+ onClick={() => setTaskView("list")}
80
+ >
81
+ List
82
+ </Button>
83
+ </ButtonGroup>
84
+ ) : undefined
85
+ }
86
+ >
87
+ {tasks.length > 0 ? (
88
+ taskView === "cards" ? (
89
+ <TaskCards tasks={tasks} onOpen={setOpenTaskId} onDismiss={dismissTask} />
90
+ ) : (
91
+ <TaskList tasks={tasks} onOpen={setOpenTaskId} onDismiss={dismissTask} />
92
+ )
93
+ ) : (
94
+ <Empty
95
+ title="No open tasks"
96
+ description="Nothing in this sprint needs a look right now."
97
+ icon="Check"
98
+ outlined
99
+ />
100
+ )}
101
+ </Section>
102
+ <Section title="Feed" description="Newest first">
103
+ <Tabs
104
+ ariaLabel="Activity type"
105
+ variant="line"
106
+ size="md"
107
+ defaultValue="all"
108
+ items={[
109
+ { id: "all", label: "All", content: <ActivityFeed tab="all" caption="All activity" /> },
110
+ { id: "comments", label: "Comments", content: <ActivityFeed tab="comments" caption="Comments" /> },
111
+ { id: "status", label: "Status", content: <ActivityFeed tab="status" caption="Status changes" /> },
112
+ { id: "mentions", label: "Mentions", content: <ActivityFeed tab="mentions" caption="Mentions" /> },
113
+ ]}
114
+ />
115
+ </Section>
116
+ </div>
117
+ <TaskDrawer task={openTask} onClose={() => setOpenTaskId(null)} />
118
+ </div>
119
+ );
120
+ }
@@ -0,0 +1,86 @@
1
+ import { Badge } from "../../Badge";
2
+ import { Button } from "../../Button";
3
+ import { ButtonGroup } from "../../ButtonGroup";
4
+ import { Carousel } from "../../Carousel";
5
+ import type { CarouselSlidesPerView } from "../../Carousel";
6
+ import { InsightCard } from "../../InsightCard";
7
+ import { Table } from "../../Table";
8
+ import type { TaskInsight } from "./TaskDrawer";
9
+
10
+ export function TaskCards({
11
+ tasks,
12
+ onOpen,
13
+ onDismiss,
14
+ }: {
15
+ tasks: TaskInsight[];
16
+ onOpen: (id: string) => void;
17
+ onDismiss: (id: string) => void;
18
+ }) {
19
+ const slidesPerView = Math.min(3, Math.max(1, tasks.length)) as CarouselSlidesPerView;
20
+
21
+ return (
22
+ <div className="layout-carousel">
23
+ <Carousel
24
+ ariaLabel="Tasks that need attention"
25
+ slidesPerView={slidesPerView}
26
+ items={tasks.map((task) => (
27
+ <InsightCard
28
+ key={task.id}
29
+ eyebrow="Task"
30
+ title={task.title}
31
+ description={task.description}
32
+ tone={task.tone}
33
+ source={task.source}
34
+ secondaryAction={{ label: "View task", onClick: () => onOpen(task.id) }}
35
+ onDismiss={() => onDismiss(task.id)}
36
+ />
37
+ ))}
38
+ />
39
+ </div>
40
+ );
41
+ }
42
+
43
+ export function TaskList({
44
+ tasks,
45
+ onOpen,
46
+ onDismiss,
47
+ }: {
48
+ tasks: TaskInsight[];
49
+ onOpen: (id: string) => void;
50
+ onDismiss: (id: string) => void;
51
+ }) {
52
+ return (
53
+ <Table
54
+ caption="Open tasks"
55
+ size="sm"
56
+ emptyLabel="No open tasks."
57
+ columns={[
58
+ { key: "task", header: "Task", emphasis: true },
59
+ { key: "owner", header: "Owner" },
60
+ { key: "status", header: "Status" },
61
+ { key: "due", header: "Due" },
62
+ { key: "actions", header: "Actions", align: "end" },
63
+ ]}
64
+ rows={tasks.map((task) => ({
65
+ task: task.title,
66
+ owner: task.owner,
67
+ status: (
68
+ <Badge size="sm" tone={task.statusTone}>
69
+ {task.status}
70
+ </Badge>
71
+ ),
72
+ due: task.due,
73
+ actions: (
74
+ <ButtonGroup ariaLabel={`${task.title} actions`}>
75
+ <Button variant="secondary" size="sm" onClick={() => onOpen(task.id)}>
76
+ View task
77
+ </Button>
78
+ <Button variant="tertiary" size="sm" onClick={() => onDismiss(task.id)}>
79
+ Dismiss
80
+ </Button>
81
+ </ButtonGroup>
82
+ ),
83
+ }))}
84
+ />
85
+ );
86
+ }
@@ -0,0 +1,39 @@
1
+ .stack {
2
+ display: grid;
3
+ gap: var(--space-stack-lg);
4
+ }
5
+
6
+ .row {
7
+ display: flex;
8
+ align-items: center;
9
+ gap: var(--space-inline-md);
10
+ }
11
+
12
+ .meta {
13
+ flex: 1;
14
+ min-width: 0;
15
+ }
16
+
17
+ .label {
18
+ margin: 0;
19
+ font-family: var(--font-sans);
20
+ font-size: var(--type-size-caption);
21
+ font-weight: var(--type-weight-caption);
22
+ color: var(--text-secondary);
23
+ }
24
+
25
+ .value {
26
+ margin: 0;
27
+ font-family: var(--font-sans);
28
+ font-size: var(--type-size-body-sm);
29
+ font-weight: var(--type-weight-label);
30
+ color: var(--text-primary);
31
+ }
32
+
33
+ .summary {
34
+ margin: 0;
35
+ font-family: var(--font-sans);
36
+ font-size: var(--type-size-body);
37
+ line-height: var(--type-line-body);
38
+ color: var(--text-secondary);
39
+ }
@@ -0,0 +1,186 @@
1
+ "use client";
2
+
3
+ import { Avatar } from "../../Avatar";
4
+ import { Badge } from "../../Badge";
5
+ import type { BadgeTone } from "../../Badge";
6
+ import { Button } from "../../Button";
7
+ import { Drawer } from "../../Drawer";
8
+ import type { InsightCardTone } from "../../InsightCard";
9
+ import { Progress } from "../../Progress";
10
+ import styles from "./TaskDrawer.module.css";
11
+
12
+ export interface TaskInsight {
13
+ id: string;
14
+ title: string;
15
+ description: string;
16
+ tone: InsightCardTone;
17
+ source: string;
18
+ owner: string;
19
+ ownerSrc?: string;
20
+ status: string;
21
+ statusTone: BadgeTone;
22
+ due: string;
23
+ summary: string;
24
+ progress: number;
25
+ }
26
+
27
+ export const TASK_INSIGHTS: TaskInsight[] = [
28
+ {
29
+ id: "qa-checklist",
30
+ title: "QA checklist is still blocked",
31
+ description: "Unassigned for 2 days. Assign an owner before Thursday's review.",
32
+ tone: "warning",
33
+ source: "From Open tasks",
34
+ owner: "Unassigned",
35
+ status: "Blocked",
36
+ statusTone: "danger",
37
+ due: "Thursday",
38
+ summary: "No owner. Legal sign-off and the last two device passes are still open.",
39
+ progress: 35,
40
+ },
41
+ {
42
+ id: "launch-brief",
43
+ title: "Launch brief is waiting on review",
44
+ description: "Maya left comments 2 hours ago. Close them before the freeze.",
45
+ tone: "info",
46
+ source: "From Open tasks",
47
+ owner: "Maya Chen",
48
+ ownerSrc: "/faces/maya-chen.jpg",
49
+ status: "In review",
50
+ statusTone: "warning",
51
+ due: "Tomorrow",
52
+ summary: "Copy is in review. Two comments on positioning still need a reply.",
53
+ progress: 72,
54
+ },
55
+ {
56
+ id: "release-notes",
57
+ title: "Release notes are ready to ship",
58
+ description: "Jordan marked this Ready. Confirm the changelog before tag.",
59
+ tone: "opportunity",
60
+ source: "From Open tasks",
61
+ owner: "Jordan Lee",
62
+ ownerSrc: "/faces/jordan-lee.jpg",
63
+ status: "Ready",
64
+ statusTone: "success",
65
+ due: "Today",
66
+ summary: "Draft is complete. Needs a final pass on the known-issues list.",
67
+ progress: 90,
68
+ },
69
+ {
70
+ id: "support-macros",
71
+ title: "Support macros need a pass",
72
+ description: "Alex updated the file 5 hours ago. Three replies are still in progress.",
73
+ tone: "neutral",
74
+ source: "From Open tasks",
75
+ owner: "Alex Rivera",
76
+ ownerSrc: "/faces/alex-rivera.jpg",
77
+ status: "In progress",
78
+ statusTone: "info",
79
+ due: "Friday",
80
+ summary: "Refund and delay macros are drafted. Escalation paths are not.",
81
+ progress: 55,
82
+ },
83
+ {
84
+ id: "user-research",
85
+ title: "User research needs synthesis",
86
+ description: "Eight interviews landed this week. Tag themes before Friday's readout.",
87
+ tone: "info",
88
+ source: "From Resources",
89
+ owner: "Iris Okafor",
90
+ ownerSrc: "/faces/iris-okafor.jpg",
91
+ status: "In progress",
92
+ statusTone: "info",
93
+ due: "Friday",
94
+ summary: "Notes are in. Themes and clips still need to land in the shared doc.",
95
+ progress: 48,
96
+ },
97
+ {
98
+ id: "at-risk-triage",
99
+ title: "At-risk items need triage",
100
+ description: "Five tagged At risk. Rank them before the freeze so owners can move.",
101
+ tone: "danger",
102
+ source: "From Tags",
103
+ owner: "Noah Williams",
104
+ ownerSrc: "/faces/noah-williams.jpg",
105
+ status: "Blocked",
106
+ statusTone: "danger",
107
+ due: "Tomorrow",
108
+ summary: "The list is stale. Two items already shipped and still carry the tag.",
109
+ progress: 20,
110
+ },
111
+ {
112
+ id: "invite-members",
113
+ title: "Invite members is still open",
114
+ description: "Three seats unused. Send invites so review comments have owners.",
115
+ tone: "warning",
116
+ source: "From Workspace",
117
+ owner: "Unassigned",
118
+ status: "Open",
119
+ statusTone: "warning",
120
+ due: "Friday",
121
+ summary: "Seats are provisioned. Nobody has sent the invites for design and QA.",
122
+ progress: 10,
123
+ },
124
+ {
125
+ id: "insights-share",
126
+ title: "Insights report is ready to share",
127
+ description: "Weekly digest is compiled. Send it before standup so the team can act.",
128
+ tone: "opportunity",
129
+ source: "From Insights",
130
+ owner: "Iris Okafor",
131
+ ownerSrc: "/faces/iris-okafor.jpg",
132
+ status: "Ready",
133
+ statusTone: "success",
134
+ due: "Today",
135
+ summary: "Charts are current. Needs a one-line takeaway on the at-risk tag.",
136
+ progress: 88,
137
+ },
138
+ ];
139
+
140
+ export function TaskDrawer({
141
+ task,
142
+ onClose,
143
+ }: {
144
+ task: TaskInsight | null;
145
+ onClose: () => void;
146
+ }) {
147
+ const unassigned = task?.owner === "Unassigned";
148
+
149
+ return (
150
+ <Drawer
151
+ open={Boolean(task)}
152
+ title={task?.title ?? "Task"}
153
+ description={task ? `${task.status} · Due ${task.due}` : undefined}
154
+ onClose={onClose}
155
+ footer={
156
+ task ? (
157
+ <>
158
+ {unassigned ? (
159
+ <Button variant="primary" block onClick={onClose}>
160
+ Assign owner
161
+ </Button>
162
+ ) : null}
163
+ <Button variant="secondary" block onClick={onClose}>
164
+ Close
165
+ </Button>
166
+ </>
167
+ ) : null
168
+ }
169
+ >
170
+ {task ? (
171
+ <div className={styles.stack}>
172
+ <div className={styles.row}>
173
+ <Avatar name={task.owner} src={task.ownerSrc} size="md" />
174
+ <div className={styles.meta}>
175
+ <p className={styles.label}>Owner</p>
176
+ <p className={styles.value}>{task.owner}</p>
177
+ </div>
178
+ <Badge tone={task.statusTone}>{task.status}</Badge>
179
+ </div>
180
+ <p className={styles.summary}>{task.summary}</p>
181
+ <Progress value={task.progress} size="sm" label="Progress" showValue />
182
+ </div>
183
+ ) : null}
184
+ </Drawer>
185
+ );
186
+ }
@@ -0,0 +1,2 @@
1
+ export { ActivityPattern } from "./ActivityPattern";
2
+ export type { ActivityPatternProps } from "./ActivityPattern";
@@ -0,0 +1,16 @@
1
+ .shell {
2
+ flex: 1;
3
+ min-width: 0;
4
+ min-height: 0;
5
+ }
6
+
7
+ .insights {
8
+ min-width: 0;
9
+ min-height: 0;
10
+ }
11
+
12
+ .rail {
13
+ min-width: 0;
14
+ min-height: 0;
15
+ display: grid;
16
+ }