@springbrand/message-panel 0.1.2 → 0.1.3-alpha.1

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 (99) hide show
  1. package/demo/camel-chat-showcase.tsx +1265 -0
  2. package/demo/fixtures.ts +292 -0
  3. package/demo/message-panel-chat-showcase.tsx +250 -0
  4. package/demo/message-panel-gallery.tsx +389 -0
  5. package/package.json +6 -16
  6. package/src/adapters/ai-sdk.ts +32 -0
  7. package/src/camel/camel-chat-messages.tsx +1435 -0
  8. package/src/camel/camel-model-select.tsx +88 -0
  9. package/src/camel/camel-plan-bar.tsx +115 -0
  10. package/src/camel/camel-prompt-input.tsx +547 -0
  11. package/src/camel/camel-tool-presentation.tsx +1270 -0
  12. package/src/camel/camel-turn.ts +334 -0
  13. package/src/camel/turn-summary-bar.tsx +81 -0
  14. package/src/chat-summary-panel.tsx +229 -0
  15. package/src/composer/chat-composer.tsx +216 -0
  16. package/src/composer/composer-attachments.tsx +138 -0
  17. package/src/composer/composer-trigger-popover.tsx +236 -0
  18. package/src/composer/composer.tsx +425 -0
  19. package/src/composer/drop-controller.ts +80 -0
  20. package/src/composer/types.ts +79 -0
  21. package/src/contracts.ts +138 -0
  22. package/src/conversation.tsx +76 -0
  23. package/src/internal/cn.ts +3 -0
  24. package/src/message-panel.tsx +368 -0
  25. package/src/message.tsx +254 -0
  26. package/src/parts/index.tsx +1149 -0
  27. package/src/parts/kind.ts +67 -0
  28. package/src/parts/plan.ts +64 -0
  29. package/src/parts/primitives.tsx +439 -0
  30. package/src/registry.ts +44 -0
  31. package/src/status.tsx +132 -0
  32. package/dist/demo/camel-chat-showcase.d.ts +0 -1
  33. package/dist/demo/camel-chat-showcase.js +0 -1007
  34. package/dist/demo/fixtures.d.ts +0 -32
  35. package/dist/demo/fixtures.js +0 -250
  36. package/dist/demo/index.js +0 -4
  37. package/dist/demo/message-panel-chat-showcase.d.ts +0 -1
  38. package/dist/demo/message-panel-chat-showcase.js +0 -114
  39. package/dist/demo/message-panel-gallery.d.ts +0 -1
  40. package/dist/demo/message-panel-gallery.js +0 -130
  41. package/dist/src/adapters/ai-sdk.d.ts +0 -4
  42. package/dist/src/adapters/ai-sdk.js +0 -25
  43. package/dist/src/camel/camel-chat-messages.d.ts +0 -44
  44. package/dist/src/camel/camel-chat-messages.js +0 -421
  45. package/dist/src/camel/camel-model-select.d.ts +0 -13
  46. package/dist/src/camel/camel-model-select.js +0 -7
  47. package/dist/src/camel/camel-plan-bar.d.ts +0 -5
  48. package/dist/src/camel/camel-plan-bar.js +0 -24
  49. package/dist/src/camel/camel-prompt-input.d.ts +0 -32
  50. package/dist/src/camel/camel-prompt-input.js +0 -182
  51. package/dist/src/camel/camel-tool-presentation.d.ts +0 -21
  52. package/dist/src/camel/camel-tool-presentation.js +0 -784
  53. package/dist/src/camel/camel-turn.d.ts +0 -57
  54. package/dist/src/camel/camel-turn.js +0 -203
  55. package/dist/src/camel/index.js +0 -7
  56. package/dist/src/camel/turn-summary-bar.d.ts +0 -8
  57. package/dist/src/camel/turn-summary-bar.js +0 -12
  58. package/dist/src/chat-summary-panel.d.ts +0 -22
  59. package/dist/src/chat-summary-panel.js +0 -26
  60. package/dist/src/composer/chat-composer.d.ts +0 -4
  61. package/dist/src/composer/chat-composer.js +0 -90
  62. package/dist/src/composer/composer-attachments.d.ts +0 -13
  63. package/dist/src/composer/composer-attachments.js +0 -47
  64. package/dist/src/composer/composer-trigger-popover.d.ts +0 -31
  65. package/dist/src/composer/composer-trigger-popover.js +0 -29
  66. package/dist/src/composer/composer.d.ts +0 -15
  67. package/dist/src/composer/composer.js +0 -180
  68. package/dist/src/composer/drop-controller.d.ts +0 -8
  69. package/dist/src/composer/drop-controller.js +0 -69
  70. package/dist/src/composer/index.js +0 -6
  71. package/dist/src/composer/types.d.ts +0 -62
  72. package/dist/src/composer/types.js +0 -1
  73. package/dist/src/contracts.d.ts +0 -94
  74. package/dist/src/contracts.js +0 -1
  75. package/dist/src/conversation.d.ts +0 -13
  76. package/dist/src/conversation.js +0 -18
  77. package/dist/src/index.js +0 -12
  78. package/dist/src/internal/cn.d.ts +0 -1
  79. package/dist/src/internal/cn.js +0 -3
  80. package/dist/src/message-panel.d.ts +0 -4
  81. package/dist/src/message-panel.js +0 -144
  82. package/dist/src/message.d.ts +0 -36
  83. package/dist/src/message.js +0 -83
  84. package/dist/src/parts/index.d.ts +0 -187
  85. package/dist/src/parts/index.js +0 -332
  86. package/dist/src/parts/kind.d.ts +0 -3
  87. package/dist/src/parts/kind.js +0 -69
  88. package/dist/src/parts/plan.d.ts +0 -10
  89. package/dist/src/parts/plan.js +0 -40
  90. package/dist/src/parts/primitives.d.ts +0 -70
  91. package/dist/src/parts/primitives.js +0 -153
  92. package/dist/src/registry.d.ts +0 -4
  93. package/dist/src/registry.js +0 -31
  94. package/dist/src/status.d.ts +0 -26
  95. package/dist/src/status.js +0 -74
  96. /package/{dist/demo/index.d.ts → demo/index.ts} +0 -0
  97. /package/{dist/src/camel/index.d.ts → src/camel/index.ts} +0 -0
  98. /package/{dist/src/composer/index.d.ts → src/composer/index.ts} +0 -0
  99. /package/{dist/src/index.d.ts → src/index.ts} +0 -0
