@elizaos/client 1.6.1-alpha.4 → 1.6.1-alpha.6

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 (50) hide show
  1. package/dist/assets/main-BM2lpId8.js +155 -0
  2. package/dist/assets/main-BM2lpId8.js.map +1 -0
  3. package/dist/assets/{main-BOBWcKWW.css → main-CNv6B3RZ.css} +597 -71
  4. package/dist/assets/{main-C4q5_rtN.js → main-CQAV8tyh.js} +4 -4
  5. package/dist/assets/main-CQAV8tyh.js.map +1 -0
  6. package/dist/assets/react-vendor-C1OK-nqm.js +611 -0
  7. package/dist/assets/react-vendor-C1OK-nqm.js.map +1 -0
  8. package/dist/index.html +1 -1
  9. package/package.json +29 -25
  10. package/src/components/agent-prism/Avatar.tsx +164 -0
  11. package/src/components/agent-prism/Badge.tsx +109 -0
  12. package/src/components/agent-prism/Button.tsx +138 -0
  13. package/src/components/agent-prism/CollapseAndExpandControls.tsx +45 -0
  14. package/src/components/agent-prism/CollapsibleSection.tsx +121 -0
  15. package/src/components/agent-prism/DetailsView/DetailsView.tsx +141 -0
  16. package/src/components/agent-prism/DetailsView/DetailsViewAttributesTab.tsx +45 -0
  17. package/src/components/agent-prism/DetailsView/DetailsViewHeader.tsx +77 -0
  18. package/src/components/agent-prism/DetailsView/DetailsViewHeaderActions.tsx +21 -0
  19. package/src/components/agent-prism/DetailsView/DetailsViewInputOutputTab.tsx +210 -0
  20. package/src/components/agent-prism/DetailsView/DetailsViewMetrics.tsx +53 -0
  21. package/src/components/agent-prism/DetailsView/DetailsViewRawDataTab.tsx +24 -0
  22. package/src/components/agent-prism/IconButton.tsx +75 -0
  23. package/src/components/agent-prism/PriceBadge.tsx +12 -0
  24. package/src/components/agent-prism/SearchInput.tsx +17 -0
  25. package/src/components/agent-prism/SpanCard/SpanCard.tsx +467 -0
  26. package/src/components/agent-prism/SpanCard/SpanCardBadges.tsx +35 -0
  27. package/src/components/agent-prism/SpanCard/SpanCardConnector.tsx +36 -0
  28. package/src/components/agent-prism/SpanCard/SpanCardTimeline.tsx +60 -0
  29. package/src/components/agent-prism/SpanCard/SpanCardToggle.tsx +32 -0
  30. package/src/components/agent-prism/SpanStatus.tsx +79 -0
  31. package/src/components/agent-prism/Tabs.tsx +141 -0
  32. package/src/components/agent-prism/TextInput.tsx +142 -0
  33. package/src/components/agent-prism/TimestampBadge.tsx +28 -0
  34. package/src/components/agent-prism/TokensBadge.tsx +26 -0
  35. package/src/components/agent-prism/TraceList/TraceList.tsx +80 -0
  36. package/src/components/agent-prism/TraceList/TraceListItem.tsx +79 -0
  37. package/src/components/agent-prism/TraceList/TraceListItemHeader.tsx +46 -0
  38. package/src/components/agent-prism/TraceViewer.tsx +476 -0
  39. package/src/components/agent-prism/TreeView.tsx +57 -0
  40. package/src/components/agent-prism/shared.ts +210 -0
  41. package/src/components/agent-runs/AgentRunTimeline.tsx +64 -673
  42. package/src/components/agent-sidebar.tsx +2 -2
  43. package/src/components/chat.tsx +8 -8
  44. package/src/lib/agent-prism-utils.ts +46 -0
  45. package/src/lib/eliza-span-adapter.ts +487 -0
  46. package/dist/assets/main-BNtEiK3o.js +0 -141
  47. package/dist/assets/main-BNtEiK3o.js.map +0 -1
  48. package/dist/assets/main-C4q5_rtN.js.map +0 -1
  49. package/dist/assets/react-vendor-pe76PXQl.js +0 -546
  50. package/dist/assets/react-vendor-pe76PXQl.js.map +0 -1
package/dist/index.html CHANGED
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="icon" type="image/x-icon" href="/favicon.ico" />
7
7
  <title>ElizaOS - Client</title>
