@gunjo/ui 0.0.1-alpha.0 → 0.0.1-alpha.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 (224) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +90 -0
  3. package/README.md +52 -91
  4. package/package.json +47 -6
  5. package/src/components/display/Accordion.tsx +185 -0
  6. package/src/components/display/AccordionGroup.tsx +155 -0
  7. package/src/components/display/ActionDataTable.tsx +413 -0
  8. package/src/components/display/ActivityTimelineCard.tsx +483 -0
  9. package/src/components/display/AnalyticsCard.tsx +167 -0
  10. package/src/components/display/AssetCard.tsx +242 -0
  11. package/src/components/display/AssetGrid.tsx +164 -0
  12. package/src/components/display/Avatar.tsx +127 -0
  13. package/src/components/display/AvatarGroup.tsx +131 -0
  14. package/src/components/{atoms → display}/Badge.tsx +3 -3
  15. package/src/components/display/BarChart.tsx +247 -0
  16. package/src/components/{molecules → display}/Card.tsx +1 -1
  17. package/src/components/display/Carousel.tsx +593 -0
  18. package/src/components/display/ChartLegend.tsx +124 -0
  19. package/src/components/display/ChatMessage.tsx +382 -0
  20. package/src/components/display/ChoroplethMap.tsx +613 -0
  21. package/src/components/display/Code.tsx +42 -0
  22. package/src/components/display/CodeBlock.tsx +338 -0
  23. package/src/components/display/ColorSwatch.tsx +71 -0
  24. package/src/components/display/ConcentricProgressCard.tsx +545 -0
  25. package/src/components/display/DataTable.tsx +522 -0
  26. package/src/components/display/DistributionBar.tsx +102 -0
  27. package/src/components/display/DocNote.tsx +36 -0
  28. package/src/components/display/DonutChart.tsx +257 -0
  29. package/src/components/display/EmptyState.tsx +44 -0
  30. package/src/components/display/FileTree.tsx +180 -0
  31. package/src/components/display/GaugeChart.tsx +219 -0
  32. package/src/components/display/HeatmapChart.tsx +266 -0
  33. package/src/components/display/Icon.tsx +66 -0
  34. package/src/components/display/ImagePreview.tsx +140 -0
  35. package/src/components/{atoms → display}/Img.tsx +46 -12
  36. package/src/components/display/LabeledDonutCard.tsx +475 -0
  37. package/src/components/display/LineChart.tsx +464 -0
  38. package/src/components/{molecules → display}/List.tsx +20 -13
  39. package/src/components/display/MarkdownRenderer.tsx +157 -0
  40. package/src/components/display/MetadataList.tsx +81 -0
  41. package/src/components/display/MiniDistributionBarCard.tsx +314 -0
  42. package/src/components/display/PieChart.tsx +234 -0
  43. package/src/components/display/QuadrantMatrix.tsx +330 -0
  44. package/src/components/display/RadarChart.tsx +335 -0
  45. package/src/components/display/RadialBarChart.tsx +264 -0
  46. package/src/components/display/RetentionCohortCard.tsx +350 -0
  47. package/src/components/display/RibbonChart.tsx +618 -0
  48. package/src/components/display/SearchableAccordion.tsx +270 -0
  49. package/src/components/display/SegmentTimelineCard.tsx +452 -0
  50. package/src/components/display/SegmentedGaugeCard.tsx +607 -0
  51. package/src/components/display/Spacer.tsx +51 -0
  52. package/src/components/display/SparklineChart.tsx +394 -0
  53. package/src/components/display/StackedBarChart.tsx +393 -0
  54. package/src/components/display/Statistic.tsx +70 -0
  55. package/src/components/{molecules → display}/Table.tsx +22 -7
  56. package/src/components/display/Tag.tsx +80 -0
  57. package/src/components/display/TagEditor.tsx +141 -0
  58. package/src/components/display/Timeline.tsx +121 -0
  59. package/src/components/{atoms → display}/ToolPill.tsx +42 -18
  60. package/src/components/display/TreeView.tsx +226 -0
  61. package/src/components/display/chart-tooltip.tsx +423 -0
  62. package/src/components/display/chart-utils.ts +71 -0
  63. package/src/components/display/circular-chart-utils.ts +147 -0
  64. package/src/components/display/generated/default-variant-keys.ts +90 -0
  65. package/src/components/display/generated/variant-keys.ts +169 -0
  66. package/src/components/{atoms → feedback}/Alert.tsx +12 -5
  67. package/src/components/feedback/Banner.tsx +90 -0
  68. package/src/components/{molecules → feedback}/NotificationCenter.tsx +64 -31
  69. package/src/components/feedback/ProgressWidget.tsx +44 -0
  70. package/src/components/{atoms → feedback}/Spinner.tsx +2 -2
  71. package/src/components/{molecules → feedback}/StatusBar.tsx +4 -4
  72. package/src/components/feedback/StatusScreen.tsx +148 -0
  73. package/src/components/{molecules → feedback}/Stepper.tsx +10 -5
  74. package/src/components/feedback/Toast.tsx +108 -0
  75. package/src/components/feedback/ToastProvider.tsx +78 -0
  76. package/src/components/feedback/generated/default-variant-keys.ts +16 -0
  77. package/src/components/feedback/generated/variant-keys.ts +21 -0
  78. package/src/components/generated/component-manifest.ts +1568 -454
  79. package/src/components/generated/component-style-hints.ts +1958 -718
  80. package/src/components/{atoms → inputs}/ButtonVariants.ts +13 -3
  81. package/src/components/inputs/Calendar.tsx +212 -0
  82. package/src/components/inputs/ChatComposer.tsx +75 -0
  83. package/src/components/inputs/ChatInput.tsx +528 -0
  84. package/src/components/{atoms → inputs}/Checkbox.tsx +2 -2
  85. package/src/components/inputs/Combobox.tsx +175 -0
  86. package/src/components/inputs/CopyButton.tsx +187 -0
  87. package/src/components/inputs/DatePicker.tsx +519 -0
  88. package/src/components/inputs/DateRangePicker.tsx +878 -0
  89. package/src/components/inputs/EditableField.tsx +182 -0
  90. package/src/components/{organisms → inputs}/FileUploader.tsx +24 -9
  91. package/src/components/inputs/FilterButton.tsx +163 -0
  92. package/src/components/{molecules → inputs}/Form.tsx +20 -3
  93. package/src/components/{atoms → inputs}/Input.tsx +2 -0
  94. package/src/components/inputs/InputOTP.tsx +75 -0
  95. package/src/components/inputs/Mention.tsx +279 -0
  96. package/src/components/inputs/NumberInput.tsx +109 -0
  97. package/src/components/inputs/PasswordGroup.tsx +138 -0
  98. package/src/components/inputs/PasswordInput.tsx +74 -0
  99. package/src/components/inputs/PasswordRequirementList.tsx +96 -0
  100. package/src/components/inputs/PasswordStrengthMeter.tsx +93 -0
  101. package/src/components/inputs/PhoneInput.tsx +99 -0
  102. package/src/components/inputs/PostalCodeInput.tsx +98 -0
  103. package/src/components/inputs/RangeSlider.tsx +129 -0
  104. package/src/components/inputs/SearchInput.tsx +76 -0
  105. package/src/components/inputs/Select.tsx +39 -0
  106. package/src/components/{atoms → inputs}/Slider.tsx +18 -5
  107. package/src/components/{molecules → inputs}/SortButton.tsx +5 -2
  108. package/src/components/{atoms → inputs}/Switch.tsx +15 -4
  109. package/src/components/inputs/TagInput.tsx +114 -0
  110. package/src/components/{atoms → inputs}/Textarea.tsx +1 -0
  111. package/src/components/inputs/TimePicker.tsx +150 -0
  112. package/src/components/inputs/Toggle.tsx +48 -0
  113. package/src/components/{atoms → inputs}/ToggleGroup.tsx +2 -2
  114. package/src/components/inputs/TooltipButton.tsx +148 -0
  115. package/src/components/inputs/VoiceInputButton.tsx +317 -0
  116. package/src/components/inputs/calendar-holidays.ts +56 -0
  117. package/src/components/inputs/generated/default-variant-keys.ts +32 -0
  118. package/src/components/{atoms → inputs}/generated/variant-keys.ts +19 -27
  119. package/src/components/layout/AspectRatio.tsx +12 -0
  120. package/src/components/layout/AssetInspectorPanel.tsx +416 -0
  121. package/src/components/layout/Cluster.tsx +56 -0
  122. package/src/components/layout/CollapsiblePanelToggle.tsx +94 -0
  123. package/src/components/layout/Container.tsx +43 -0
  124. package/src/components/layout/DeviceFrame.tsx +227 -0
  125. package/src/components/layout/Grid.tsx +65 -0
  126. package/src/components/layout/HStack.tsx +73 -0
  127. package/src/components/{organisms → layout}/InspectorPanel.tsx +6 -5
  128. package/src/components/layout/MarqueeFrame.tsx +158 -0
  129. package/src/components/layout/Resizable.tsx +94 -0
  130. package/src/components/layout/ScrollArea.tsx +71 -0
  131. package/src/components/{organisms → layout}/SpatialCanvas.tsx +12 -7
  132. package/src/components/layout/VStack.tsx +69 -0
  133. package/src/components/layout/generated/default-variant-keys.ts +16 -0
  134. package/src/components/layout/generated/variant-keys.ts +21 -0
  135. package/src/components/{molecules → navigation}/Breadcrumb.tsx +5 -4
  136. package/src/components/navigation/Command.tsx +266 -0
  137. package/src/components/navigation/CommandPalette.tsx +83 -0
  138. package/src/components/navigation/DocumentPager.tsx +171 -0
  139. package/src/components/navigation/Footer.tsx +88 -0
  140. package/src/components/navigation/Header.tsx +80 -0
  141. package/src/components/{molecules → navigation}/Menubar.tsx +45 -12
  142. package/src/components/navigation/NavigationMenu.tsx +128 -0
  143. package/src/components/navigation/PageAside.tsx +84 -0
  144. package/src/components/{molecules → navigation}/Pagination.tsx +60 -7
  145. package/src/components/{organisms → navigation}/RightRail.tsx +1 -1
  146. package/src/components/navigation/Sidebar.tsx +223 -0
  147. package/src/components/navigation/SidebarItem.tsx +160 -0
  148. package/src/components/{molecules → navigation}/Tabs.tsx +2 -2
  149. package/src/components/navigation/TextLink.tsx +71 -0
  150. package/src/components/navigation/generated/default-variant-keys.ts +12 -0
  151. package/src/components/navigation/generated/variant-keys.ts +13 -0
  152. package/src/components/overlay/AIChatInput.tsx +5 -0
  153. package/src/components/overlay/AIChatMessage.tsx +6 -0
  154. package/src/components/overlay/AlertDialog.tsx +145 -0
  155. package/src/components/overlay/ChatPanel.tsx +180 -0
  156. package/src/components/{molecules → overlay}/ContextMenu.tsx +65 -29
  157. package/src/components/{molecules → overlay}/Dialog.tsx +21 -13
  158. package/src/components/overlay/Drawer.tsx +131 -0
  159. package/src/components/{molecules → overlay}/DropdownMenu.tsx +52 -17
  160. package/src/components/overlay/FloatingPanel.tsx +90 -0
  161. package/src/components/overlay/HoverCard.tsx +36 -0
  162. package/src/components/overlay/MediaLightbox.tsx +403 -0
  163. package/src/components/overlay/MediaPickerDialog.tsx +198 -0
  164. package/src/components/overlay/Modal.tsx +103 -0
  165. package/src/components/overlay/OnboardingFlow.tsx +172 -0
  166. package/src/components/overlay/Popover.tsx +36 -0
  167. package/src/components/overlay/ShareModal.tsx +324 -0
  168. package/src/components/{molecules → overlay}/Sheet.tsx +76 -19
  169. package/src/components/overlay/Tooltip.tsx +130 -0
  170. package/src/components/overlay/generated/default-variant-keys.ts +14 -0
  171. package/src/components/overlay/generated/variant-keys.ts +17 -0
  172. package/src/components/patterns/BlogTemplate.tsx +46 -0
  173. package/src/components/{templates → patterns}/DashboardTemplate.tsx +2 -2
  174. package/src/components/patterns/DocsTemplate.tsx +41 -0
  175. package/src/components/{templates → patterns}/MediaLibraryTemplate.tsx +1 -1
  176. package/src/components/patterns/OnboardingTemplate.tsx +32 -0
  177. package/src/components/patterns/PricingTemplate.tsx +106 -0
  178. package/src/globals.css +173 -22
  179. package/src/index.ts +177 -76
  180. package/tailwind-theme-extend.cjs +48 -3
  181. package/design/atoms-metadata.json +0 -82
  182. package/design/molecules-metadata.json +0 -130
  183. package/design/organisms-metadata.json +0 -38
  184. package/design/templates-metadata.json +0 -38
  185. package/src/components/atoms/Avatar.tsx +0 -57
  186. package/src/components/atoms/Select.tsx +0 -28
  187. package/src/components/atoms/generated/default-variant-keys.ts +0 -36
  188. package/src/components/molecules/AIChatInput.tsx +0 -140
  189. package/src/components/molecules/AIChatMessage.tsx +0 -109
  190. package/src/components/molecules/Accordion.tsx +0 -99
  191. package/src/components/molecules/Calendar.tsx +0 -60
  192. package/src/components/molecules/Carousel.tsx +0 -261
  193. package/src/components/molecules/Command.tsx +0 -152
  194. package/src/components/molecules/FilterButton.tsx +0 -133
  195. package/src/components/molecules/HoverCard.tsx +0 -29
  196. package/src/components/molecules/Modal.tsx +0 -66
  197. package/src/components/molecules/Popover.tsx +0 -31
  198. package/src/components/molecules/ProgressWidget.tsx +0 -40
  199. package/src/components/molecules/Resizable.tsx +0 -47
  200. package/src/components/molecules/ScrollArea.tsx +0 -48
  201. package/src/components/molecules/SidebarItem.tsx +0 -134
  202. package/src/components/molecules/Toast.tsx +0 -57
  203. package/src/components/molecules/Tooltip.tsx +0 -30
  204. package/src/components/molecules/generated/default-variant-keys.ts +0 -22
  205. package/src/components/molecules/generated/variant-keys.ts +0 -33
  206. package/src/components/organisms/CommandPalette.tsx +0 -58
  207. package/src/components/organisms/FloatingPanel.tsx +0 -46
  208. package/src/components/organisms/ShareModal.tsx +0 -182
  209. package/src/components/organisms/ToastProvider.tsx +0 -49
  210. /package/src/components/{atoms → display}/Kbd.tsx +0 -0
  211. /package/src/components/{atoms → display}/Separator.tsx +0 -0
  212. /package/src/components/{atoms → display}/Skeleton.tsx +0 -0
  213. /package/src/components/{atoms → feedback}/Progress.tsx +0 -0
  214. /package/src/components/{atoms → inputs}/Button.tsx +0 -0
  215. /package/src/components/{atoms → inputs}/Label.tsx +0 -0
  216. /package/src/components/{atoms → inputs}/RadioGroup.tsx +0 -0
  217. /package/src/components/{organisms → navigation}/AppRail.tsx +0 -0
  218. /package/src/components/{templates → patterns}/AuthTemplate.tsx +0 -0
  219. /package/src/components/{templates → patterns}/BannalyzeTemplate.tsx +0 -0
  220. /package/src/components/{templates → patterns}/ChatTemplate.tsx +0 -0
  221. /package/src/components/{templates → patterns}/EditorTemplate.tsx +0 -0
  222. /package/src/components/{templates → patterns}/KanbanTemplate.tsx +0 -0
  223. /package/src/components/{templates → patterns}/LandingTemplate.tsx +0 -0
  224. /package/src/components/{templates → patterns}/SettingsTemplate.tsx +0 -0
