@springbrand/message-panel 0.1.3-alpha.0 → 0.1.3-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cloud-os/README.md +71 -0
- package/cloud-os/capability-chip.tsx +35 -0
- package/cloud-os/chat/activity-indicator.tsx +29 -0
- package/cloud-os/chat/cloud-os-chat-messages.tsx +660 -0
- package/cloud-os/chat/markdown-message.tsx +78 -0
- package/cloud-os/chat/rich-blocks.tsx +787 -0
- package/cloud-os/chat/tool-presentation.ts +586 -0
- package/cloud-os/chat/tool-rows.tsx +216 -0
- package/cloud-os/chat/transcript-model.ts +780 -0
- package/cloud-os/composer/cloud-os-chat-input.tsx +686 -0
- package/cloud-os/file-view.tsx +258 -0
- package/cloud-os/index.ts +123 -0
- package/cloud-os/internal/cn.ts +6 -0
- package/cloud-os/internal/theme-context.tsx +16 -0
- package/cloud-os/layout/cloud-os-root.tsx +34 -0
- package/cloud-os/layout/cloud-os-workspace-split.tsx +228 -0
- package/cloud-os/primitives/dropdown-menu.tsx +82 -0
- package/cloud-os/primitives/tooltip.tsx +68 -0
- package/cloud-os/primitives/workshop-controls.tsx +114 -0
- package/cloud-os/styles/cloud-os.css +553 -0
- package/cloud-os/workspace/cloud-os-workspace-panel.tsx +272 -0
- package/demo/camel-chat-showcase.tsx +13 -917
- package/demo/chat-scenarios.ts +926 -0
- package/demo/cloud-os-chat-showcase.tsx +481 -0
- package/demo/index.ts +2 -0
- package/package.json +17 -5
- package/src/camel/camel-chat-messages.tsx +55 -20
- package/src/camel/camel-prompt-input.tsx +2 -1
- package/src/camel/camel-turn.ts +21 -3
- package/src/chat-summary-panel.tsx +1 -1
- package/src/composer/chat-composer.tsx +2 -1
- package/src/composer/composer-trigger-popover.tsx +1 -1
- package/src/composer/composer.tsx +2 -1
- package/src/composer/index.ts +1 -0
- package/src/composer/key-rules.ts +12 -0
- package/src/message.tsx +0 -8
- package/src/parts/plan.ts +3 -2
- package/src/styles/index.css +4 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
2
|
+
import {
|
|
3
|
+
cloneElement,
|
|
4
|
+
isValidElement,
|
|
5
|
+
type ComponentProps,
|
|
6
|
+
type ReactElement,
|
|
7
|
+
type ReactNode,
|
|
8
|
+
} from "react";
|
|
9
|
+
import { cn } from "../internal/cn";
|
|
10
|
+
import { useCloudOsMode } from "../internal/theme-context";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Kumo 的 DropdownMenu 用的是 `<DropdownMenu.Trigger render={<button/>} />`
|
|
14
|
+
* 这种「render prop 传元素」的写法。这里保留同一个调用面(免得改动拷来的 JSX),
|
|
15
|
+
* 内部翻译成 radix 的 asChild。
|
|
16
|
+
*/
|
|
17
|
+
function Root({ children }: { children: ReactNode }) {
|
|
18
|
+
return <DropdownMenuPrimitive.Root>{children}</DropdownMenuPrimitive.Root>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Trigger({ render }: { render: ReactElement }) {
|
|
22
|
+
return (
|
|
23
|
+
<DropdownMenuPrimitive.Trigger asChild>
|
|
24
|
+
{isValidElement(render)
|
|
25
|
+
? // data-[popup-open] 是 Kumo 的开合标记,拷来的 className 里在用;
|
|
26
|
+
// radix 给的是 data-state="open",这里补一份等价属性。
|
|
27
|
+
cloneElement(render as ReactElement<Record<string, unknown>>, {})
|
|
28
|
+
: render}
|
|
29
|
+
</DropdownMenuPrimitive.Trigger>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function Content({
|
|
34
|
+
className,
|
|
35
|
+
collisionPadding = 12,
|
|
36
|
+
align = "start",
|
|
37
|
+
sideOffset = 6,
|
|
38
|
+
children,
|
|
39
|
+
...props
|
|
40
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
41
|
+
const mode = useCloudOsMode();
|
|
42
|
+
return (
|
|
43
|
+
<DropdownMenuPrimitive.Portal>
|
|
44
|
+
<DropdownMenuPrimitive.Content
|
|
45
|
+
data-cloud-os-portal=""
|
|
46
|
+
data-mode={mode}
|
|
47
|
+
align={align}
|
|
48
|
+
sideOffset={sideOffset}
|
|
49
|
+
collisionPadding={collisionPadding}
|
|
50
|
+
className={cn("z-[1100] outline-none", className)}
|
|
51
|
+
{...props}
|
|
52
|
+
>
|
|
53
|
+
{children}
|
|
54
|
+
</DropdownMenuPrimitive.Content>
|
|
55
|
+
</DropdownMenuPrimitive.Portal>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function Item({
|
|
60
|
+
className,
|
|
61
|
+
children,
|
|
62
|
+
...props
|
|
63
|
+
}: ComponentProps<typeof DropdownMenuPrimitive.Item>) {
|
|
64
|
+
return (
|
|
65
|
+
<DropdownMenuPrimitive.Item
|
|
66
|
+
className={cn(
|
|
67
|
+
"flex cursor-pointer select-none items-center outline-none",
|
|
68
|
+
// Kumo 用 data-highlighted;radix 也叫 data-highlighted,直接通用。
|
|
69
|
+
className,
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</DropdownMenuPrimitive.Item>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const DropdownMenu = Object.assign(Root, {
|
|
79
|
+
Trigger,
|
|
80
|
+
Content,
|
|
81
|
+
Item,
|
|
82
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { cn } from "../internal/cn";
|
|
4
|
+
import { useCloudOsMode } from "../internal/theme-context";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 对齐 `@cloudflare/kumo` 的 `<Tooltip content side align asChild>` 调用面,
|
|
8
|
+
* 底座换成 radix —— 这样拷过来的 JSX 一个字都不用改,又不必把整个 Kumo
|
|
9
|
+
* 设计系统拖进本仓(它会和 ui 的 shadcn 主题在同一层 @theme 里打架)。
|
|
10
|
+
*/
|
|
11
|
+
export function TooltipProvider({ children }: { children: ReactNode }) {
|
|
12
|
+
return (
|
|
13
|
+
<TooltipPrimitive.Provider delayDuration={250} skipDelayDuration={300}>
|
|
14
|
+
{children}
|
|
15
|
+
</TooltipPrimitive.Provider>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TooltipProps {
|
|
20
|
+
content: ReactNode;
|
|
21
|
+
children: ReactNode;
|
|
22
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
23
|
+
align?: "start" | "center" | "end";
|
|
24
|
+
/** Kumo 里 asChild 表示「把触发器渲染成 children 本身」;radix 语义一致。 */
|
|
25
|
+
asChild?: boolean;
|
|
26
|
+
disabled?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function Tooltip({
|
|
30
|
+
content,
|
|
31
|
+
children,
|
|
32
|
+
side = "top",
|
|
33
|
+
align = "center",
|
|
34
|
+
asChild = false,
|
|
35
|
+
disabled = false,
|
|
36
|
+
}: TooltipProps) {
|
|
37
|
+
const mode = useCloudOsMode();
|
|
38
|
+
if (disabled || content == null || content === "") return <>{children}</>;
|
|
39
|
+
return (
|
|
40
|
+
// 自带 Provider:radix 的 Root 必须活在 Provider 里,而这些行会被单独渲染
|
|
41
|
+
// (单测、宿主局部挂载)。Provider 可以嵌套,外面再包一层也不冲突。
|
|
42
|
+
<TooltipPrimitive.Provider delayDuration={250} skipDelayDuration={300}>
|
|
43
|
+
<TooltipPrimitive.Root>
|
|
44
|
+
<TooltipPrimitive.Trigger asChild={asChild}>
|
|
45
|
+
{children}
|
|
46
|
+
</TooltipPrimitive.Trigger>
|
|
47
|
+
<TooltipPrimitive.Portal>
|
|
48
|
+
<TooltipPrimitive.Content
|
|
49
|
+
data-cloud-os-portal=""
|
|
50
|
+
data-mode={mode}
|
|
51
|
+
side={side}
|
|
52
|
+
align={align}
|
|
53
|
+
sideOffset={6}
|
|
54
|
+
collisionPadding={12}
|
|
55
|
+
className={cn(
|
|
56
|
+
"z-[1200] max-w-[min(28rem,90vw)] rounded-lg border px-2.5 py-1.5",
|
|
57
|
+
"text-[12px] leading-4 tracking-[-0.2px]",
|
|
58
|
+
"border-kumo-line bg-kumo-base text-kumo-default",
|
|
59
|
+
"shadow-[0_8px_20px_var(--color-kumo-tip-shadow)]",
|
|
60
|
+
)}
|
|
61
|
+
>
|
|
62
|
+
{content}
|
|
63
|
+
</TooltipPrimitive.Content>
|
|
64
|
+
</TooltipPrimitive.Portal>
|
|
65
|
+
</TooltipPrimitive.Root>
|
|
66
|
+
</TooltipPrimitive.Provider>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes, InputHTMLAttributes, ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 从 cloudflare-os-main `components/WorkshopControls.tsx` 拷来。
|
|
5
|
+
* 唯一改动:底座从 `@cloudflare/kumo` 的 <Button>/<Input> 换成原生元素,
|
|
6
|
+
* 因为那几个组件除了 focus ring 之外的视觉全靠这里的 className 覆盖。
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const buttonBaseClassName =
|
|
10
|
+
"inline-flex cursor-pointer items-center justify-center rounded-lg text-[13px] leading-[18px] font-medium tracking-[-0.25px] transition-[background-color,color,opacity,transform] duration-150 ease-out active:scale-[0.98] disabled:cursor-not-allowed disabled:active:scale-100";
|
|
11
|
+
|
|
12
|
+
const buttonToneClassNames = {
|
|
13
|
+
primary:
|
|
14
|
+
"!h-9 bg-kumo-contrast px-3 text-kumo-inverse enabled:hover:bg-kumo-strong disabled:opacity-50",
|
|
15
|
+
secondary:
|
|
16
|
+
"!h-8 border border-kumo-line bg-kumo-base px-3 text-kumo-default enabled:hover:bg-kumo-elevated disabled:opacity-40",
|
|
17
|
+
danger:
|
|
18
|
+
"!h-8 bg-kumo-danger px-3 text-white enabled:hover:opacity-90 disabled:opacity-50",
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
type WorkshopButtonTone = keyof typeof buttonToneClassNames;
|
|
22
|
+
|
|
23
|
+
type WorkshopButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
24
|
+
tone?: WorkshopButtonTone;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function WorkshopButton({
|
|
28
|
+
tone = "secondary",
|
|
29
|
+
className = "",
|
|
30
|
+
type = "button",
|
|
31
|
+
...props
|
|
32
|
+
}: WorkshopButtonProps) {
|
|
33
|
+
return (
|
|
34
|
+
<button
|
|
35
|
+
type={type}
|
|
36
|
+
{...props}
|
|
37
|
+
className={`${buttonBaseClassName} ${buttonToneClassNames[tone]} ${className}`}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type WorkshopIconButtonProps = Omit<
|
|
43
|
+
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
44
|
+
"children"
|
|
45
|
+
> & {
|
|
46
|
+
children: ReactNode;
|
|
47
|
+
danger?: boolean;
|
|
48
|
+
tone?: "ghost" | "primary";
|
|
49
|
+
"aria-label": string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export function WorkshopIconButton({
|
|
53
|
+
children,
|
|
54
|
+
danger = false,
|
|
55
|
+
tone = "ghost",
|
|
56
|
+
className = "",
|
|
57
|
+
type = "button",
|
|
58
|
+
...props
|
|
59
|
+
}: WorkshopIconButtonProps) {
|
|
60
|
+
const toneClassName =
|
|
61
|
+
tone === "primary"
|
|
62
|
+
? "bg-kumo-contrast text-kumo-inverse enabled:hover:bg-kumo-strong enabled:hover:text-kumo-inverse"
|
|
63
|
+
: danger
|
|
64
|
+
? "text-kumo-subtle enabled:hover:bg-kumo-danger-tint enabled:hover:text-kumo-danger"
|
|
65
|
+
: "text-kumo-subtle enabled:hover:bg-kumo-tint enabled:hover:text-kumo-default";
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<button
|
|
69
|
+
type={type}
|
|
70
|
+
{...props}
|
|
71
|
+
className={`!flex !h-8 !w-8 shrink-0 cursor-pointer items-center justify-center rounded-md !p-0 transition-[background-color,color,opacity,transform] duration-150 ease-out active:scale-[0.96] disabled:cursor-not-allowed disabled:opacity-40 disabled:active:scale-100 ${toneClassName} ${className}`}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</button>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type WorkshopInputProps = InputHTMLAttributes<HTMLInputElement>;
|
|
79
|
+
|
|
80
|
+
export function WorkshopInput({ className = "", ...props }: WorkshopInputProps) {
|
|
81
|
+
return (
|
|
82
|
+
<input
|
|
83
|
+
{...props}
|
|
84
|
+
className={`!h-9 rounded-lg border border-kumo-line bg-kumo-base px-3 text-[13px] leading-[18px] font-normal tracking-[-0.25px] text-kumo-default placeholder:text-kumo-inactive shadow-none focus:border-kumo-ring focus:outline-none focus:ring-1 focus:ring-kumo-ring/15 ${className}`}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function CountBadge({
|
|
90
|
+
count,
|
|
91
|
+
tone = "tint",
|
|
92
|
+
max = 9,
|
|
93
|
+
className = "",
|
|
94
|
+
}: {
|
|
95
|
+
count: number;
|
|
96
|
+
tone?: "solid" | "tint";
|
|
97
|
+
max?: number;
|
|
98
|
+
className?: string;
|
|
99
|
+
}) {
|
|
100
|
+
if (count <= 0) return null;
|
|
101
|
+
|
|
102
|
+
const toneClassName =
|
|
103
|
+
tone === "solid"
|
|
104
|
+
? "border border-kumo-base bg-kumo-brand text-white"
|
|
105
|
+
: "bg-kumo-brand/15 text-kumo-strong";
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<span
|
|
109
|
+
className={`grid h-4 min-w-4 flex-shrink-0 place-items-center rounded-full px-1 text-[10px] font-semibold leading-none tabular-nums ${toneClassName} ${className}`}
|
|
110
|
+
>
|
|
111
|
+
{count > max ? `${max}+` : count}
|
|
112
|
+
</span>
|
|
113
|
+
);
|
|
114
|
+
}
|