8
- <script type="module" crossorigin src="/assets/main-C4q5_rtN.js"></script>
8
+ <script type="module" crossorigin src="/assets/main-CQAV8tyh.js"></script>
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/client",
3
- "version": "1.6.1-alpha.4",
3
+ "version": "1.6.1-alpha.6",
4
4
  "description": "Web client interface for ElizaOS agents",
5
5
  "repository": {
6
6
  "type": "git",
@@ -61,8 +61,10 @@
61
61
  "access": "public"
62
62
  },
63
63
  "dependencies": {
64
- "@elizaos/api-client": "1.6.1-alpha.4",
65
- "@elizaos/core": "1.6.1-alpha.4",
64
+ "@elizaos/api-client": "1.6.1-alpha.6",
65
+ "@elizaos/core": "1.6.1-alpha.6",
66
+ "@evilmartians/agent-prism-data": "^0.0.4",
67
+ "@evilmartians/agent-prism-types": "^0.0.4",
66
68
  "@hookform/resolvers": "^5.1.1",
67
69
  "@radix-ui/react-alert-dialog": "^1.0.5",
68
70
  "@radix-ui/react-avatar": "^1.1.3",
@@ -79,25 +81,27 @@
79
81
  "@radix-ui/react-tabs": "^1.1.3",
80
82
  "@radix-ui/react-toast": "^1.2.6",
81
83
  "@radix-ui/react-tooltip": "^1.1.8",
82
- "@react-spring/web": "^9.7.5",
84
+ "@react-spring/web": "^10.0.3",
83
85
  "@tanstack/react-query": "^5.67.2",
84
86
  "@uidotdev/usehooks": "^2.4.1",
85
87
  "buffer": "^6.0.3",
86
88
  "class-variance-authority": "^0.7.1",
89
+ "classnames": "^2.5.1",
87
90
  "clsx": "2.1.1",
88
91
  "cmdk": "^1.0.4",
89
92
  "date-fns": "^4.1.0",
90
93
  "dayjs": "^1.11.13",
91
94
  "evt": "^2.5.9",
92
- "lucide-react": "^0.469.0",
95
+ "lucide-react": "^0.544.0",
93
96
  "react": "^19.1.0",
94
97
  "react-aiwriter": "^1.0.0",
95
98
  "react-dom": "^19.1.0",
96
99
  "react-force-graph": "^1.47.6",
97
100
  "react-force-graph-2d": "^1.27.1",
98
101
  "react-joyride": "^2.9.3",
102
+ "react-json-pretty": "^2.2.0",
99
103
  "react-markdown": "^10.1.0",
100
- "react-resizable-panels": "^2.1.7",
104
+ "react-resizable-panels": "^3.0.6",
101
105
  "react-router": "^7.3.0",
102
106
  "react-router-dom": "^7.3.0",
103
107
  "remark-breaks": "^4.0.0",
@@ -105,7 +109,7 @@
105
109
  "semver": "^7.7.1",
106
110
  "shiki": "^3.6.0",
107
111
  "socket.io-client": "^4.8.1",
108
- "tailwind-merge": "^2.6.0",
112
+ "tailwind-merge": "^3.3.1",
109
113
  "tailwindcss-animate": "^1.0.7",
110
114
  "use-stick-to-bottom": "^1.1.1",
111
115
  "vis-data": "^8.0.3",
@@ -114,48 +118,48 @@
114
118
  },