@@ -0,0 +1,145 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
5
+
6
+ import { cn } from "../../lib/utils"
7
+ import { buttonVariants } from "../inputs/ButtonVariants"
8
+
9
+ const AlertDialog = AlertDialogPrimitive.Root
10
+
11
+ const AlertDialogTrigger = AlertDialogPrimitive.Trigger
12
+
13
+ const AlertDialogPortal = AlertDialogPrimitive.Portal
14
+
15
+ const AlertDialogOverlay = React.forwardRef<
16
+ React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
17
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
18
+ >(({ className, ...props }, ref) => (
19
+ <AlertDialogPrimitive.Overlay
20
+ ref={ref}
21
+ className={cn(
22
+ "fixed inset-0 z-50 bg-overlay/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
23
+ className
24
+ )}
25
+ {...props}
26
+ />
27
+ ))
28
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
29
+
30
+ const AlertDialogContent = React.forwardRef<
31
+ React.ElementRef<typeof AlertDialogPrimitive.Content>,
32
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> & {
33
+ portalContainer?: HTMLElement | null
34
+ overlayClassName?: string
35
+ }
36
+ >(({ className, portalContainer, overlayClassName, ...props }, ref) => (
37
+ <AlertDialogPortal container={portalContainer ?? undefined}>
38
+ <AlertDialogOverlay className={cn(portalContainer && "absolute", overlayClassName)} />
39
+ <AlertDialogPrimitive.Content
40
+ ref={ref}
41
+ className={cn(
42
+ "fixed left-[50%] top-[50%] z-50 grid w-[calc(100%-2rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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 sm:rounded-lg",
43
+ portalContainer && "absolute",
44
+ className
45
+ )}
46
+ {...props}
47
+ />
48
+ </AlertDialogPortal>
49
+ ))
50
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
51
+
52
+ const AlertDialogHeader = ({
53
+ className,
54
+ ...props
55
+ }: React.HTMLAttributes<HTMLDivElement>) => (
56
+ <div
57
+ className={cn(
58
+ "flex flex-col space-y-2 text-center sm:text-left",
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ )
64
+ AlertDialogHeader.displayName = "AlertDialogHeader"
65
+
66
+ const AlertDialogFooter = ({
67
+ className,
68
+ ...props
69
+ }: React.HTMLAttributes<HTMLDivElement>) => (
70
+ <div
71
+ className={cn(
72
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
73
+ className
74
+ )}
75
+ {...props}
76
+ />
77
+ )
78
+ AlertDialogFooter.displayName = "AlertDialogFooter"
79
+
80
+ const AlertDialogTitle = React.forwardRef<
81
+ React.ElementRef<typeof AlertDialogPrimitive.Title>,
82
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
83
+ >(({ className, ...props }, ref) => (
84
+ <AlertDialogPrimitive.Title
85
+ ref={ref}
86
+ className={cn("text-lg font-semibold", className)}
87
+ {...props}
88
+ />
89
+ ))
90
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
91
+
92
+ const AlertDialogDescription = React.forwardRef<
93
+ React.ElementRef<typeof AlertDialogPrimitive.Description>,
94
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
95
+ >(({ className, ...props }, ref) => (
96
+ <AlertDialogPrimitive.Description
97
+ ref={ref}
98
+ className={cn("text-sm text-muted-foreground", className)}
99
+ {...props}
100
+ />
101
+ ))
102
+ AlertDialogDescription.displayName =
103
+ AlertDialogPrimitive.Description.displayName
104
+
105
+ const AlertDialogAction = React.forwardRef<
106
+ React.ElementRef<typeof AlertDialogPrimitive.Action>,
107
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
108
+ >(({ className, ...props }, ref) => (
109
+ <AlertDialogPrimitive.Action
110
+ ref={ref}
111
+ className={cn(buttonVariants(), className)}
112
+ {...props}
113
+ />
114
+ ))
115
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
116
+
117
+ const AlertDialogCancel = React.forwardRef<
118
+ React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
119
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
120
+ >(({ className, ...props }, ref) => (
121
+ <AlertDialogPrimitive.Cancel
122
+ ref={ref}
123
+ className={cn(
124
+ buttonVariants({ variant: "outline" }),
125
+ "mt-2 sm:mt-0",
126
+ className
127
+ )}
128
+ {...props}
129
+ />
130
+ ))
131
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
132
+
133
+ export {
134
+ AlertDialog,
135
+ AlertDialogPortal,
136
+ AlertDialogOverlay,
137
+ AlertDialogTrigger,
138
+ AlertDialogContent,
139
+ AlertDialogHeader,
140
+ AlertDialogFooter,
141
+ AlertDialogTitle,
142
+ AlertDialogDescription,
143
+ AlertDialogAction,
144
+ AlertDialogCancel,
145
+ }
@@ -0,0 +1,180 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { IconX as X } from "@tabler/icons-react";
5
+ import { cn } from "../../lib/utils";
6
+ import { ChatMessage, type ChatMessageActionKey, type ChatMessageProps } from "../display/ChatMessage";
7
+ import { EmptyState } from "../display/EmptyState";
8
+ import { ChatInput, type ChatInputLabels, type ChatInputProps } from "../inputs/ChatInput";
9
+ import { TooltipButton } from "../inputs/TooltipButton";
10
+ import { chatPanelDefaultVariantKey } from "./generated/default-variant-keys";
11
+ import type { ChatPanelVariantKey } from "./generated/variant-keys";
12
+
13
+ const chatPanelVariantClassNames: Record<ChatPanelVariantKey, string> = {
14
+ compact: "h-[420px]",
15
+ default: "h-[560px]",
16
+ };
17
+
18
+ export interface ChatPanelMessage extends Omit<ChatMessageProps, "className"> {
19
+ id: string;
20
+ }
21
+
22
+ export interface ChatPanelLabels {
23
+ close?: string;
24
+ empty?: string;
25
+ }
26
+
27
+ export interface ChatPanelProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
28
+ variant?: ChatPanelVariantKey;
29
+ title?: React.ReactNode;
30
+ description?: React.ReactNode;
31
+ messages: ChatPanelMessage[];
32
+ onSend: ChatInputProps["onSend"];
33
+ onStop?: ChatInputProps["onStop"];
34
+ isProcessing?: boolean;
35
+ placeholder?: string;
36
+ enableAttachments?: boolean;
37
+ emptyState?: React.ReactNode;
38
+ welcome?: React.ReactNode;
39
+ onMessageAction?: (
40
+ message: ChatPanelMessage,
41
+ actionKey: ChatMessageActionKey,
42
+ event: React.MouseEvent<HTMLButtonElement>
43
+ ) => void;
44
+ onClose?: () => void;
45
+ labels?: ChatPanelLabels;
46
+ inputLabels?: ChatInputLabels;
47
+ }
48
+
49
+ export function ChatPanel({
50
+ variant = chatPanelDefaultVariantKey,
51
+ title = "Assistant",
52
+ description,
53
+ messages,
54
+ onSend,
55
+ onStop,
56
+ isProcessing = false,
57
+ placeholder,
58
+ enableAttachments = true,
59
+ emptyState,
60
+ welcome,
61
+ onMessageAction,
62
+ onClose,
63
+ labels,
64
+ inputLabels,
65
+ className,
66
+ ...props
67
+ }: ChatPanelProps) {
68
+ const messageScrollRef = React.useRef<HTMLDivElement | null>(null);
69
+ const resolvedLabels = {
70
+ close: labels?.close ?? "閉じる",
71
+ empty: labels?.empty ?? "まだメッセージはありません。",
72
+ };
73
+
74
+ React.useEffect(() => {
75
+ if (messages.length === 0 && !isProcessing) return;
76
+
77
+ const frame = window.requestAnimationFrame(() => {
78
+ const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
79
+ const scrollElement = messageScrollRef.current;
80
+
81
+ if (!scrollElement) return;
82
+
83
+ scrollElement.scrollTo({
84
+ top: scrollElement.scrollHeight,
85
+ behavior: reduceMotion ? "auto" : "smooth",
86
+ });
87
+ });
88
+
89
+ return () => window.cancelAnimationFrame(frame);
90
+ }, [isProcessing, messages]);
91
+
92
+ return (
93
+ <section
94
+ className={cn(
95
+ "flex w-full max-w-2xl flex-col overflow-hidden rounded-lg border bg-background p-0 shadow-xl",
96
+ chatPanelVariantClassNames[variant],
97
+ className
98
+ )}
99
+ {...props}
100
+ >
101
+ <header className="flex items-start gap-3 border-b bg-muted/50 px-4 py-3">
102
+ <div className="min-w-0 flex-1">
103
+ <h3 className="truncate text-sm font-semibold">{title}</h3>
104
+ {description ? (
105
+ <p className="mt-0.5 text-xs leading-relaxed text-muted-foreground">
106
+ {description}
107
+ </p>
108
+ ) : null}
109
+ </div>
110
+ {onClose ? (
111
+ <TooltipButton
112
+ type="button"
113
+ tooltip={resolvedLabels.close}
114
+ aria-label={resolvedLabels.close}
115
+ variant="ghost"
116
+ size="icon"
117
+ className="-mr-2 -mt-1 h-8 w-8 shrink-0"
118
+ onClick={onClose}
119
+ >
120
+ <X className="h-4 w-4" />
121
+ </TooltipButton>
122
+ ) : null}
123
+ </header>
124
+ <div
125
+ ref={messageScrollRef}
126
+ className={cn(
127
+ "flex-1 bg-muted/30 p-4",
128
+ messages.length > 0 || isProcessing ? "overflow-y-auto" : "overflow-hidden"
129
+ )}
130
+ >
131
+ {messages.length > 0 ? (
132
+ <div className="space-y-3">
133
+ {messages.map((message) => {
134
+ const { onAction, ...messageProps } = message;
135
+
136
+ return (
137
+ <ChatMessage
138
+ key={message.id}
139
+ {...messageProps}
140
+ onAction={(actionKey, event) => {
141
+ onAction?.(actionKey, event);
142
+ if (!event.defaultPrevented) {
143
+ onMessageAction?.(message, actionKey, event);
144
+ }
145
+ }}
146
+ />
147
+ );
148
+ })}
149
+ {isProcessing ? (
150
+ <ChatMessage role="assistant" content="" isTyping />
151
+ ) : null}
152
+ </div>
153
+ ) : welcome ? (
154
+ <div className="flex min-h-full items-end justify-center">
155
+ {welcome}
156
+ </div>
157
+ ) : emptyState ? (
158
+ <div className="flex min-h-full items-center justify-center">
159
+ {emptyState}
160
+ </div>
161
+ ) : (
162
+ <EmptyState
163
+ className="min-h-full border-dashed bg-background/70"
164
+ title={resolvedLabels.empty}
165
+ />
166
+ )}
167
+ </div>
168
+ <div className="bg-muted/30 p-3 sm:p-4">
169
+ <ChatInput
170
+ onSend={onSend}
171
+ onStop={onStop}
172
+ isProcessing={isProcessing}
173
+ placeholder={placeholder}
174
+ enableAttachments={enableAttachments}
175
+ labels={inputLabels}
176
+ />
177
+ </div>
178
+ </section>
179
+ );
180
+ }
@@ -2,9 +2,10 @@
2
2
 
3
3
  import * as React from "react"
4
4
  import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
5
- import { Check, ChevronRight, Circle } from "lucide-react"
5
+ import { IconCheck as Check, IconChevronRight as ChevronRight, IconCircle as Circle } from "@tabler/icons-react";
6
6
 
7
7
  import { cn } from "../../lib/utils"
8
+ import { Tooltip, TooltipContent, TooltipTrigger } from "./Tooltip"
8
9
 
9
10
  const ContextMenu = ContextMenuPrimitive.Root
10
11
 
@@ -27,7 +28,7 @@ const ContextMenuSubTrigger = React.forwardRef<
27
28
  <ContextMenuPrimitive.SubTrigger
28
29
  ref={ref}
29
30
  className={cn(
30
- "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
31
+ "flex w-full cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
31
32
  inset && "pl-8",
32
33
  className
33
34
  )}
@@ -41,28 +42,34 @@ ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName
41
42
 
42
43
  const ContextMenuSubContent = React.forwardRef<
43
44
  React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
44
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
45
- >(({ className, ...props }, ref) => (
46
- <ContextMenuPrimitive.SubContent
47
- ref={ref}
48
- className={cn(
49
- "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",
50
- className
51
- )}
52
- {...props}
53
- />
45
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent> & {
46
+ portalContainer?: HTMLElement | null
47
+ }
48
+ >(({ className, portalContainer, ...props }, ref) => (
49
+ <ContextMenuPrimitive.Portal container={portalContainer ?? undefined}>
50
+ <ContextMenuPrimitive.SubContent
51
+ ref={ref}
52
+ className={cn(
53
+ "z-50 flex min-w-[8rem] flex-col items-stretch gap-0.5 overflow-hidden rounded-md border bg-popover p-1 text-left 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",
54
+ className
55
+ )}
56
+ {...props}
57
+ />
58
+ </ContextMenuPrimitive.Portal>
54
59
  ))
55
60
  ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName
56
61
 
57
62
  const ContextMenuContent = React.forwardRef<
58
63
  React.ElementRef<typeof ContextMenuPrimitive.Content>,
59
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
60
- >(({ className, ...props }, ref) => (
61
- <ContextMenuPrimitive.Portal>
64
+ React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content> & {
65
+ portalContainer?: HTMLElement | null
66
+ }
67
+ >(({ className, portalContainer, ...props }, ref) => (
68
+ <ContextMenuPrimitive.Portal container={portalContainer ?? undefined}>
62
69
  <ContextMenuPrimitive.Content
63
70
  ref={ref}
64
71
  className={cn(
65
- "z-50 flex flex-col items-center w-[192px] min-w-[8rem] gap-0.5 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md animate-in fade-in-80 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",
72
+ "z-50 flex w-[192px] min-w-[8rem] flex-col items-stretch gap-0.5 overflow-hidden rounded-md border bg-popover p-1 text-left text-popover-foreground shadow-md animate-in fade-in-80 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",
66
73
  className
67
74
  )}
68
75
  {...props}
@@ -75,18 +82,47 @@ const ContextMenuItem = React.forwardRef<
75
82
  React.ElementRef<typeof ContextMenuPrimitive.Item>,
76
83
  React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
77
84
  inset?: boolean
85
+ disabledReason?: React.ReactNode
86
+ disabledReasonLabel?: string
78
87
  }
79
- >(({ className, inset, ...props }, ref) => (
80
- <ContextMenuPrimitive.Item
81
- ref={ref}
82
- className={cn(
83
- "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
84
- inset && "pl-8",
85
- className
86
- )}
87
- {...props}
88
- />
89
- ))
88
+ >(({ className, inset, disabledReason, disabledReasonLabel, disabled, onSelect, ...props }, ref) => {
89
+ const item = (
90
+ <ContextMenuPrimitive.Item
91
+ ref={ref}
92
+ disabled={disabled}
93
+ onSelect={(event) => {
94
+ if (disabled) {
95
+ event.preventDefault()
96
+ return
97
+ }
98
+ onSelect?.(event)
99
+ }}
100
+ className={cn(
101
+ "relative flex w-full cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
102
+ inset && "pl-8",
103
+ className
104
+ )}
105
+ {...props}
106
+ />
107
+ )
108
+
109
+ if (!disabled || !disabledReason) return item
110
+
111
+ return (
112
+ <Tooltip>
113
+ <TooltipTrigger asChild>
114
+ <span
115
+ className="block w-full"
116
+ tabIndex={0}
117
+ aria-label={disabledReasonLabel ?? (typeof disabledReason === "string" ? disabledReason : undefined)}
118
+ >
119
+ {item}
120
+ </span>
121
+ </TooltipTrigger>
122
+ <TooltipContent className="max-w-64 text-left">{disabledReason}</TooltipContent>
123
+ </Tooltip>
124
+ )
125
+ })
90
126
  ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName
91
127
 
92
128
  const ContextMenuCheckboxItem = React.forwardRef<
@@ -96,7 +132,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
96
132
  <ContextMenuPrimitive.CheckboxItem
97
133
  ref={ref}
98
134
  className={cn(
99
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
135
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-left text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
100
136
  className
101
137
  )}
102
138
  checked={checked}
@@ -120,7 +156,7 @@ const ContextMenuRadioItem = React.forwardRef<
120
156
  <ContextMenuPrimitive.RadioItem
121
157
  ref={ref}
122
158
  className={cn(
123
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
159
+ "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-left text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
124
160
  className
125
161
  )}
126
162
  {...props}
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as React from "react"
4
4
  import * as DialogPrimitive from "@radix-ui/react-dialog"
5
- import { X } from "lucide-react"
5
+ import { IconX as X } from "@tabler/icons-react";
6
6
 
7
7
  import { cn } from "../../lib/utils"
8
8
 
@@ -31,23 +31,31 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
31
31
 
32
32
  const DialogContent = React.forwardRef<
33
33
  React.ElementRef<typeof DialogPrimitive.Content>,
34
- React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
35
- >(({ className, children, ...props }, ref) => (
36
- <DialogPortal>
37
- <DialogOverlay />
34
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
35
+ portalContainer?: HTMLElement | null
36
+ overlayClassName?: string
37
+ showCloseButton?: boolean
38
+ closeLabel?: string
39
+ }
40
+ >(({ className, children, portalContainer, overlayClassName, showCloseButton = true, closeLabel = "Close", ...props }, ref) => (
41
+ <DialogPortal container={portalContainer ?? undefined}>
42
+ <DialogOverlay className={cn(portalContainer && "absolute", overlayClassName)} />
38
43
  <DialogPrimitive.Content
39
44
  ref={ref}
40
45
  className={cn(
41
- "fixed left-[50%] top-[50%] z-50 grid w-[512px] w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
46
+ "fixed left-1/2 top-1/2 z-50 grid w-[512px] w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border bg-background p-6 shadow-lg duration-200 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 sm:rounded-lg",
47
+ portalContainer && "absolute w-[calc(100%-2rem)] max-w-[calc(100%-2rem)]",
42
48
  className
43
49
  )}
44
50
  {...props}
45
51
  >
46
52
  {children}
47
- <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
48
- <X className="h-4 w-4" />
49
- <span className="sr-only">Close</span>
50
- </DialogPrimitive.Close>
53
+ {showCloseButton ? (
54
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
55
+ <X className="h-4 w-4" />
56
+ <span className="sr-only">{closeLabel}</span>
57
+ </DialogPrimitive.Close>
58
+ ) : null}
51
59
  </DialogPrimitive.Content>
52
60
  </DialogPortal>
53
61
  ))
@@ -59,7 +67,7 @@ const DialogHeader = ({
59
67
  }: React.HTMLAttributes<HTMLDivElement>) => (
60
68
  <div
61
69
  className={cn(
62
- "flex flex-col space-y-1.5 text-center sm:text-left",
70
+ "flex flex-col space-y-1.5 pr-4 text-left",
63
71
  className
64
72
  )}
65
73
  {...props}
@@ -73,7 +81,7 @@ const DialogFooter = ({
73
81
  }: React.HTMLAttributes<HTMLDivElement>) => (
74
82
  <div
75
83
  className={cn(
76
- "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
84
+ "flex flex-row flex-wrap justify-end gap-2 sm:space-x-2",
77
85
  className
78
86
  )}
79
87
  {...props}
@@ -88,7 +96,7 @@ const DialogTitle = React.forwardRef<
88
96
  <DialogPrimitive.Title
89
97
  ref={ref}
90
98
  className={cn(
91
- "text-lg font-semibold leading-none tracking-tight",
99
+ "text-lg font-semibold leading-tight tracking-tight",
92
100
  className
93
101
  )}
94
102
  {...props}
@@ -0,0 +1,131 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Drawer as DrawerPrimitive } from "vaul"
5
+
6
+ import { cn } from "../../lib/utils"
7
+
8
+ const Drawer = ({
9
+ shouldScaleBackground = true,
10
+ ...props
11
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
12
+ <DrawerPrimitive.Root
13
+ shouldScaleBackground={shouldScaleBackground}
14
+ {...props}
15
+ />
16
+ )
17
+ Drawer.displayName = "Drawer"
18
+
19
+ const DrawerTrigger = DrawerPrimitive.Trigger
20
+ const DrawerPortal = DrawerPrimitive.Portal
21
+ const DrawerClose = DrawerPrimitive.Close
22
+
23
+ const DrawerOverlay = React.forwardRef<
24
+ React.ElementRef<typeof DrawerPrimitive.Overlay>,
25
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
26
+ >(({ className, ...props }, ref) => (
27
+ <DrawerPrimitive.Overlay
28
+ ref={ref}
29
+ className={cn("fixed inset-0 z-50 bg-overlay/80", className)}
30
+ {...props}
31
+ />
32
+ ))
33
+ DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
34
+
35
+ type DrawerSide = "bottom" | "right" | "left" | "top"
36
+
37
+ const drawerContentSideClasses: Record<DrawerSide, string> = {
38
+ bottom: "inset-x-0 bottom-0 mt-24 h-auto rounded-t-[10px] border",
39
+ right: "inset-y-0 right-0 h-full w-80 max-w-[calc(100%_-_2rem)] rounded-l-[10px] border-l",
40
+ left: "inset-y-0 left-0 h-full w-80 max-w-[calc(100%_-_2rem)] rounded-r-[10px] border-r",
41
+ top: "inset-x-0 top-0 mb-24 h-auto rounded-b-[10px] border",
42
+ }
43
+
44
+ const DrawerContent = React.forwardRef<
45
+ React.ElementRef<typeof DrawerPrimitive.Content>,
46
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content> & {
47
+ side?: DrawerSide
48
+ portalContainer?: HTMLElement | null
49
+ overlayClassName?: string
50
+ }
51
+ >(({ className, children, side = "bottom", portalContainer, overlayClassName, ...props }, ref) => (
52
+ <DrawerPortal container={portalContainer ?? undefined}>
53
+ <DrawerOverlay className={cn(portalContainer && "absolute", overlayClassName)} />
54
+ <DrawerPrimitive.Content
55
+ ref={ref}
56
+ className={cn(
57
+ "fixed z-50 flex flex-col bg-background",
58
+ portalContainer && "absolute",
59
+ drawerContentSideClasses[side],
60
+ className
61
+ )}
62
+ {...props}
63
+ >
64
+ {side === "bottom" ? <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" /> : null}
65
+ {children}
66
+ </DrawerPrimitive.Content>
67
+ </DrawerPortal>
68
+ ))
69
+ DrawerContent.displayName = "DrawerContent"
70
+
71
+ const DrawerHeader = ({
72
+ className,
73
+ ...props
74
+ }: React.HTMLAttributes<HTMLDivElement>) => (
75
+ <div
76
+ className={cn("grid gap-1.5 p-4 text-left", className)}
77
+ {...props}
78
+ />
79
+ )
80
+ DrawerHeader.displayName = "DrawerHeader"
81
+
82
+ const DrawerFooter = ({
83
+ className,
84
+ ...props
85
+ }: React.HTMLAttributes<HTMLDivElement>) => (
86
+ <div
87
+ className={cn("mt-auto flex flex-row flex-wrap justify-end gap-2 p-4", className)}
88
+ {...props}
89
+ />
90
+ )
91
+ DrawerFooter.displayName = "DrawerFooter"
92
+
93
+ const DrawerTitle = React.forwardRef<
94
+ React.ElementRef<typeof DrawerPrimitive.Title>,
95
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
96
+ >(({ className, ...props }, ref) => (
97
+ <DrawerPrimitive.Title
98
+ ref={ref}
99
+ className={cn(
100
+ "text-lg font-semibold leading-none tracking-tight",
101
+ className
102
+ )}
103
+ {...props}
104
+ />
105
+ ))
106
+ DrawerTitle.displayName = DrawerPrimitive.Title.displayName
107
+
108
+ const DrawerDescription = React.forwardRef<
109
+ React.ElementRef<typeof DrawerPrimitive.Description>,
110
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
111
+ >(({ className, ...props }, ref) => (
112
+ <DrawerPrimitive.Description
113
+ ref={ref}
114
+ className={cn("text-sm text-muted-foreground", className)}
115
+ {...props}
116
+ />
117
+ ))
118
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName
119
+
120
+ export {
121
+ Drawer,
122
+ DrawerPortal,
123
+ DrawerOverlay,
124
+ DrawerTrigger,
125
+ DrawerClose,
126
+ DrawerContent,
127
+ DrawerHeader,
128
+ DrawerFooter,
129
+ DrawerTitle,
130
+ DrawerDescription,
131
+ }