@@ -0,0 +1,88 @@
1
+ import { CheckIcon, ChevronDownIcon, ZapIcon } from "lucide-react";
2
+ import { Select as SelectPrimitive } from "radix-ui";
3
+
4
+ export interface CamelModelOption {
5
+ value: string;
6
+ label: string;
7
+ hint?: string;
8
+ }
9
+
10
+ export interface CamelModelSelectProps {
11
+ value: string;
12
+ options: readonly CamelModelOption[];
13
+ disabled?: boolean;
14
+ label?: string;
15
+ onValueChange: (value: string) => void;
16
+ }
17
+
18
+ export function CamelModelSelect({
19
+ value,
20
+ options,
21
+ disabled,
22
+ label = "Select model",
23
+ onValueChange,
24
+ }: CamelModelSelectProps) {
25
+ const selected = options.find((option) => option.value === value);
26
+
27
+ return (
28
+ <SelectPrimitive.Root
29
+ value={value}
30
+ disabled={disabled}
31
+ onValueChange={onValueChange}
32
+ >
33
+ <SelectPrimitive.Trigger
34
+ data-camel-model-select=""
35
+ aria-label={label}
36
+ title={label}
37
+ className="inline-flex h-8 max-w-60 shrink-0 items-center justify-center gap-1.5 rounded-md px-1.5 text-sm font-medium text-foreground/90 outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50"
38
+ >
39
+ <ZapIcon
40
+ className="size-[17px] shrink-0 text-foreground/90"
41
+ strokeWidth={1.8}
42
+ />
43
+ <SelectPrimitive.Value className="max-w-40 truncate text-[15px]">
44
+ {selected?.label ?? value}
45
+ </SelectPrimitive.Value>
46
+ <SelectPrimitive.Icon asChild>
47
+ <ChevronDownIcon
48
+ className="size-4 shrink-0 text-muted-foreground"
49
+ strokeWidth={1.8}
50
+ />
51
+ </SelectPrimitive.Icon>
52
+ </SelectPrimitive.Trigger>
53
+ <SelectPrimitive.Portal>
54
+ <SelectPrimitive.Content
55
+ data-camel-model-select-content=""
56
+ position="popper"
57
+ align="start"
58
+ sideOffset={4}
59
+ className="z-50 w-72 overflow-hidden rounded-md border border-border bg-popover text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95"
60
+ >
61
+ <SelectPrimitive.Viewport className="max-h-80 overflow-y-auto p-1">
62
+ {options.map((option) => (
63
+ <SelectPrimitive.Item
64
+ key={option.value}
65
+ value={option.value}
66
+ className="relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50"
67
+ >
68
+ <SelectPrimitive.ItemText className="w-full">
69
+ <span className="flex min-w-0 items-center justify-between gap-3">
70
+ <span className="truncate">{option.label}</span>
71
+ {option.hint && (
72
+ <span className="shrink-0 text-xs text-muted-foreground">
73
+ {option.hint}
74
+ </span>
75
+ )}
76
+ </span>
77
+ </SelectPrimitive.ItemText>
78
+ <SelectPrimitive.ItemIndicator className="absolute right-2 flex size-4 items-center justify-center">
79
+ <CheckIcon className="size-4" />
80
+ </SelectPrimitive.ItemIndicator>
81
+ </SelectPrimitive.Item>
82
+ ))}
83
+ </SelectPrimitive.Viewport>
84
+ </SelectPrimitive.Content>
85
+ </SelectPrimitive.Portal>
86
+ </SelectPrimitive.Root>
87
+ );
88
+ }
@@ -0,0 +1,115 @@
1
+ import type { UIMessage } from "ai";
2
+ import { CheckIcon, ChevronDownIcon, CircleIcon } from "lucide-react";
3
+ import { useId, useMemo, useState } from "react";
4
+ import { cn } from "../internal/cn";
5
+ import { projectLatestPlan } from "../parts/plan";
6
+
7
+ export interface CamelPlanBarProps {
8
+ messages: readonly UIMessage[];
9
+ }
10
+
11
+ export function CamelPlanBar({ messages }: CamelPlanBarProps) {
12
+ const [open, setOpen] = useState(false);
13
+ const contentId = useId();
14
+ const steps = useMemo(() => projectLatestPlan(messages), [messages]);
15
+
16
+ if (!steps || steps.length === 0) return null;
17
+
18
+ const doneCount = steps.filter((step) => step.status === "done").length;
19
+ const activeIndex = steps.findIndex((step) => step.status !== "done");
20
+ const allDone = activeIndex === -1;
21
+ const headline = steps[allDone ? steps.length - 1 : activeIndex]!;
22
+
23
+ return (
24
+ <section
25
+ className="shrink-0 bg-background px-4 pt-2"
26
+ data-camel-plan-bar=""
27
+ aria-label="Task progress"
28
+ >
29
+ <div className="mx-auto w-full max-w-3xl rounded-2xl border border-border bg-card shadow-[0_8px_16px_rgb(0_0_0/0.12)]">
30
+ <button
31
+ type="button"
32
+ className="group flex w-full items-center gap-2 rounded-2xl px-4 py-2.5 text-left"
33
+ aria-expanded={open}
34
+ aria-controls={contentId}
35
+ onClick={() => setOpen((current) => !current)}
36
+ >
37
+ <span className="relative flex h-5 min-w-0 flex-1 items-center gap-2 overflow-hidden">
38
+ {allDone ? (
39
+ <CheckIcon className="size-4 shrink-0 text-success" />
40
+ ) : (
41
+ <span className="flex size-4 shrink-0 items-center justify-center">
42
+ <span className="size-2 animate-manus-pulse rounded-full bg-primary" />
43
+ </span>
44
+ )}
45
+ <span
46
+ className="min-w-0 truncate text-sm text-foreground"
47
+ title={headline.text}
48
+ >
49
+ {headline.text}
50
+ </span>
51
+ </span>
52
+ <span className="shrink-0 text-[13px] tabular-nums text-muted-foreground">
53
+ {doneCount} / {steps.length}
54
+ </span>
55
+ <ChevronDownIcon
56
+ className={cn(
57
+ "size-4 shrink-0 text-muted-foreground transition-transform duration-200",
58
+ open && "rotate-180",
59
+ )}
60
+ />
61
+ </button>
62
+ <div
63
+ id={contentId}
64
+ data-camel-plan-content=""
65
+ data-camel-collapsible-content=""
66
+ data-state={open ? "open" : "closed"}
67
+ aria-hidden={!open}
68
+ inert={!open ? true : undefined}
69
+ >
70
+ <div
71
+ data-camel-collapsible-inner=""
72
+ >
73
+ <div className="px-4 pb-3">
74
+ <p className="text-[13px] text-muted-foreground">Task progress</p>
75
+ <div className="mt-2 max-h-72 space-y-2 overflow-y-auto overflow-x-hidden">
76
+ {steps.map((step, index) => {
77
+ const active = !allDone && index === activeIndex;
78
+ return (
79
+ <div
80
+ key={`${index}:${step.text}`}
81
+ className="flex w-full min-w-0 items-center gap-2"
82
+ >
83
+ <span className="flex h-5 w-4 shrink-0 items-center justify-center">
84
+ {step.status === "done" ? (
85
+ <CheckIcon className="size-4 text-success" />
86
+ ) : active ? (
87
+ <span className="size-2 animate-manus-pulse rounded-full bg-primary" />
88
+ ) : (
89
+ <CircleIcon className="size-3.5 text-muted-foreground/40" />
90
+ )}
91
+ </span>
92
+ <span
93
+ className={cn(
94
+ "min-w-0 flex-1 truncate text-sm",
95
+ active
96
+ ? "font-medium text-foreground"
97
+ : step.status === "done"
98
+ ? "text-foreground"
99
+ : "text-muted-foreground",
100
+ )}
101
+ title={step.text}
102
+ >
103
+ {step.text}
104
+ </span>
105
+ </div>
106
+ );
107
+ })}
108
+ </div>
109
+ </div>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ </section>
114
+ );
115
+ }