115
119
  "devDependencies": {
116
120
  "@cypress/react": "^9.0.1",
117
- "@cypress/vite-dev-server": "^6.0.3",
121
+ "@cypress/vite-dev-server": "^7.0.0",
118
122
  "@eslint/js": "^9.22.0",
119
- "@happy-dom/global-registrator": "^18.0.1",
123
+ "@happy-dom/global-registrator": "^19.0.2",
120
124
  "@playwright/test": "^1.40.0",
121
125
  "@radix-ui/react-direction": "^1.1.1",
122
126
  "@rollup/plugin-inject": "^5.0.5",
123
127
  "@tailwindcss/vite": "^4.1.0",
124
128
  "@testing-library/cypress": "^10.0.3",
125
129
  "@testing-library/jest-dom": "^6.6.3",
126
- "@testing-library/react": "^14.0.0",
130
+ "@testing-library/react": "^16.3.0",
127
131
  "@testing-library/react-hooks": "^8.0.1",
128
132
  "@types/cypress": "^1.1.6",
129
133
  "@types/node": "^24.0.1",
130
- "@types/react": "^19.0.10",
134
+ "@types/react": "^19.1.16",
131
135
  "@types/react-dom": "^19.0.4",
132
136
  "@types/semver": "^7.5.8",
133
- "@typescript-eslint/eslint-plugin": "8.26.0",
134
- "@typescript-eslint/parser": "8.26.0",
135
- "@vitejs/plugin-react-swc": "^3.7.2",
137
+ "@typescript-eslint/eslint-plugin": "8.45.0",
138
+ "@typescript-eslint/parser": "8.45.0",
139
+ "@vitejs/plugin-react-swc": "^4.1.0",
136
140
  "asn1.js": "^5.4.1",
137
- "cypress": "^14.5.4",
141
+ "cypress": "^15.3.0",
138
142
  "cypress-real-events": "^1.14.0",
139
143
  "eslint": "^9.22.0",
140
- "eslint-import-resolver-typescript": "^3.8.3",
144
+ "eslint-import-resolver-typescript": "^4.4.4",
141
145
  "eslint-plugin-import": "^2.31.0",
142
146
  "eslint-plugin-jsx-a11y": "^6.10.2",
143
147
  "eslint-plugin-react": "^7.37.4",
144
148
  "eslint-plugin-react-hooks": "^5.2.0",
145
149
  "eslint-plugin-react-refresh": "^0.4.19",
146
150
  "evp_bytestokey": "^1.0.3",
147
- "globals": "^15.15.0",
148
- "jsdom": "^26.1.0",
151
+ "globals": "^16.4.0",
152
+ "jsdom": "^27.0.0",
149
153
  "postcss": "^8.5.3",
150
- "prettier": "3.5.3",
154
+ "prettier": "3.6.2",
151
155
  "process": "^0.11.10",
152
- "rollup-plugin-visualizer": "^5.14.0",
156
+ "rollup-plugin-visualizer": "^6.0.3",
153
157
  "tailwindcss": "^4.1.0",
154
- "typescript": "5.8.2",
155
- "typescript-eslint": "^8.26.0",
156
- "vite": "6.3.6",
158
+ "typescript": "5.9.2",
159
+ "typescript-eslint": "^8.45.0",
160
+ "vite": "^7.1.7",
157
161
  "vite-tsconfig-paths": "^5.1.4",
158
- "wait-on": "^8.0.3"
162
+ "wait-on": "^9.0.1"
159
163
  },
160
- "gitHead": "39870dec366b5a412c69999b3e4b8f114fa10ea7"
164
+ "gitHead": "8a0b8d2bba9bc932188f8a4f7f06360f65748f04"
161
165
  }
