@plannotator/ui 0.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.
Files changed (305) hide show
  1. package/README.md +60 -0
  2. package/assets/diff-options.png +0 -0
  3. package/assets/icon-codex.png +0 -0
  4. package/assets/look-flat.png +0 -0
  5. package/assets/look-grid.png +0 -0
  6. package/assets/review-sections.png +0 -0
  7. package/assets/review-tree.png +0 -0
  8. package/assets/workspaces.webp +0 -0
  9. package/components/AISettingsTab.tsx +145 -0
  10. package/components/ActionMenu.tsx +101 -0
  11. package/components/AgentControls.tsx +216 -0
  12. package/components/AgentsTab.tsx +1294 -0
  13. package/components/AnnotationPanel.tsx +731 -0
  14. package/components/AnnotationSidebar.tsx +86 -0
  15. package/components/AnnotationToolbar.tsx +323 -0
  16. package/components/AnnotationToolstrip.tsx +355 -0
  17. package/components/ApproveDropdown.tsx +170 -0
  18. package/components/AttachmentsButton.tsx +410 -0
  19. package/components/BlockRenderer.tsx +163 -0
  20. package/components/BorderTrail.tsx +38 -0
  21. package/components/CodeFilePicker.tsx +64 -0
  22. package/components/CodeFilePopout.tsx +602 -0
  23. package/components/CodePathValidationContext.tsx +14 -0
  24. package/components/CommentPopover.tsx +512 -0
  25. package/components/CompletionOverlay.tsx +99 -0
  26. package/components/ConfirmDialog.tsx +128 -0
  27. package/components/DocBadges.tsx +231 -0
  28. package/components/EditorAnnotationCard.tsx +65 -0
  29. package/components/ExportModal.tsx +565 -0
  30. package/components/FloatingQuickLabelPicker.tsx +144 -0
  31. package/components/GitHubIcon.tsx +16 -0
  32. package/components/GitLabIcon.tsx +30 -0
  33. package/components/GraphvizBlock.tsx +511 -0
  34. package/components/ImageAnnotator/Canvas.tsx +118 -0
  35. package/components/ImageAnnotator/Toolbar.tsx +218 -0
  36. package/components/ImageAnnotator/index.tsx +272 -0
  37. package/components/ImageAnnotator/types.ts +39 -0
  38. package/components/ImageAnnotator/utils.ts +147 -0
  39. package/components/ImageThumbnail.tsx +126 -0
  40. package/components/ImportModal.tsx +146 -0
  41. package/components/InlineMarkdown.tsx +1094 -0
  42. package/components/KeyboardShortcuts.tsx +208 -0
  43. package/components/Landing.tsx +496 -0
  44. package/components/ListItemBody.tsx +62 -0
  45. package/components/ListMarker.tsx +73 -0
  46. package/components/LookAndFeelAnnouncementDialog.tsx +230 -0
  47. package/components/MarkdownEditor.tsx +44 -0
  48. package/components/MenuVersionSection.tsx +91 -0
  49. package/components/MermaidBlock.tsx +579 -0
  50. package/components/ModeToggle.tsx +68 -0
  51. package/components/OpenInAppButton.tsx +299 -0
  52. package/components/OverlayScrollArea.tsx +82 -0
  53. package/components/PermissionModeSetup.tsx +92 -0
  54. package/components/PinpointOverlay.tsx +99 -0
  55. package/components/PlanAIAnnouncementDialog.tsx +187 -0
  56. package/components/PlanHeaderMenu.tsx +299 -0
  57. package/components/PopoutDialog.tsx +91 -0
  58. package/components/Popover.tsx +27 -0
  59. package/components/ProviderIcons.tsx +51 -0
  60. package/components/PullRequestIcon.tsx +12 -0
  61. package/components/QuickLabelDropdown.tsx +63 -0
  62. package/components/RenderedMarkdown.tsx +54 -0
  63. package/components/RepoIcon.tsx +12 -0
  64. package/components/ResizeHandle.tsx +86 -0
  65. package/components/ReviewAgentsIcon.tsx +18 -0
  66. package/components/SearchableSelect.tsx +157 -0
  67. package/components/Settings.tsx +2220 -0
  68. package/components/SparklesIcon.tsx +45 -0
  69. package/components/StickyHeaderLane.tsx +260 -0
  70. package/components/TableOfContents.tsx +157 -0
  71. package/components/TaterSpritePullup.tsx +34 -0
  72. package/components/TaterSpriteRunning.tsx +54 -0
  73. package/components/TaterSpriteSitting.tsx +37 -0
  74. package/components/TextShimmer.tsx +57 -0
  75. package/components/ThemeProvider.tsx +162 -0
  76. package/components/ThemeTab.tsx +139 -0
  77. package/components/ToolbarButtons.tsx +116 -0
  78. package/components/Tooltip.tsx +45 -0
  79. package/components/Viewer.tsx +977 -0
  80. package/components/ai/AIProviderBar.tsx +95 -0
  81. package/components/ai/DocumentAIChatPanel.tsx +313 -0
  82. package/components/blocks/AlertBlock.tsx +58 -0
  83. package/components/blocks/Callout.tsx +60 -0
  84. package/components/blocks/CodeBlock.tsx +75 -0
  85. package/components/blocks/HtmlBlock.tsx +122 -0
  86. package/components/blocks/MathBlock.tsx +36 -0
  87. package/components/blocks/TableBlock.tsx +146 -0
  88. package/components/blocks/TablePopout.tsx +279 -0
  89. package/components/blocks/TableToolbar.tsx +153 -0
  90. package/components/blocks/proseBody.tsx +102 -0
  91. package/components/core/button.tsx +44 -0
  92. package/components/core/textarea.tsx +26 -0
  93. package/components/diagramLanguages.ts +14 -0
  94. package/components/goal-setup/GoalSetupSurface.tsx +1354 -0
  95. package/components/html-viewer/HtmlViewer.tsx +386 -0
  96. package/components/html-viewer/bridge-script.ts +505 -0
  97. package/components/html-viewer/index.ts +1 -0
  98. package/components/html-viewer/useHtmlAnnotation.ts +400 -0
  99. package/components/icons/AgentIcons.tsx +66 -0
  100. package/components/icons/AppIcon.tsx +56 -0
  101. package/components/icons/MessagesIcon.tsx +11 -0
  102. package/components/icons/ObsidianIcons.tsx +208 -0
  103. package/components/icons/app/android-studio.svg +369 -0
  104. package/components/icons/app/antigravity.svg +97 -0
  105. package/components/icons/app/cursor.svg +16 -0
  106. package/components/icons/app/file-explorer.svg +20 -0
  107. package/components/icons/app/finder.png +0 -0
  108. package/components/icons/app/ghostty.svg +13 -0
  109. package/components/icons/app/iterm2.svg +13 -0
  110. package/components/icons/app/powershell.svg +14 -0
  111. package/components/icons/app/sublime-text.svg +17 -0
  112. package/components/icons/app/terminal.png +0 -0
  113. package/components/icons/app/textmate.png +0 -0
  114. package/components/icons/app/vscode.svg +39 -0
  115. package/components/icons/app/warp.png +0 -0
  116. package/components/icons/app/xcode.png +0 -0
  117. package/components/icons/app/zed-dark.svg +15 -0
  118. package/components/icons/app/zed.svg +15 -0
  119. package/components/icons/themeIcons.tsx +47 -0
  120. package/components/mermaidSvg.ts +33 -0
  121. package/components/plan-diff/PlanCleanDiffView.tsx +884 -0
  122. package/components/plan-diff/PlanDiffBadge.tsx +48 -0
  123. package/components/plan-diff/PlanDiffModeSwitcher.tsx +103 -0
  124. package/components/plan-diff/PlanDiffViewer.tsx +214 -0
  125. package/components/plan-diff/PlanRawDiffView.tsx +102 -0
  126. package/components/plan-diff/VSCodeIcon.tsx +132 -0
  127. package/components/settings/HooksTab.tsx +208 -0
  128. package/components/sidebar/ArchiveBrowser.tsx +98 -0
  129. package/components/sidebar/CountBadge.tsx +12 -0
  130. package/components/sidebar/FileBrowser.tsx +498 -0
  131. package/components/sidebar/MessagesBrowser.tsx +109 -0
  132. package/components/sidebar/SidebarContainer.tsx +353 -0
  133. package/components/sidebar/SidebarTabs.tsx +155 -0
  134. package/components/sidebar/VersionBrowser.tsx +141 -0
  135. package/components/types.d.ts +7 -0
  136. package/components/ui/badge.tsx +44 -0
  137. package/components/ui/button.tsx +83 -0
  138. package/components/ui/card.tsx +58 -0
  139. package/components/ui/dialog.tsx +106 -0
  140. package/components/ui/dropdown-menu.tsx +240 -0
  141. package/components/ui/state-pill.tsx +45 -0
  142. package/components/ui/tabs.tsx +46 -0
  143. package/components/ui/textarea.tsx +25 -0
  144. package/config/configStore.ts +214 -0
  145. package/config/index.ts +4 -0
  146. package/config/reviewView.ts +42 -0
  147. package/config/settings.ts +310 -0
  148. package/config/useConfig.ts +20 -0
  149. package/configure.ts +69 -0
  150. package/globals.d.ts +14 -0
  151. package/hooks/pfm/useCodeFilePopout.ts +111 -0
  152. package/hooks/useAIChat.ts +532 -0
  153. package/hooks/useAIProviderConfig.ts +115 -0
  154. package/hooks/useActiveSection.ts +78 -0
  155. package/hooks/useAgentJobs.ts +306 -0
  156. package/hooks/useAgentSettings.ts +579 -0
  157. package/hooks/useAgents.ts +90 -0
  158. package/hooks/useAnnotationDraft.ts +523 -0
  159. package/hooks/useAnnotationHighlighter.ts +1170 -0
  160. package/hooks/useArchive.ts +171 -0
  161. package/hooks/useAutoClose.ts +104 -0
  162. package/hooks/useCodeAnnotationDraft.ts +194 -0
  163. package/hooks/useCodeFilePopout.ts +1 -0
  164. package/hooks/useDismissOnOutsideAndEscape.ts +50 -0
  165. package/hooks/useDraggable.ts +108 -0
  166. package/hooks/useEditorAnnotations.ts +64 -0
  167. package/hooks/useExternalAnnotationHighlights.ts +105 -0
  168. package/hooks/useExternalAnnotations.ts +268 -0
  169. package/hooks/useFileBrowser.ts +402 -0
  170. package/hooks/useInputMethodSwitch.ts +89 -0
  171. package/hooks/useIsMobile.ts +17 -0
  172. package/hooks/useLinkedDoc.ts +494 -0
  173. package/hooks/useOverlayViewport.ts +36 -0
  174. package/hooks/usePinpoint.ts +182 -0
  175. package/hooks/usePlanDiff.ts +176 -0
  176. package/hooks/usePrintMode.ts +27 -0
  177. package/hooks/useResizablePanel.ts +173 -0
  178. package/hooks/useScrollViewport.ts +38 -0
  179. package/hooks/useSharing.ts +441 -0
  180. package/hooks/useSidebar.ts +55 -0
  181. package/hooks/useUpdateCheck.ts +132 -0
  182. package/hooks/useValidatedCodePaths.ts +94 -0
  183. package/icons/GitUser.tsx +17 -0
  184. package/lib/utils.ts +11 -0
  185. package/package.json +117 -0
  186. package/plannotator.webp +0 -0
  187. package/print.css +427 -0
  188. package/shortcuts/code-review/ai.shortcuts.ts +25 -0
  189. package/shortcuts/code-review/allFilesDiff.shortcuts.ts +46 -0
  190. package/shortcuts/code-review/annotationToolbar.shortcuts.ts +30 -0
  191. package/shortcuts/code-review/fileTree.shortcuts.ts +35 -0
  192. package/shortcuts/code-review/prComments.shortcuts.ts +18 -0
  193. package/shortcuts/code-review/suggestionModal.shortcuts.ts +25 -0
  194. package/shortcuts/code-review/tourDialog.shortcuts.ts +18 -0
  195. package/shortcuts/core.ts +399 -0
  196. package/shortcuts/index.ts +21 -0
  197. package/shortcuts/plan-review/annotationPanel.shortcuts.ts +25 -0
  198. package/shortcuts/plan-review/annotationToolbar.shortcuts.ts +39 -0
  199. package/shortcuts/plan-review/commentPopover.shortcuts.ts +21 -0
  200. package/shortcuts/plan-review/goalSetup.shortcuts.ts +10 -0
  201. package/shortcuts/plan-review/imageAnnotator.shortcuts.ts +42 -0
  202. package/shortcuts/plan-review/inputMethod.shortcuts.ts +30 -0
  203. package/shortcuts/plan-review/sidebar.shortcuts.ts +34 -0
  204. package/shortcuts/plan-review/viewer.shortcuts.ts +24 -0
  205. package/shortcuts/runtime.ts +259 -0
  206. package/sprite_package_additional/index.html +34 -0
  207. package/sprite_package_additional/sprite.png +0 -0
  208. package/sprite_package_new/index.html +34 -0
  209. package/sprite_package_new/sprite.png +0 -0
  210. package/sprite_package_pulluphang/index.html +34 -0
  211. package/sprite_package_pulluphang/sprite.png +0 -0
  212. package/styles.css +1 -0
  213. package/theme.css +893 -0
  214. package/themes/adwaita.css +62 -0
  215. package/themes/andromeeda.css +66 -0
  216. package/themes/aurora-x.css +66 -0
  217. package/themes/ayu-dark.css +66 -0
  218. package/themes/caffeine.css +113 -0
  219. package/themes/catppuccin.css +62 -0
  220. package/themes/claude-plus.css +60 -0
  221. package/themes/cursor-hc.css +34 -0
  222. package/themes/cursor-midnight.css +34 -0
  223. package/themes/cursor.css +62 -0
  224. package/themes/dark-plus.css +66 -0
  225. package/themes/doom-64.css +109 -0
  226. package/themes/dracula.css +33 -0
  227. package/themes/everforest-hard.css +62 -0
  228. package/themes/everforest-soft.css +62 -0
  229. package/themes/everforest.css +62 -0
  230. package/themes/github.css +66 -0
  231. package/themes/gruvbox.css +62 -0
  232. package/themes/houston.css +66 -0
  233. package/themes/kanagawa-dragon.css +34 -0
  234. package/themes/kanagawa-lotus.css +34 -0
  235. package/themes/kanagawa-wave.css +34 -0
  236. package/themes/laserwave.css +66 -0
  237. package/themes/material.css +62 -0
  238. package/themes/min.css +66 -0
  239. package/themes/monokai-pro.css +34 -0
  240. package/themes/neutral.css +59 -0
  241. package/themes/night-owl.css +66 -0
  242. package/themes/nord.css +66 -0
  243. package/themes/one-dark-pro.css +66 -0
  244. package/themes/one-light.css +66 -0
  245. package/themes/paulmillr.css +34 -0
  246. package/themes/plannotator.css +60 -0
  247. package/themes/plastic.css +66 -0
  248. package/themes/poimandres.css +66 -0
  249. package/themes/quantum-rose.css +109 -0
  250. package/themes/red.css +66 -0
  251. package/themes/rose-pine.css +62 -0
  252. package/themes/simple.css +124 -0
  253. package/themes/slack.css +66 -0
  254. package/themes/snazzy-light.css +66 -0
  255. package/themes/soft-pop.css +60 -0
  256. package/themes/solar-dusk.css +109 -0
  257. package/themes/solarized.css +66 -0
  258. package/themes/synthwave-84.css +34 -0
  259. package/themes/terminal.css +62 -0
  260. package/themes/tinacious.css +57 -0
  261. package/themes/tokyo-night.css +62 -0
  262. package/themes/vesper.css +62 -0
  263. package/themes/vitesse-black.css +66 -0
  264. package/themes/vitesse.css +62 -0
  265. package/types.ts +264 -0
  266. package/utils/agentSwitch.ts +71 -0
  267. package/utils/aiChatFormat.ts +33 -0
  268. package/utils/aiPrompt.ts +29 -0
  269. package/utils/aiProvider.ts +217 -0
  270. package/utils/anchors.ts +11 -0
  271. package/utils/annotateAgentTerminal.ts +29 -0
  272. package/utils/annotationHelpers.ts +101 -0
  273. package/utils/bear.ts +59 -0
  274. package/utils/blockTargeting.ts +240 -0
  275. package/utils/callback.ts +99 -0
  276. package/utils/commentContent.ts +8 -0
  277. package/utils/defaultNotesApp.ts +20 -0
  278. package/utils/diffFonts.ts +33 -0
  279. package/utils/editorMode.ts +31 -0
  280. package/utils/fileBrowser.ts +40 -0
  281. package/utils/generateId.ts +7 -0
  282. package/utils/generateIdentity.ts +29 -0
  283. package/utils/identity.ts +112 -0
  284. package/utils/inlineTransforms.ts +41 -0
  285. package/utils/inputMethod.ts +17 -0
  286. package/utils/lookAndFeelAnnouncement.ts +18 -0
  287. package/utils/obsidian.ts +201 -0
  288. package/utils/octarine.ts +53 -0
  289. package/utils/parser.ts +991 -0
  290. package/utils/permissionMode.ts +77 -0
  291. package/utils/planAIAnnouncement.ts +17 -0
  292. package/utils/planAgentInstructions.ts +137 -0
  293. package/utils/planDiffEngine.ts +590 -0
  294. package/utils/planSave.ts +49 -0
  295. package/utils/platform.ts +11 -0
  296. package/utils/quickLabels.ts +77 -0
  297. package/utils/reviewAgentInstructions.ts +182 -0
  298. package/utils/sanitizeHtml.ts +45 -0
  299. package/utils/sharing.ts +350 -0
  300. package/utils/slugify.ts +37 -0
  301. package/utils/storage.ts +141 -0
  302. package/utils/themeRegistry.ts +567 -0
  303. package/utils/uiPreferences.ts +34 -0
  304. package/utils/upload.ts +56 -0
  305. package/utils/wideMode.ts +48 -0