@@ -0,0 +1,164 @@
1
+ import { cn } from "@/lib/utils";
2
+ import { User } from "lucide-react";
3
+ import { useState, type ComponentPropsWithRef, type ReactElement } from "react";
4
+
5
+ import {
6
+ ROUNDED_CLASSES,
7
+ type ColorVariant,
8
+ type ComponentSize,
9
+ } from "./shared.ts";
10
+
11
+ export type AvatarSize = Extract<
12
+ ComponentSize,
13
+ "4" | "6" | "8" | "9" | "10" | "11" | "12" | "16"
14
+ >;
15
+
16
+ const sizeClasses: Record<AvatarSize, string> = {
17
+ "4": "size-4 text-xs",
18
+ "6": "size-6 text-xs",
19
+ "8": "size-8 text-xs",
20
+ "9": "size-9 text-sm",
21
+ "10": "size-10 text-base",
22
+ "11": "size-11 text-lg",
23
+ "12": "size-12 text-xl",
24
+ "16": "size-16 text-2xl",
25
+ };
26
+
27
+ const iconSizeClasses: Record<AvatarSize, string> = {
28
+ "4": "size-3",
29
+ "6": "size-4",
30
+ "8": "size-6",
31
+ "9": "size-7",
32
+ "10": "size-8",
33
+ "11": "size-9",
34
+ "12": "size-10",
35
+ "16": "size-12",
36
+ };
37
+
38
+ const textSizeClasses: Record<AvatarSize, string> = {
39
+ "4": "text-xs",
40
+ "6": "text-xs",
41
+ "8": "text-xs",
42
+ "9": "text-sm",
43
+ "10": "text-base",
44
+ "11": "text-lg",
45
+ "12": "text-xl",
46
+ "16": "text-2xl",
47
+ };
48
+
49
+ const bgColorClasses: Record<ColorVariant, string> = {
50
+ gray: "bg-muted-foreground",
51
+ red: "bg-destructive",
52
+ orange: "bg-chart-1",
53
+ yellow: "bg-chart-5",
54
+ teal: "bg-chart-2",
55
+ indigo: "bg-primary",
56
+ purple: "bg-primary",
57
+ sky: "bg-chart-4",
58
+ cyan: "bg-chart-3",
59
+ emerald: "bg-accent",
60
+ };
61
+
62
+ export type AvatarProps = ComponentPropsWithRef<"div"> & {
63
+ /**
64
+ * The image source for the avatar
65
+ */
66
+ src?: string;
67
+ /**
68
+ * The alt text for the avatar
69
+ */
70
+ alt?: string;
71
+ /**
72
+ * The size of the avatar
73
+ * @default "md"
74
+ */
75
+ size?: AvatarSize;
76
+ /**
77
+ * The border radius of the avatar
78
+ * @default "full"
79
+ */
80
+ rounded?: "none" | "sm" | "md" | "lg" | "full";
81
+ /**
82
+ * Background color theme for the letter avatar
83
+ * Uses the unified color theme system
84
+ * @default "gray"
85
+ */
86
+ bgColor?: ColorVariant;
87
+ /**
88
+ * Text color for the letter avatar
89
+ * @default "white"
90
+ */
91
+ textColor?: "white" | "black";
92
+ /**
93
+ * Custom letter to display (will use first letter of alt if not provided)
94
+ */
95
+ letter?: string;
96
+ /**
97
+ * Optional className for additional styling
98
+ */
99
+ className?: string;
100
+ };
101
+
102
+ export const Avatar = ({
103
+ src,
104
+ alt = "Avatar",
105
+ size = "10",
106
+ rounded = "full",
107
+ bgColor = "gray",
108
+ textColor = "white",
109
+ letter,
110
+ className = "",
111
+ ...rest
112
+ }: AvatarProps): ReactElement => {
113
+ const [error, setError] = useState(false);
114
+
115
+ const displayLetter = letter ? letter.charAt(0) : alt.charAt(0).toUpperCase();
116
+
117
+ const actualTextColor = textColor === "white" ? "text-white" : "text-black";
118
+
119
+ return (
120
+ <div
121
+ className={cn(
122
+ "flex items-center justify-center overflow-hidden",
123
+ "bg-muted",
124
+ error && "border border-border",
125
+ sizeClasses[size],
126
+ textSizeClasses[size],
127
+ ROUNDED_CLASSES[rounded],
128
+ className,
129
+ )}
130
+ {...rest}
131
+ >
132
+ {error ? (
133
+ <User
134
+ className={cn(
135
+ iconSizeClasses[size],
136
+ "text-muted-foreground",
137
+ )}
138
+ />
139
+ ) : (
140
+ <>
141
+ {src ? (
142
+ <img
143
+ src={src}
144
+ alt={alt}
145
+ className="h-full w-full object-cover"
146
+ onError={() => setError(true)}
147
+ />
148
+ ) : (
149
+ <div
150
+ className={cn(
151
+ "flex h-full w-full items-center justify-center",
152
+ bgColorClasses[bgColor],
153
+ actualTextColor,
154
+ "font-medium",
155
+ )}
156
+ >
157
+ {displayLetter}
158
+ </div>
159
+ )}
160
+ </>
161
+ )}
162
+ </div>
163
+ );
164
+ };
@@ -0,0 +1,109 @@
1
+ import type { ComponentPropsWithRef, ReactElement, ReactNode } from "react";
2
+
3
+ import { cn } from "@/lib/utils";
4
+
5
+ import {
6
+ COLOR_THEME_CLASSES,
7
+ type ColorVariant,
8
+ type ComponentSize,
9
+ } from "./shared.ts";
10
+
11
+ type BadgeSize = Extract<ComponentSize, "4" | "5" | "6" | "7">;
12
+
13
+ const sizeClasses: Record<BadgeSize, string> = {
14
+ "4": "px-1 gap-1 h-4",
15
+ "5": "px-1.5 gap-1 h-5",
16
+ "6": "px-2 gap-1.5 h-6",
17
+ "7": "px-2.5 gap-2 h-7",
18
+ };
19
+
20
+ const textSizes: Record<BadgeSize, string> = {
21
+ "4": "text-xs font-normal leading-3",
22
+ "5": "text-xs font-medium",
23
+ "6": "text-sm font-medium",
24
+ "7": "text-sm font-medium",
25
+ };
26
+
27
+ export type BadgeProps = ComponentPropsWithRef<"span"> & {
28
+ /**
29
+ * The content of the badge
30
+ */
31
+ label: ReactNode;
32
+
33
+ /**
34
+ * The color theme of the badge
35
+ * Uses the unified color theme system
36
+ * @default "gray"
37
+ */
38
+ theme: ColorVariant;
39
+
40
+ /**
41
+ * The visual variant of the badge
42
+ * @default "solid"
43
+ */
44
+ variant?: "solid" | "outline";
45
+
46
+ /**
47
+ * The size of the badge
48
+ * @default "md"
49
+ */
50
+ size?: BadgeSize;
51
+
52
+ /**
53
+ * Optional icon to display at the start of the badge
54
+ */
55
+ iconStart?: ReactElement;
56
+
57
+ /**
58
+ * Optional icon to display at the end of the badge
59
+ */
60
+ iconEnd?: ReactElement;
61
+
62
+ /**
63
+ * Optional className for additional styling
64
+ */
65
+ className?: string;
66
+ };
67
+
68
+ export const Badge = ({
69
+ label,
70
+ theme = "gray",
71
+ variant = "solid",
72
+ size = "4",
73
+ iconStart,
74
+ iconEnd,
75
+ className = "",
76
+ ...rest
77
+ }: BadgeProps): ReactElement => {
78
+ const { bg, darkBg, text, darkText } = COLOR_THEME_CLASSES[theme];
79
+
80
+ const variantClasses =
81
+ variant === "outline"
82
+ ? `border ${text} ${darkText} bg-transparent dark:bg-transparent border-current`
83
+ : `${bg} ${text} ${darkBg} ${darkText}`;
84
+
85
+ return (
86
+ <span
87
+ className={cn(
88
+ "inline-flex min-w-0 items-center overflow-hidden rounded font-medium",
89
+ variantClasses,
90
+ sizeClasses[size],
91
+ className,
92
+ )}
93
+ {...rest}
94
+ >
95
+ {iconStart && <span className="shrink-0">{iconStart}</span>}
96
+
97
+ <span
98
+ className={cn(
99
+ textSizes[size],
100
+ "min-w-0 max-w-full flex-shrink-0 truncate tracking-normal",
101
+ )}
102
+ >
103
+ {label}
104
+ </span>
105
+
106
+ {iconEnd && <span className="shrink-0">{iconEnd}</span>}
107
+ </span>
108
+ );
109
+ };
@@ -0,0 +1,138 @@
1
+ import type { ComponentPropsWithRef, ReactElement } from "react";
2
+
3
+ import { cn } from "@/lib/utils";
4
+
5
+ import {
6
+ ROUNDED_CLASSES,
7
+ type ColorVariant,
8
+ type ComponentSize,
9
+ } from "./shared.ts";
10
+
11
+ type ButtonSize = Extract<
12
+ ComponentSize,
13
+ "6" | "7" | "8" | "9" | "10" | "11" | "12" | "16"
14
+ >;
15
+
16
+ const BASE_CLASSES =
17
+ "inline-flex items-center justify-center font-medium transition-all duration-200";
18
+
19
+ const sizeClasses = {
20
+ "6": "h-6 px-2 gap-1 text-xs",
21
+ "7": "h-7 px-2 gap-1 text-xs",
22
+ "8": "h-8 px-2 gap-1 text-xs",
23
+ "9": "h-9 px-2.5 gap-2 text-sm",
24
+ "10": "h-10 px-4 gap-2 text-sm",
25
+ "11": "h-11 px-5 gap-3 text-base",
26
+ "12": "h-12 px-5 gap-2.5 text-base",
27
+ "16": "h-16 px-7 gap-3 text-lg",
28
+ };
29
+
30
+ const filledThemeClasses: Record<ColorVariant, string> = {
31
+ gray: "bg-muted text-muted-foreground",
32
+ purple: "bg-primary text-primary-foreground",
33
+ indigo: "bg-primary text-primary-foreground",
34
+ orange: "bg-chart-1 text-primary-foreground",
35
+ teal: "bg-chart-2 text-primary-foreground",
36
+ cyan: "bg-chart-3 text-primary-foreground",
37
+ sky: "bg-chart-4 text-primary-foreground",
38
+ yellow: "bg-chart-5 text-primary-foreground",
39
+ emerald: "bg-accent text-accent-foreground",
40
+ red: "bg-destructive text-destructive-foreground",
41
+ };
42
+
43
+ const variantClasses = {
44
+ filled: "",
45
+ outlined:
46
+ "border border-2 bg-transparent text-foreground border-border",
47
+ ghost: "bg-transparent text-muted-foreground",
48
+ };
49
+
50
+ export type ButtonProps = ComponentPropsWithRef<"button"> & {
51
+ /**
52
+ * The size of the button
53
+ * @default "6"
54
+ */
55
+ size?: ButtonSize;
56
+
57
+ /**
58
+ * The color theme of the button
59
+ * @default "gray"
60
+ */
61
+ theme?: ColorVariant;
62
+
63
+ /**
64
+ * The border radius of the button
65
+ * @default "md"
66
+ */
67
+ rounded?: "none" | "sm" | "md" | "lg" | "full";
68
+
69
+ /**
70
+ * The visual variant of the button
71
+ * @default "filled"
72
+ */
73
+ variant?: "filled" | "outlined" | "ghost";
74
+
75
+ /**
76
+ * Makes the button full width
77
+ * @default false
78
+ */
79
+ fullWidth?: boolean;
80
+
81
+ /**
82
+ * Optional icon to display at the start of the button
83
+ */
84
+ iconStart?: ReactElement;
85
+
86
+ /**
87
+ * Optional icon to display at the end of the button
88
+ */
89
+ iconEnd?: ReactElement;
90
+ };
91
+
92
+ export const Button = ({
93
+ children,
94
+ size = "6",
95
+ theme = "gray",
96
+ rounded = "md",
97
+ variant = "filled",
98
+ fullWidth = false,
99
+ disabled = false,
100
+ iconStart,
101
+ iconEnd,
102
+ type = "button",
103
+ onClick,
104
+ className = "",
105
+ ...rest
106
+ }: ButtonProps) => {
107
+ const widthClass = fullWidth ? "w-full" : "";
108
+ const stateClasses = disabled
109
+ ? "cursor-not-allowed opacity-50"
110
+ : "hover:opacity-70";
111
+ const filledThemeClass =
112
+ variant === "filled"
113
+ ? filledThemeClasses[theme] || filledThemeClasses.gray
114
+ : "";
115
+
116
+ return (
117
+ <button
118
+ type={type}
119
+ onClick={onClick}
120
+ disabled={disabled}
121
+ className={cn(
122
+ BASE_CLASSES,
123
+ sizeClasses[size],
124
+ ROUNDED_CLASSES[rounded],
125
+ variantClasses[variant],
126
+ filledThemeClass,
127
+ widthClass,
128
+ stateClasses,
129
+ className,
130
+ )}
131
+ {...rest}
132
+ >
133
+ {iconStart && <span className="mr-1">{iconStart}</span>}
134
+ {children}
135
+ {iconEnd && <span className="ml-1">{iconEnd}</span>}
136
+ </button>
137
+ );
138
+ };
@@ -0,0 +1,45 @@
1
+ import type { ComponentPropsWithRef } from "react";
2
+
3
+ import { ChevronsUpDown, ChevronsDownUp } from "lucide-react";
4
+
5
+ import { IconButton } from "./IconButton.tsx";
6
+
7
+ export type SpanCardExpandAllButtonProps = ComponentPropsWithRef<"button"> & {
8
+ onExpandAll: () => void;
9
+ };
10
+
11
+ export type SpanCardCollapseAllButtonProps = ComponentPropsWithRef<"button"> & {
12
+ onCollapseAll: () => void;
13
+ };
14
+
15
+ export const ExpandAllButton = ({
16
+ onExpandAll,
17
+ ...rest
18
+ }: SpanCardExpandAllButtonProps) => {
19
+ return (
20
+ <IconButton
21
+ size="7"
22
+ onClick={onExpandAll}
23
+ aria-label="Expand all"
24
+ {...rest}
25
+ >
26
+ <ChevronsUpDown className="size-3.5" />
27
+ </IconButton>
28
+ );
29
+ };
30
+
31
+ export const CollapseAllButton = ({
32
+ onCollapseAll,
33
+ ...rest
34
+ }: SpanCardCollapseAllButtonProps) => {
35
+ return (
36
+ <IconButton
37
+ size="7"
38
+ onClick={onCollapseAll}
39
+ aria-label="Collapse all"
40
+ {...rest}
41
+ >
42
+ <ChevronsDownUp className="size-3.5" />
43
+ </IconButton>
44
+ );
45
+ };