@@ -0,0 +1,83 @@
1
+ import { Slot, Slottable } from "@radix-ui/react-slot";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import type * as React from "react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ /**
8
+ * Button — the canonical action primitive (shared by the frontend shell and the
9
+ * embedded plan/review apps). cva variants + sizes, optional `iconLeft`/`iconRight`
10
+ * slots, and `asChild` for polymorphism.
11
+ *
12
+ * `success` (solid, token-driven green) covers the plan app's Approve action; the
13
+ * Feedback action uses `outline`. (No `accent` variant — `text-accent` on `bg-accent`
14
+ * has no contrast in neutral-accent themes.)
15
+ */
16
+ const buttonVariants = cva(
17
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-[13px] font-medium transition-[color,background-color,box-shadow] disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
18
+ {
19
+ variants: {
20
+ variant: {
21
+ default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
22
+ destructive:
23
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
24
+ success: "bg-success text-success-foreground shadow-xs hover:bg-success/90",
25
+ outline:
26
+ "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground",
27
+ secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
28
+ ghost: "hover:bg-accent hover:text-accent-foreground",
29
+ link: "text-primary underline-offset-4 hover:underline",
30
+ },
31
+ size: {
32
+ default: "h-9 px-4 py-2",
33
+ xxs: "h-6 rounded-md gap-1.5 px-2.5",
34
+ xs: "h-7 rounded-md gap-1.5 px-2.5",
35
+ sm: "h-8 rounded-md gap-1.5 px-3",
36
+ lg: "h-10 rounded-md px-6",
37
+ icon: "size-9",
38
+ },
39
+ },
40
+ defaultVariants: {
41
+ variant: "default",
42
+ size: "default",
43
+ },
44
+ },
45
+ );
46
+
47
+ type ButtonIcon = React.ReactNode;
48
+
49
+ function Button({
50
+ children,
51
+ className,
52
+ variant,
53
+ size,
54
+ asChild = false,
55
+ iconLeft,
56
+ iconRight,
57
+ ...props
58
+ }: React.ComponentProps<"button"> &
59
+ VariantProps<typeof buttonVariants> & {
60
+ asChild?: boolean;
61
+ iconLeft?: ButtonIcon;
62
+ iconRight?: ButtonIcon;
63
+ }) {
64
+ const Comp = asChild ? Slot : "button";
65
+
66
+ return (
67
+ <Comp data-slot="button" className={cn(buttonVariants({ variant, size, className }))} {...props}>
68
+ {iconLeft ? (
69
+ <span data-slot="button-icon" data-side="left" aria-hidden="true" className="shrink-0">
70
+ {iconLeft}
71
+ </span>
72
+ ) : null}
73
+ <Slottable>{children}</Slottable>
74
+ {iconRight ? (
75
+ <span data-slot="button-icon" data-side="right" aria-hidden="true" className="shrink-0">
76
+ {iconRight}
77
+ </span>
78
+ ) : null}
79
+ </Comp>
80
+ );
81
+ }
82
+
83
+ export { Button, buttonVariants };
@@ -0,0 +1,58 @@
1
+ import type * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ /**
6
+ * Card — surface container primitive (shadcn-style).
7
+ *
8
+ * Composition: Card > CardHeader (CardTitle + CardDescription) / CardContent / CardFooter.
9
+ * Uses the shared token surface (`bg-card`/`text-card-foreground`) so it adapts to every
10
+ * theme. Pair with `shadow-[var(--card-shadow)]` (instead of `shadow-sm`) when you want
11
+ * the themed elevation used across the app shell.
12
+ */
13
+ function Card({ className, ...props }: React.ComponentProps<"div">) {
14
+ return (
15
+ <div
16
+ data-slot="card"
17
+ className={cn(
18
+ "flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
19
+ className,
20
+ )}
21
+ {...props}
22
+ />
23
+ );
24
+ }
25
+
26
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
27
+ return (
28
+ <div data-slot="card-header" className={cn("flex flex-col gap-1.5 px-6", className)} {...props} />
29
+ );
30
+ }
31
+
32
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
33
+ return (
34
+ <div data-slot="card-title" className={cn("font-semibold leading-none", className)} {...props} />
35
+ );
36
+ }
37
+
38
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
39
+ return (
40
+ <div
41
+ data-slot="card-description"
42
+ className={cn("text-sm text-muted-foreground", className)}
43
+ {...props}
44
+ />
45
+ );
46
+ }
47
+
48
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
49
+ return <div data-slot="card-content" className={cn("px-6", className)} {...props} />;
50
+ }
51
+
52
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
53
+ return (
54
+ <div data-slot="card-footer" className={cn("flex items-center px-6", className)} {...props} />
55
+ );
56
+ }
57
+
58
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
@@ -0,0 +1,106 @@
1
+ import * as React from "react";
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
3
+ import { X } from "lucide-react";
4
+ import { cn } from "../../lib/utils";
5
+
6
+ const Dialog = DialogPrimitive.Root;
7
+ const DialogTrigger = DialogPrimitive.Trigger;
8
+ const DialogPortal = DialogPrimitive.Portal;
9
+ const DialogClose = DialogPrimitive.Close;
10
+
11
+ const DialogOverlay = React.forwardRef<
12
+ React.ComponentRef<typeof DialogPrimitive.Overlay>,
13
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
14
+ >(({ className, ...props }, ref) => (
15
+ <DialogPrimitive.Overlay
16
+ ref={ref}
17
+ className={cn(
18
+ "fixed inset-0 z-[110] bg-black/55 backdrop-blur-[2px]",
19
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0",
20
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0",
21
+ className,
22
+ )}
23
+ {...props}
24
+ />
25
+ ));
26
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
27
+
28
+ const DialogContent = React.forwardRef<
29
+ React.ComponentRef<typeof DialogPrimitive.Content>,
30
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
31
+ hideClose?: boolean;
32
+ }
33
+ >(({ className, children, hideClose, ...props }, ref) => (
34
+ <DialogPortal>
35
+ <DialogOverlay />
36
+ <DialogPrimitive.Content
37
+ ref={ref}
38
+ className={cn(
39
+ "fixed top-[50%] left-[50%] z-[110] w-full translate-x-[-50%] translate-y-[-50%]",
40
+ "max-w-4xl max-h-[min(640px,85vh)]",
41
+ "flex flex-col overflow-hidden",
42
+ "rounded-2xl border border-border bg-popover text-popover-foreground",
43
+ "shadow-[0_24px_80px_-36px_rgba(15,23,42,0.5)]",
44
+ "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
45
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
46
+ "duration-200",
47
+ className,
48
+ )}
49
+ {...props}
50
+ >
51
+ {children}
52
+ {!hideClose && (
53
+ <DialogPrimitive.Close className="absolute top-3.5 right-3.5 rounded-md p-1.5 text-muted-foreground hover:text-foreground focus:outline-none focus:ring-2 focus:ring-ring/50">
54
+ <X className="size-4" />
55
+ <span className="sr-only">Close</span>
56
+ </DialogPrimitive.Close>
57
+ )}
58
+ </DialogPrimitive.Content>
59
+ </DialogPortal>
60
+ ));
61
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
62
+
63
+ function DialogHeader({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {
64
+ return (
65
+ <div
66
+ className={cn("flex flex-col gap-1.5 border-b border-border px-5 py-4", className)}
67
+ {...props}
68
+ />
69
+ );
70
+ }
71
+
72
+ const DialogTitle = React.forwardRef<
73
+ React.ComponentRef<typeof DialogPrimitive.Title>,
74
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
75
+ >(({ className, ...props }, ref) => (
76
+ <DialogPrimitive.Title
77
+ ref={ref}
78
+ className={cn("text-base font-semibold tracking-tight", className)}
79
+ {...props}
80
+ />
81
+ ));
82
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
83
+
84
+ const DialogDescription = React.forwardRef<
85
+ React.ComponentRef<typeof DialogPrimitive.Description>,
86
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
87
+ >(({ className, ...props }, ref) => (
88
+ <DialogPrimitive.Description
89
+ ref={ref}
90
+ className={cn("text-sm text-muted-foreground", className)}
91
+ {...props}
92
+ />
93
+ ));
94
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
95
+
96
+ export {
97
+ Dialog,
98
+ DialogPortal,
99
+ DialogOverlay,
100
+ DialogClose,
101
+ DialogTrigger,
102
+ DialogContent,
103
+ DialogHeader,
104
+ DialogTitle,
105
+ DialogDescription,
106
+ };
@@ -0,0 +1,240 @@
1
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
2
+ import { Check, ChevronRight, Circle } from "lucide-react";
3
+ import type * as React from "react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ /**
8
+ * DropdownMenu — Radix-backed menu primitive (shadcn-style). Replaces the plan app's
9
+ * hand-rolled Approve dropdown / label picker / header menus. Icons via lucide-react.
10
+ */
11
+ function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
12
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
13
+ }
14
+
15
+ function DropdownMenuPortal({
16
+ ...props
17
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
18
+ return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
19
+ }
20
+
21
+ function DropdownMenuTrigger({
22
+ ...props
23
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
24
+ return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;
25
+ }
26
+
27
+ function DropdownMenuContent({
28
+ className,
29
+ sideOffset = 4,
30
+ ...props
31
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
32
+ return (
33
+ <DropdownMenuPrimitive.Portal>
34
+ <DropdownMenuPrimitive.Content
35
+ data-slot="dropdown-menu-content"
36
+ sideOffset={sideOffset}
37
+ className={cn(
38
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
39
+ className,
40
+ )}
41
+ {...props}
42
+ />
43
+ </DropdownMenuPrimitive.Portal>
44
+ );
45
+ }
46
+
47
+ function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
48
+ return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
49
+ }
50
+
51
+ function DropdownMenuItem({
52
+ className,
53
+ inset,
54
+ variant = "default",
55
+ ...props
56
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
57
+ inset?: boolean;
58
+ variant?: "default" | "destructive";
59
+ }) {
60
+ return (
61
+ <DropdownMenuPrimitive.Item
62
+ data-slot="dropdown-menu-item"
63
+ data-inset={inset}
64
+ data-variant={variant}
65
+ className={cn(
66
+ "relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5 font-medium outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
67
+ className,
68
+ )}
69
+ {...props}
70
+ />
71
+ );
72
+ }
73
+
74
+ function DropdownMenuCheckboxItem({
75
+ className,
76
+ children,
77
+ checked,
78
+ ...props
79
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
80
+ return (
81
+ <DropdownMenuPrimitive.CheckboxItem
82
+ data-slot="dropdown-menu-checkbox-item"
83
+ className={cn(
84
+ "relative flex cursor-default select-none items-center gap-2 rounded-md py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
85
+ className,
86
+ )}
87
+ checked={checked}
88
+ {...props}
89
+ >
90
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
91
+ <DropdownMenuPrimitive.ItemIndicator>
92
+ <Check className="size-4" />
93
+ </DropdownMenuPrimitive.ItemIndicator>
94
+ </span>
95
+ {children}
96
+ </DropdownMenuPrimitive.CheckboxItem>
97
+ );
98
+ }
99
+
100
+ function DropdownMenuRadioGroup({
101
+ ...props
102
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
103
+ return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
104
+ }
105
+
106
+ function DropdownMenuRadioItem({
107
+ className,
108
+ children,
109
+ ...props
110
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
111
+ return (
112
+ <DropdownMenuPrimitive.RadioItem
113
+ data-slot="dropdown-menu-radio-item"
114
+ className={cn(
115
+ "relative flex cursor-default select-none items-center gap-2 rounded-md py-1.5 pl-8 pr-2 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
116
+ className,
117
+ )}
118
+ {...props}
119
+ >
120
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
121
+ <DropdownMenuPrimitive.ItemIndicator>
122
+ <Circle className="size-2 fill-current" />
123
+ </DropdownMenuPrimitive.ItemIndicator>
124
+ </span>
125
+ {children}
126
+ </DropdownMenuPrimitive.RadioItem>
127
+ );
128
+ }
129
+
130
+ function DropdownMenuLabel({
131
+ className,
132
+ inset,
133
+ ...props
134
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {
135
+ return (
136
+ <DropdownMenuPrimitive.Label
137
+ data-slot="dropdown-menu-label"
138
+ data-inset={inset}
139
+ className={cn("px-2 py-1.5 font-medium data-[inset]:pl-8", className)}
140
+ {...props}
141
+ />
142
+ );
143
+ }
144
+
145
+ function DropdownMenuSeparator({
146
+ className,
147
+ ...props
148
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
149
+ return (
150
+ <DropdownMenuPrimitive.Separator
151
+ data-slot="dropdown-menu-separator"
152
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
153
+ {...props}
154
+ />
155
+ );
156
+ }
157
+
158
+ function DropdownMenuShortcut({
159
+ className,
160
+ keys,
161
+ children,
162
+ ...props
163
+ }: React.ComponentProps<"span"> & { keys?: string[] }) {
164
+ return (
165
+ <span
166
+ data-slot="dropdown-menu-shortcut"
167
+ className={cn("ml-auto flex items-center gap-1 text-[11px] text-muted-foreground", className)}
168
+ {...props}
169
+ >
170
+ {keys
171
+ ? keys.map((key, i) => (
172
+ <span key={key} className="flex items-center gap-1">
173
+ {i > 0 && <span>then</span>}
174
+ <kbd className="font-sans">{key}</kbd>
175
+ </span>
176
+ ))
177
+ : children}
178
+ </span>
179
+ );
180
+ }
181
+
182
+ function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
183
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
184
+ }
185
+
186
+ function DropdownMenuSubTrigger({
187
+ className,
188
+ inset,
189
+ children,
190
+ ...props
191
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {
192
+ return (
193
+ <DropdownMenuPrimitive.SubTrigger
194
+ data-slot="dropdown-menu-sub-trigger"
195
+ data-inset={inset}
196
+ className={cn(
197
+ "flex cursor-default select-none items-center rounded-md px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
198
+ className,
199
+ )}
200
+ {...props}
201
+ >
202
+ {children}
203
+ <ChevronRight className="ml-auto size-4" />
204
+ </DropdownMenuPrimitive.SubTrigger>
205
+ );
206
+ }
207
+
208
+ function DropdownMenuSubContent({
209
+ className,
210
+ ...props
211
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
212
+ return (
213
+ <DropdownMenuPrimitive.SubContent
214
+ data-slot="dropdown-menu-sub-content"
215
+ className={cn(
216
+ "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
217
+ className,
218
+ )}
219
+ {...props}
220
+ />
221
+ );
222
+ }
223
+
224
+ export {
225
+ DropdownMenu,
226
+ DropdownMenuPortal,
227
+ DropdownMenuTrigger,
228
+ DropdownMenuContent,
229
+ DropdownMenuGroup,
230
+ DropdownMenuLabel,
231
+ DropdownMenuItem,
232
+ DropdownMenuCheckboxItem,
233
+ DropdownMenuRadioGroup,
234
+ DropdownMenuRadioItem,
235
+ DropdownMenuSeparator,
236
+ DropdownMenuShortcut,
237
+ DropdownMenuSub,
238
+ DropdownMenuSubTrigger,
239
+ DropdownMenuSubContent,
240
+ };
@@ -0,0 +1,45 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import type * as React from "react";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ /**
7
+ * StatePill — semantic status indicator (PR/issue/session state). Rounded-full pill
8
+ * with tone-based color. Uses standard color ramps (green/red/purple) for instantly
9
+ * legible state rather than theme accent tokens.
10
+ */
11
+ const statePillVariants = cva(
12
+ "inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full px-2 py-0.5 text-xs font-medium",
13
+ {
14
+ variants: {
15
+ tone: {
16
+ open: "bg-green-500/10 text-green-500",
17
+ closed: "bg-red-500/10 text-red-500",
18
+ merged: "bg-purple-500/10 text-purple-500",
19
+ muted: "bg-muted text-muted-foreground",
20
+ secondary: "bg-secondary text-secondary-foreground",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ tone: "muted",
25
+ },
26
+ },
27
+ );
28
+
29
+ export type StatePillTone = NonNullable<VariantProps<typeof statePillVariants>["tone"]>;
30
+
31
+ function StatePill({
32
+ className,
33
+ tone,
34
+ ...props
35
+ }: React.ComponentProps<"span"> & VariantProps<typeof statePillVariants>) {
36
+ return (
37
+ <span
38
+ data-slot="state-pill"
39
+ className={cn(statePillVariants({ tone }), className)}
40
+ {...props}
41
+ />
42
+ );
43
+ }
44
+
45
+ export { StatePill, statePillVariants };
@@ -0,0 +1,46 @@
1
+ import * as React from "react";
2
+ import * as TabsPrimitive from "@radix-ui/react-tabs";
3
+ import { cn } from "../../lib/utils";
4
+
5
+ const Tabs = TabsPrimitive.Root;
6
+
7
+ const TabsList = React.forwardRef<
8
+ React.ComponentRef<typeof TabsPrimitive.List>,
9
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
10
+ >(({ className, ...props }, ref) => (
11
+ <TabsPrimitive.List
12
+ ref={ref}
13
+ className={cn("flex data-[orientation=vertical]:flex-col", className)}
14
+ {...props}
15
+ />
16
+ ));
17
+ TabsList.displayName = TabsPrimitive.List.displayName;
18
+
19
+ const TabsTrigger = React.forwardRef<
20
+ React.ComponentRef<typeof TabsPrimitive.Trigger>,
21
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
22
+ >(({ className, ...props }, ref) => (
23
+ <TabsPrimitive.Trigger
24
+ ref={ref}
25
+ className={cn(
26
+ "inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-[13px] font-medium text-foreground",
27
+ "hover:bg-surface-1",
28
+ "data-[state=active]:bg-primary/10 data-[state=active]:text-foreground",
29
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
30
+ "disabled:pointer-events-none disabled:opacity-50",
31
+ className,
32
+ )}
33
+ {...props}
34
+ />
35
+ ));
36
+ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
37
+
38
+ const TabsContent = React.forwardRef<
39
+ React.ComponentRef<typeof TabsPrimitive.Content>,
40
+ React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
41
+ >(({ className, ...props }, ref) => (
42
+ <TabsPrimitive.Content ref={ref} className={cn("flex-1 outline-none", className)} {...props} />
43
+ ));
44
+ TabsContent.displayName = TabsPrimitive.Content.displayName;
45
+
46
+ export { Tabs, TabsList, TabsTrigger, TabsContent };
@@ -0,0 +1,25 @@
1
+ import type * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ /**
6
+ * Textarea — multi-line text input primitive. `field-sizing-content` auto-grows to
7
+ * fit content. Defaults to `bg-background`; pass `bg-card` via className when used
8
+ * inside an elevated surface (e.g. annotation/comment editors).
9
+ */
10
+ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
11
+ return (
12
+ <textarea
13
+ data-slot="textarea"
14
+ className={cn(
15
+ "flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-background px-3 py-2 text-base shadow-xs outline-none transition-[color,box-shadow] placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
16
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
17
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
18
+ className,
19
+ )}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+
25
+ export { Textarea };