@mastra/playground-ui 48.0.0 → 48.1.0-alpha.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.
- package/CHANGELOG.md +23 -0
- package/dist/Composer.css +2 -2
- package/dist/components/ai/task-list.cjs.js +44 -18
- package/dist/components/ai/task-list.cjs.js.map +1 -1
- package/dist/components/ai/task-list.es.js +47 -21
- package/dist/components/ai/task-list.es.js.map +1 -1
- package/dist/src/ds/components/ai/task-list/task-list.d.ts +4 -2
- package/dist/src/ds/components/ai/task-list/task-list.stories.d.ts +2 -0
- package/dist/style.css +0 -4
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# @mastra/playground-ui
|
|
2
2
|
|
|
3
|
+
## 48.1.0-alpha.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Made the task list collapsible and moved its scrolling to the design system scroll area. ([#21337](https://github.com/mastra-ai/mastra/pull/21337))
|
|
8
|
+
|
|
9
|
+
Clicking the task list header now collapses it. The collapsed row keeps the completion count and shows the task currently in progress — or the next pending one — with its status icon and color, so the panel can be minimized without losing track of where the agent is. Long lists scroll inside `ScrollArea` (overlay scrollbar, edge fades) instead of a raw `overflow-y` container.
|
|
10
|
+
|
|
11
|
+
Use `defaultOpen` to render it collapsed:
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<TaskList tasks={tasks} defaultOpen={false} />
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Fixed the composer edge glow so it follows the cursor only when the cursor is actually there. Focusing the composer used to light the moving arc as well, which meant the coloured segment kept sliding around the border while you typed or moved the mouse anywhere on the page. Focus now just brightens the border, and the arc lights on hover. ([#21320](https://github.com/mastra-ai/mastra/pull/21320))
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [[`088e41e`](https://github.com/mastra-ai/mastra/commit/088e41e434ed05f2c674b254f1034ec46a57a7be), [`b2f0013`](https://github.com/mastra-ai/mastra/commit/b2f0013375588d40c03c13e843b99c0ff8872ca5), [`3b541ae`](https://github.com/mastra-ai/mastra/commit/3b541ae5d410c52b80a7e381d84d021cddb9a449), [`ae79e34`](https://github.com/mastra-ai/mastra/commit/ae79e34c0bd8674fc24c7524217bfc4a051c6136), [`a6c4399`](https://github.com/mastra-ai/mastra/commit/a6c4399763590b3dae21a2c81826e89a3b1deee4)]:
|
|
22
|
+
- @mastra/core@1.59.0-alpha.0
|
|
23
|
+
- @mastra/client-js@1.39.1-alpha.0
|
|
24
|
+
- @mastra/react@1.4.3-alpha.0
|
|
25
|
+
|
|
3
26
|
## 48.0.0
|
|
4
27
|
|
|
5
28
|
### Minor Changes
|
package/dist/Composer.css
CHANGED
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
background-color: var(--border2);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
.
|
|
51
|
-
.composer-ring:
|
|
50
|
+
/* The arc tracks the cursor, so it lights on hover only — focus brightens the edge instead. */
|
|
51
|
+
.composer-ring:hover {
|
|
52
52
|
--composer-ring-strength: 0.4;
|
|
53
53
|
}
|
|
54
54
|
|
|
@@ -5,11 +5,19 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
5
5
|
const jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
const lucideReact = require('lucide-react');
|
|
7
7
|
const React = require('react');
|
|
8
|
+
const collapsible = require('../../collapsible-CoBU143c.cjs');
|
|
9
|
+
const scrollArea = require('../../scroll-area-Dv6QagXt.cjs');
|
|
8
10
|
const utils_cn = require('../../cn-vA5sWo9W.cjs');
|
|
9
11
|
|
|
10
12
|
const TaskListContainer = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("section", { className: utils_cn.cn("rounded-2xl border border-border2/40 bg-surface3 px-3 py-2.5", className), ...props });
|
|
11
|
-
const TaskListHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12
|
-
|
|
13
|
+
const TaskListHeader = ({ className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
14
|
+
collapsible.CollapsibleTrigger,
|
|
15
|
+
{
|
|
16
|
+
className: utils_cn.cn("flex w-full cursor-pointer items-center gap-2 text-left text-neutral4", className),
|
|
17
|
+
...props
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
const TaskListCount = ({ completed, total, className, ...props }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: utils_cn.cn("ml-auto shrink-0 text-ui-xs text-neutral4 tabular-nums", className), ...props, children: [
|
|
13
21
|
completed,
|
|
14
22
|
"/",
|
|
15
23
|
total,
|
|
@@ -25,7 +33,7 @@ const TaskListProgress = ({ completed, total, className, ...props }) => {
|
|
|
25
33
|
"aria-valuemin": 0,
|
|
26
34
|
"aria-valuemax": total,
|
|
27
35
|
"aria-valuenow": completed,
|
|
28
|
-
className: utils_cn.cn("mb-2.5 h-1 w-full rounded-full bg-surface4", className),
|
|
36
|
+
className: utils_cn.cn("mt-2 mb-2.5 h-1 w-full rounded-full bg-surface4", className),
|
|
29
37
|
...props,
|
|
30
38
|
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-accent6 h-full rounded-full transition-all duration-300", style: { width: `${percentage}%` } })
|
|
31
39
|
}
|
|
@@ -46,38 +54,56 @@ const textClasses = {
|
|
|
46
54
|
in_progress: "font-medium text-warning1",
|
|
47
55
|
pending: "text-neutral5"
|
|
48
56
|
};
|
|
49
|
-
const
|
|
57
|
+
const taskLabel = (task) => task.status === "in_progress" ? task.activeForm : task.content;
|
|
58
|
+
const TaskListStatusIcon = ({ status, className, ...props }) => /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-label": statusLabels[status], className: utils_cn.cn("flex pt-0.5", className), ...props, children: icons[status] });
|
|
50
59
|
const TaskListRow = ({ task, className, ...props }) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: utils_cn.cn("flex items-start gap-2 py-0.5", className), ...props, children: [
|
|
51
60
|
/* @__PURE__ */ jsxRuntime.jsx(TaskListStatusIcon, { status: task.status }),
|
|
52
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: utils_cn.cn("text-ui-sm leading-ui-sm", textClasses[task.status]), children: task
|
|
61
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: utils_cn.cn("text-ui-sm leading-ui-sm", textClasses[task.status]), children: taskLabel(task) })
|
|
53
62
|
] });
|
|
63
|
+
const TaskListSummary = ({ task }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx(TaskListStatusIcon, { status: task.status, className: "pt-0" }),
|
|
65
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: utils_cn.cn("truncate text-ui-sm leading-ui-sm", textClasses[task.status]), children: taskLabel(task) })
|
|
66
|
+
] });
|
|
67
|
+
const TaskListTitle = ({ title }) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
68
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ListChecks, { className: "text-accent6 size-4 shrink-0" }),
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-sm leading-ui-sm text-neutral6 truncate font-medium", children: title })
|
|
70
|
+
] });
|
|
71
|
+
const scrollTaskIntoView = (node) => {
|
|
72
|
+
if (typeof node?.scrollIntoView === "function") node.scrollIntoView({ block: "nearest" });
|
|
73
|
+
};
|
|
54
74
|
const TaskList = ({
|
|
55
75
|
tasks,
|
|
56
76
|
title = "Tasks",
|
|
57
77
|
hideWhenEmpty = true,
|
|
58
78
|
hideWhenComplete = true,
|
|
59
79
|
scrollActiveIntoView = true,
|
|
80
|
+
defaultOpen = true,
|
|
60
81
|
...props
|
|
61
82
|
}) => {
|
|
62
|
-
const
|
|
63
|
-
const
|
|
83
|
+
const [open, setOpen] = React.useState(defaultOpen);
|
|
84
|
+
const activeTask = tasks.find((task) => task.status === "in_progress");
|
|
85
|
+
const summaryTask = activeTask ?? tasks.find((task) => task.status === "pending");
|
|
64
86
|
const completed = tasks.filter((task) => task.status === "completed").length;
|
|
65
87
|
const total = tasks.length;
|
|
66
|
-
React.useEffect(() => {
|
|
67
|
-
if (!scrollActiveIntoView || !activeTaskRef.current || typeof activeTaskRef.current.scrollIntoView !== "function")
|
|
68
|
-
return;
|
|
69
|
-
activeTaskRef.current.scrollIntoView({ block: "nearest" });
|
|
70
|
-
}, [activeTaskId, scrollActiveIntoView]);
|
|
71
88
|
if (hideWhenEmpty && total === 0 || hideWhenComplete && total > 0 && completed === total) return null;
|
|
72
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
89
|
+
return /* @__PURE__ */ jsxRuntime.jsx(TaskListContainer, { "aria-label": "Task list", "data-testid": "task-list", ...props, children: /* @__PURE__ */ jsxRuntime.jsxs(collapsible.Collapsible, { open, onOpenChange: setOpen, children: [
|
|
73
90
|
/* @__PURE__ */ jsxRuntime.jsxs(TaskListHeader, { children: [
|
|
74
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
75
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
92
|
+
open || !summaryTask ? /* @__PURE__ */ jsxRuntime.jsx(TaskListTitle, { title }) : /* @__PURE__ */ jsxRuntime.jsx(TaskListSummary, { task: summaryTask }),
|
|
76
93
|
/* @__PURE__ */ jsxRuntime.jsx(TaskListCount, { completed, total })
|
|
77
94
|
] }),
|
|
78
|
-
/* @__PURE__ */ jsxRuntime.
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsxs(collapsible.CollapsibleContent, { children: [
|
|
96
|
+
/* @__PURE__ */ jsxRuntime.jsx(TaskListProgress, { completed, total }),
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsx(scrollArea.ScrollArea, { maxHeight: "8rem", viewPortClassName: "pr-1", children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "space-y-1", children: tasks.map((task) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
98
|
+
TaskListRow,
|
|
99
|
+
{
|
|
100
|
+
ref: scrollActiveIntoView && task.id === activeTask?.id ? scrollTaskIntoView : void 0,
|
|
101
|
+
task
|
|
102
|
+
},
|
|
103
|
+
task.id
|
|
104
|
+
)) }) })
|
|
105
|
+
] })
|
|
106
|
+
] }) });
|
|
81
107
|
};
|
|
82
108
|
|
|
83
109
|
exports.TaskList = TaskList;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-list.cjs.js","sources":["../../../src/ds/components/ai/task-list/task-list.tsx"],"sourcesContent":["import type { TaskItem } from '@mastra/core/signals';\nimport { CheckCircle2, Circle, ListChecks, Loader2 } from 'lucide-react';\nimport { useEffect, useRef } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport type TaskListItem = TaskItem;\n\nexport const TaskListContainer = ({ className, ...props }: ComponentProps<'section'>) => (\n <section className={cn('rounded-2xl border border-border2/40 bg-surface3 px-3 py-2.5', className)} {...props} />\n);\n\nexport const TaskListHeader = ({ className, ...props }: ComponentProps<'header'>) => (\n <header className={cn('mb-2 flex items-center gap-2', className)} {...props} />\n);\n\nexport interface TaskListCountProps extends ComponentProps<'span'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListCount = ({ completed, total, className, ...props }: TaskListCountProps) => (\n <span className={cn('ml-auto text-ui-xs text-neutral4 tabular-nums', className)} {...props}>\n {completed}/{total} completed\n </span>\n);\n\nexport interface TaskListProgressProps extends Omit<ComponentProps<'div'>, 'children'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListProgress = ({ completed, total, className, ...props }: TaskListProgressProps) => {\n const percentage = total === 0 ? 0 : (completed / total) * 100;\n return (\n <div\n role=\"progressbar\"\n aria-label=\"Task completion\"\n aria-valuemin={0}\n aria-valuemax={total}\n aria-valuenow={completed}\n className={cn('mb-2.5 h-1 w-full rounded-full bg-surface4', className)}\n {...props}\n >\n <div className=\"bg-accent6 h-full rounded-full transition-all duration-300\" style={{ width: `${percentage}%` }} />\n </div>\n );\n};\n\nconst icons: Record<TaskListItem['status'], ReactNode> = {\n completed: <CheckCircle2 className=\"text-positive1 size-3.5 shrink-0\" />,\n in_progress: <Loader2 className=\"text-warning1 size-3.5 shrink-0 motion-safe:animate-spin\" />,\n pending: <Circle className=\"text-neutral4 size-3.5 shrink-0\" />,\n};\n\nconst statusLabels: Record<TaskListItem['status'], string> = {\n completed: 'Completed',\n in_progress: 'In progress',\n pending: 'Pending',\n};\n\nconst textClasses: Record<TaskListItem['status'], string> = {\n completed: 'text-neutral4 line-through',\n in_progress: 'font-medium text-warning1',\n pending: 'text-neutral5',\n};\n\nexport interface TaskListStatusIconProps extends ComponentProps<'span'> {\n status: TaskListItem['status'];\n}\n\nexport const TaskListStatusIcon = ({ status, className, ...props }: TaskListStatusIconProps) => (\n <span aria-label={statusLabels[status]} className={cn('pt-0.5', className)} {...props}>\n {icons[status]}\n </span>\n);\n\nexport interface TaskListRowProps extends ComponentProps<'li'> {\n task: TaskListItem;\n}\n\nexport const TaskListRow = ({ task, className, ...props }: TaskListRowProps) => (\n <li className={cn('flex items-start gap-2 py-0.5', className)} {...props}>\n <TaskListStatusIcon status={task.status} />\n <span className={cn('text-ui-sm leading-ui-sm', textClasses[task.status])}>\n {task.status === 'in_progress' ? task.activeForm : task.content}\n </span>\n </li>\n);\n\nexport interface TaskListProps extends Omit<ComponentProps<typeof TaskListContainer>, 'children' | 'title'> {\n tasks: TaskListItem[];\n title?: ReactNode;\n hideWhenEmpty?: boolean;\n hideWhenComplete?: boolean;\n scrollActiveIntoView?: boolean;\n}\n\nexport const TaskList = ({\n tasks,\n title = 'Tasks',\n hideWhenEmpty = true,\n hideWhenComplete = true,\n scrollActiveIntoView = true,\n ...props\n}: TaskListProps) => {\n const activeTaskRef = useRef<HTMLLIElement | null>(null);\n const activeTaskId = tasks.find(task => task.status === 'in_progress')?.id;\n const completed = tasks.filter(task => task.status === 'completed').length;\n const total = tasks.length;\n\n useEffect(() => {\n if (!scrollActiveIntoView || !activeTaskRef.current || typeof activeTaskRef.current.scrollIntoView !== 'function')\n return;\n activeTaskRef.current.scrollIntoView({ block: 'nearest' });\n }, [activeTaskId, scrollActiveIntoView]);\n\n if ((hideWhenEmpty && total === 0) || (hideWhenComplete && total > 0 && completed === total)) return null;\n\n return (\n <TaskListContainer aria-label=\"Task list\" data-testid=\"task-list\" {...props}>\n <TaskListHeader>\n <ListChecks className=\"text-accent6 size-4 shrink-0\" />\n <h2 className=\"text-ui-sm leading-ui-sm text-neutral6 font-medium\">{title}</h2>\n <TaskListCount completed={completed} total={total} />\n </TaskListHeader>\n <TaskListProgress completed={completed} total={total} />\n <ul className=\"max-h-32 space-y-1 overflow-y-auto pr-1\">\n {tasks.map(task => (\n <TaskListRow key={task.id} ref={task.id === activeTaskId ? activeTaskRef : undefined} task={task} />\n ))}\n </ul>\n </TaskListContainer>\n );\n};\n"],"names":["jsx","cn","jsxs","CheckCircle2","Loader2","Circle","useRef","useEffect","ListChecks"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task-list.cjs.js","sources":["../../../src/ds/components/ai/task-list/task-list.tsx"],"sourcesContent":["import type { TaskItem } from '@mastra/core/signals';\nimport { CheckCircle2, ChevronRight, Circle, ListChecks, Loader2 } from 'lucide-react';\nimport { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/ds/components/Collapsible';\nimport { ScrollArea } from '@/ds/components/ScrollArea';\nimport { cn } from '@/lib/utils';\n\nexport type TaskListItem = TaskItem;\n\nexport const TaskListContainer = ({ className, ...props }: ComponentProps<'section'>) => (\n <section className={cn('rounded-2xl border border-border2/40 bg-surface3 px-3 py-2.5', className)} {...props} />\n);\n\nexport const TaskListHeader = ({ className, ...props }: ComponentProps<typeof CollapsibleTrigger>) => (\n <CollapsibleTrigger\n className={cn('flex w-full cursor-pointer items-center gap-2 text-left text-neutral4', className)}\n {...props}\n />\n);\n\nexport interface TaskListCountProps extends ComponentProps<'span'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListCount = ({ completed, total, className, ...props }: TaskListCountProps) => (\n <span className={cn('ml-auto shrink-0 text-ui-xs text-neutral4 tabular-nums', className)} {...props}>\n {completed}/{total} completed\n </span>\n);\n\nexport interface TaskListProgressProps extends Omit<ComponentProps<'div'>, 'children'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListProgress = ({ completed, total, className, ...props }: TaskListProgressProps) => {\n const percentage = total === 0 ? 0 : (completed / total) * 100;\n return (\n <div\n role=\"progressbar\"\n aria-label=\"Task completion\"\n aria-valuemin={0}\n aria-valuemax={total}\n aria-valuenow={completed}\n className={cn('mt-2 mb-2.5 h-1 w-full rounded-full bg-surface4', className)}\n {...props}\n >\n <div className=\"bg-accent6 h-full rounded-full transition-all duration-300\" style={{ width: `${percentage}%` }} />\n </div>\n );\n};\n\nconst icons: Record<TaskListItem['status'], ReactNode> = {\n completed: <CheckCircle2 className=\"text-positive1 size-3.5 shrink-0\" />,\n in_progress: <Loader2 className=\"text-warning1 size-3.5 shrink-0 motion-safe:animate-spin\" />,\n pending: <Circle className=\"text-neutral4 size-3.5 shrink-0\" />,\n};\n\nconst statusLabels: Record<TaskListItem['status'], string> = {\n completed: 'Completed',\n in_progress: 'In progress',\n pending: 'Pending',\n};\n\nconst textClasses: Record<TaskListItem['status'], string> = {\n completed: 'text-neutral4 line-through',\n in_progress: 'font-medium text-warning1',\n pending: 'text-neutral5',\n};\n\nconst taskLabel = (task: TaskListItem) => (task.status === 'in_progress' ? task.activeForm : task.content);\n\nexport interface TaskListStatusIconProps extends ComponentProps<'span'> {\n status: TaskListItem['status'];\n}\n\nexport const TaskListStatusIcon = ({ status, className, ...props }: TaskListStatusIconProps) => (\n <span aria-label={statusLabels[status]} className={cn('flex pt-0.5', className)} {...props}>\n {icons[status]}\n </span>\n);\n\nexport interface TaskListRowProps extends ComponentProps<'li'> {\n task: TaskListItem;\n}\n\nexport const TaskListRow = ({ task, className, ...props }: TaskListRowProps) => (\n <li className={cn('flex items-start gap-2 py-0.5', className)} {...props}>\n <TaskListStatusIcon status={task.status} />\n <span className={cn('text-ui-sm leading-ui-sm', textClasses[task.status])}>{taskLabel(task)}</span>\n </li>\n);\n\nconst TaskListSummary = ({ task }: { task: TaskListItem }) => (\n <span className=\"flex min-w-0 flex-1 items-center gap-2\">\n <TaskListStatusIcon status={task.status} className=\"pt-0\" />\n <span className={cn('truncate text-ui-sm leading-ui-sm', textClasses[task.status])}>{taskLabel(task)}</span>\n </span>\n);\n\nconst TaskListTitle = ({ title }: { title: ReactNode }) => (\n <span className=\"flex min-w-0 flex-1 items-center gap-2\">\n <ListChecks className=\"text-accent6 size-4 shrink-0\" />\n <span className=\"text-ui-sm leading-ui-sm text-neutral6 truncate font-medium\">{title}</span>\n </span>\n);\n\nconst scrollTaskIntoView = (node: HTMLLIElement | null) => {\n if (typeof node?.scrollIntoView === 'function') node.scrollIntoView({ block: 'nearest' });\n};\n\nexport interface TaskListProps extends Omit<ComponentProps<typeof TaskListContainer>, 'children' | 'title'> {\n tasks: TaskListItem[];\n title?: ReactNode;\n hideWhenEmpty?: boolean;\n hideWhenComplete?: boolean;\n scrollActiveIntoView?: boolean;\n defaultOpen?: boolean;\n}\n\nexport const TaskList = ({\n tasks,\n title = 'Tasks',\n hideWhenEmpty = true,\n hideWhenComplete = true,\n scrollActiveIntoView = true,\n defaultOpen = true,\n ...props\n}: TaskListProps) => {\n const [open, setOpen] = useState(defaultOpen);\n const activeTask = tasks.find(task => task.status === 'in_progress');\n const summaryTask = activeTask ?? tasks.find(task => task.status === 'pending');\n const completed = tasks.filter(task => task.status === 'completed').length;\n const total = tasks.length;\n\n if ((hideWhenEmpty && total === 0) || (hideWhenComplete && total > 0 && completed === total)) return null;\n\n return (\n <TaskListContainer aria-label=\"Task list\" data-testid=\"task-list\" {...props}>\n <Collapsible open={open} onOpenChange={setOpen}>\n <TaskListHeader>\n <ChevronRight className=\"size-3.5 shrink-0\" />\n {open || !summaryTask ? <TaskListTitle title={title} /> : <TaskListSummary task={summaryTask} />}\n <TaskListCount completed={completed} total={total} />\n </TaskListHeader>\n <CollapsibleContent>\n <TaskListProgress completed={completed} total={total} />\n <ScrollArea maxHeight=\"8rem\" viewPortClassName=\"pr-1\">\n <ul className=\"space-y-1\">\n {tasks.map(task => (\n <TaskListRow\n key={task.id}\n ref={scrollActiveIntoView && task.id === activeTask?.id ? scrollTaskIntoView : undefined}\n task={task}\n />\n ))}\n </ul>\n </ScrollArea>\n </CollapsibleContent>\n </Collapsible>\n </TaskListContainer>\n );\n};\n"],"names":["jsx","cn","CollapsibleTrigger","jsxs","CheckCircle2","Loader2","Circle","ListChecks","useState","Collapsible","ChevronRight","CollapsibleContent","ScrollArea"],"mappings":"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"}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ListChecks, Circle, Loader2, CheckCircle2 } from 'lucide-react';
|
|
3
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { ChevronRight, ListChecks, Circle, Loader2, CheckCircle2 } from 'lucide-react';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { C as Collapsible, a as CollapsibleContent, b as CollapsibleTrigger } from '../../collapsible-D6MHpP1g.js';
|
|
5
|
+
import { S as ScrollArea } from '../../scroll-area-DZrEuKjC.js';
|
|
4
6
|
import { c as cn } from '../../cn-BakJzhuv.js';
|
|
5
7
|
|
|
6
8
|
const TaskListContainer = ({ className, ...props }) => /* @__PURE__ */ jsx("section", { className: cn("rounded-2xl border border-border2/40 bg-surface3 px-3 py-2.5", className), ...props });
|
|
7
|
-
const TaskListHeader = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
8
|
-
|
|
9
|
+
const TaskListHeader = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
10
|
+
CollapsibleTrigger,
|
|
11
|
+
{
|
|
12
|
+
className: cn("flex w-full cursor-pointer items-center gap-2 text-left text-neutral4", className),
|
|
13
|
+
...props
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
const TaskListCount = ({ completed, total, className, ...props }) => /* @__PURE__ */ jsxs("span", { className: cn("ml-auto shrink-0 text-ui-xs text-neutral4 tabular-nums", className), ...props, children: [
|
|
9
17
|
completed,
|
|
10
18
|
"/",
|
|
11
19
|
total,
|
|
@@ -21,7 +29,7 @@ const TaskListProgress = ({ completed, total, className, ...props }) => {
|
|
|
21
29
|
"aria-valuemin": 0,
|
|
22
30
|
"aria-valuemax": total,
|
|
23
31
|
"aria-valuenow": completed,
|
|
24
|
-
className: cn("mb-2.5 h-1 w-full rounded-full bg-surface4", className),
|
|
32
|
+
className: cn("mt-2 mb-2.5 h-1 w-full rounded-full bg-surface4", className),
|
|
25
33
|
...props,
|
|
26
34
|
children: /* @__PURE__ */ jsx("div", { className: "bg-accent6 h-full rounded-full transition-all duration-300", style: { width: `${percentage}%` } })
|
|
27
35
|
}
|
|
@@ -42,38 +50,56 @@ const textClasses = {
|
|
|
42
50
|
in_progress: "font-medium text-warning1",
|
|
43
51
|
pending: "text-neutral5"
|
|
44
52
|
};
|
|
45
|
-
const
|
|
53
|
+
const taskLabel = (task) => task.status === "in_progress" ? task.activeForm : task.content;
|
|
54
|
+
const TaskListStatusIcon = ({ status, className, ...props }) => /* @__PURE__ */ jsx("span", { "aria-label": statusLabels[status], className: cn("flex pt-0.5", className), ...props, children: icons[status] });
|
|
46
55
|
const TaskListRow = ({ task, className, ...props }) => /* @__PURE__ */ jsxs("li", { className: cn("flex items-start gap-2 py-0.5", className), ...props, children: [
|
|
47
56
|
/* @__PURE__ */ jsx(TaskListStatusIcon, { status: task.status }),
|
|
48
|
-
/* @__PURE__ */ jsx("span", { className: cn("text-ui-sm leading-ui-sm", textClasses[task.status]), children: task
|
|
57
|
+
/* @__PURE__ */ jsx("span", { className: cn("text-ui-sm leading-ui-sm", textClasses[task.status]), children: taskLabel(task) })
|
|
49
58
|
] });
|
|
59
|
+
const TaskListSummary = ({ task }) => /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
60
|
+
/* @__PURE__ */ jsx(TaskListStatusIcon, { status: task.status, className: "pt-0" }),
|
|
61
|
+
/* @__PURE__ */ jsx("span", { className: cn("truncate text-ui-sm leading-ui-sm", textClasses[task.status]), children: taskLabel(task) })
|
|
62
|
+
] });
|
|
63
|
+
const TaskListTitle = ({ title }) => /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-2", children: [
|
|
64
|
+
/* @__PURE__ */ jsx(ListChecks, { className: "text-accent6 size-4 shrink-0" }),
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: "text-ui-sm leading-ui-sm text-neutral6 truncate font-medium", children: title })
|
|
66
|
+
] });
|
|
67
|
+
const scrollTaskIntoView = (node) => {
|
|
68
|
+
if (typeof node?.scrollIntoView === "function") node.scrollIntoView({ block: "nearest" });
|
|
69
|
+
};
|
|
50
70
|
const TaskList = ({
|
|
51
71
|
tasks,
|
|
52
72
|
title = "Tasks",
|
|
53
73
|
hideWhenEmpty = true,
|
|
54
74
|
hideWhenComplete = true,
|
|
55
75
|
scrollActiveIntoView = true,
|
|
76
|
+
defaultOpen = true,
|
|
56
77
|
...props
|
|
57
78
|
}) => {
|
|
58
|
-
const
|
|
59
|
-
const
|
|
79
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
80
|
+
const activeTask = tasks.find((task) => task.status === "in_progress");
|
|
81
|
+
const summaryTask = activeTask ?? tasks.find((task) => task.status === "pending");
|
|
60
82
|
const completed = tasks.filter((task) => task.status === "completed").length;
|
|
61
83
|
const total = tasks.length;
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
if (!scrollActiveIntoView || !activeTaskRef.current || typeof activeTaskRef.current.scrollIntoView !== "function")
|
|
64
|
-
return;
|
|
65
|
-
activeTaskRef.current.scrollIntoView({ block: "nearest" });
|
|
66
|
-
}, [activeTaskId, scrollActiveIntoView]);
|
|
67
84
|
if (hideWhenEmpty && total === 0 || hideWhenComplete && total > 0 && completed === total) return null;
|
|
68
|
-
return /* @__PURE__ */
|
|
85
|
+
return /* @__PURE__ */ jsx(TaskListContainer, { "aria-label": "Task list", "data-testid": "task-list", ...props, children: /* @__PURE__ */ jsxs(Collapsible, { open, onOpenChange: setOpen, children: [
|
|
69
86
|
/* @__PURE__ */ jsxs(TaskListHeader, { children: [
|
|
70
|
-
/* @__PURE__ */ jsx(
|
|
71
|
-
/* @__PURE__ */ jsx(
|
|
87
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 shrink-0" }),
|
|
88
|
+
open || !summaryTask ? /* @__PURE__ */ jsx(TaskListTitle, { title }) : /* @__PURE__ */ jsx(TaskListSummary, { task: summaryTask }),
|
|
72
89
|
/* @__PURE__ */ jsx(TaskListCount, { completed, total })
|
|
73
90
|
] }),
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
/* @__PURE__ */ jsxs(CollapsibleContent, { children: [
|
|
92
|
+
/* @__PURE__ */ jsx(TaskListProgress, { completed, total }),
|
|
93
|
+
/* @__PURE__ */ jsx(ScrollArea, { maxHeight: "8rem", viewPortClassName: "pr-1", children: /* @__PURE__ */ jsx("ul", { className: "space-y-1", children: tasks.map((task) => /* @__PURE__ */ jsx(
|
|
94
|
+
TaskListRow,
|
|
95
|
+
{
|
|
96
|
+
ref: scrollActiveIntoView && task.id === activeTask?.id ? scrollTaskIntoView : void 0,
|
|
97
|
+
task
|
|
98
|
+
},
|
|
99
|
+
task.id
|
|
100
|
+
)) }) })
|
|
101
|
+
] })
|
|
102
|
+
] }) });
|
|
77
103
|
};
|
|
78
104
|
|
|
79
105
|
export { TaskList, TaskListContainer, TaskListCount, TaskListHeader, TaskListProgress, TaskListRow, TaskListStatusIcon };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-list.es.js","sources":["../../../src/ds/components/ai/task-list/task-list.tsx"],"sourcesContent":["import type { TaskItem } from '@mastra/core/signals';\nimport { CheckCircle2, Circle, ListChecks, Loader2 } from 'lucide-react';\nimport { useEffect, useRef } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { cn } from '@/lib/utils';\n\nexport type TaskListItem = TaskItem;\n\nexport const TaskListContainer = ({ className, ...props }: ComponentProps<'section'>) => (\n <section className={cn('rounded-2xl border border-border2/40 bg-surface3 px-3 py-2.5', className)} {...props} />\n);\n\nexport const TaskListHeader = ({ className, ...props }: ComponentProps<'header'>) => (\n <header className={cn('mb-2 flex items-center gap-2', className)} {...props} />\n);\n\nexport interface TaskListCountProps extends ComponentProps<'span'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListCount = ({ completed, total, className, ...props }: TaskListCountProps) => (\n <span className={cn('ml-auto text-ui-xs text-neutral4 tabular-nums', className)} {...props}>\n {completed}/{total} completed\n </span>\n);\n\nexport interface TaskListProgressProps extends Omit<ComponentProps<'div'>, 'children'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListProgress = ({ completed, total, className, ...props }: TaskListProgressProps) => {\n const percentage = total === 0 ? 0 : (completed / total) * 100;\n return (\n <div\n role=\"progressbar\"\n aria-label=\"Task completion\"\n aria-valuemin={0}\n aria-valuemax={total}\n aria-valuenow={completed}\n className={cn('mb-2.5 h-1 w-full rounded-full bg-surface4', className)}\n {...props}\n >\n <div className=\"bg-accent6 h-full rounded-full transition-all duration-300\" style={{ width: `${percentage}%` }} />\n </div>\n );\n};\n\nconst icons: Record<TaskListItem['status'], ReactNode> = {\n completed: <CheckCircle2 className=\"text-positive1 size-3.5 shrink-0\" />,\n in_progress: <Loader2 className=\"text-warning1 size-3.5 shrink-0 motion-safe:animate-spin\" />,\n pending: <Circle className=\"text-neutral4 size-3.5 shrink-0\" />,\n};\n\nconst statusLabels: Record<TaskListItem['status'], string> = {\n completed: 'Completed',\n in_progress: 'In progress',\n pending: 'Pending',\n};\n\nconst textClasses: Record<TaskListItem['status'], string> = {\n completed: 'text-neutral4 line-through',\n in_progress: 'font-medium text-warning1',\n pending: 'text-neutral5',\n};\n\nexport interface TaskListStatusIconProps extends ComponentProps<'span'> {\n status: TaskListItem['status'];\n}\n\nexport const TaskListStatusIcon = ({ status, className, ...props }: TaskListStatusIconProps) => (\n <span aria-label={statusLabels[status]} className={cn('pt-0.5', className)} {...props}>\n {icons[status]}\n </span>\n);\n\nexport interface TaskListRowProps extends ComponentProps<'li'> {\n task: TaskListItem;\n}\n\nexport const TaskListRow = ({ task, className, ...props }: TaskListRowProps) => (\n <li className={cn('flex items-start gap-2 py-0.5', className)} {...props}>\n <TaskListStatusIcon status={task.status} />\n <span className={cn('text-ui-sm leading-ui-sm', textClasses[task.status])}>\n {task.status === 'in_progress' ? task.activeForm : task.content}\n </span>\n </li>\n);\n\nexport interface TaskListProps extends Omit<ComponentProps<typeof TaskListContainer>, 'children' | 'title'> {\n tasks: TaskListItem[];\n title?: ReactNode;\n hideWhenEmpty?: boolean;\n hideWhenComplete?: boolean;\n scrollActiveIntoView?: boolean;\n}\n\nexport const TaskList = ({\n tasks,\n title = 'Tasks',\n hideWhenEmpty = true,\n hideWhenComplete = true,\n scrollActiveIntoView = true,\n ...props\n}: TaskListProps) => {\n const activeTaskRef = useRef<HTMLLIElement | null>(null);\n const activeTaskId = tasks.find(task => task.status === 'in_progress')?.id;\n const completed = tasks.filter(task => task.status === 'completed').length;\n const total = tasks.length;\n\n useEffect(() => {\n if (!scrollActiveIntoView || !activeTaskRef.current || typeof activeTaskRef.current.scrollIntoView !== 'function')\n return;\n activeTaskRef.current.scrollIntoView({ block: 'nearest' });\n }, [activeTaskId, scrollActiveIntoView]);\n\n if ((hideWhenEmpty && total === 0) || (hideWhenComplete && total > 0 && completed === total)) return null;\n\n return (\n <TaskListContainer aria-label=\"Task list\" data-testid=\"task-list\" {...props}>\n <TaskListHeader>\n <ListChecks className=\"text-accent6 size-4 shrink-0\" />\n <h2 className=\"text-ui-sm leading-ui-sm text-neutral6 font-medium\">{title}</h2>\n <TaskListCount completed={completed} total={total} />\n </TaskListHeader>\n <TaskListProgress completed={completed} total={total} />\n <ul className=\"max-h-32 space-y-1 overflow-y-auto pr-1\">\n {tasks.map(task => (\n <TaskListRow key={task.id} ref={task.id === activeTaskId ? activeTaskRef : undefined} task={task} />\n ))}\n </ul>\n </TaskListContainer>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task-list.es.js","sources":["../../../src/ds/components/ai/task-list/task-list.tsx"],"sourcesContent":["import type { TaskItem } from '@mastra/core/signals';\nimport { CheckCircle2, ChevronRight, Circle, ListChecks, Loader2 } from 'lucide-react';\nimport { useState } from 'react';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/ds/components/Collapsible';\nimport { ScrollArea } from '@/ds/components/ScrollArea';\nimport { cn } from '@/lib/utils';\n\nexport type TaskListItem = TaskItem;\n\nexport const TaskListContainer = ({ className, ...props }: ComponentProps<'section'>) => (\n <section className={cn('rounded-2xl border border-border2/40 bg-surface3 px-3 py-2.5', className)} {...props} />\n);\n\nexport const TaskListHeader = ({ className, ...props }: ComponentProps<typeof CollapsibleTrigger>) => (\n <CollapsibleTrigger\n className={cn('flex w-full cursor-pointer items-center gap-2 text-left text-neutral4', className)}\n {...props}\n />\n);\n\nexport interface TaskListCountProps extends ComponentProps<'span'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListCount = ({ completed, total, className, ...props }: TaskListCountProps) => (\n <span className={cn('ml-auto shrink-0 text-ui-xs text-neutral4 tabular-nums', className)} {...props}>\n {completed}/{total} completed\n </span>\n);\n\nexport interface TaskListProgressProps extends Omit<ComponentProps<'div'>, 'children'> {\n completed: number;\n total: number;\n}\n\nexport const TaskListProgress = ({ completed, total, className, ...props }: TaskListProgressProps) => {\n const percentage = total === 0 ? 0 : (completed / total) * 100;\n return (\n <div\n role=\"progressbar\"\n aria-label=\"Task completion\"\n aria-valuemin={0}\n aria-valuemax={total}\n aria-valuenow={completed}\n className={cn('mt-2 mb-2.5 h-1 w-full rounded-full bg-surface4', className)}\n {...props}\n >\n <div className=\"bg-accent6 h-full rounded-full transition-all duration-300\" style={{ width: `${percentage}%` }} />\n </div>\n );\n};\n\nconst icons: Record<TaskListItem['status'], ReactNode> = {\n completed: <CheckCircle2 className=\"text-positive1 size-3.5 shrink-0\" />,\n in_progress: <Loader2 className=\"text-warning1 size-3.5 shrink-0 motion-safe:animate-spin\" />,\n pending: <Circle className=\"text-neutral4 size-3.5 shrink-0\" />,\n};\n\nconst statusLabels: Record<TaskListItem['status'], string> = {\n completed: 'Completed',\n in_progress: 'In progress',\n pending: 'Pending',\n};\n\nconst textClasses: Record<TaskListItem['status'], string> = {\n completed: 'text-neutral4 line-through',\n in_progress: 'font-medium text-warning1',\n pending: 'text-neutral5',\n};\n\nconst taskLabel = (task: TaskListItem) => (task.status === 'in_progress' ? task.activeForm : task.content);\n\nexport interface TaskListStatusIconProps extends ComponentProps<'span'> {\n status: TaskListItem['status'];\n}\n\nexport const TaskListStatusIcon = ({ status, className, ...props }: TaskListStatusIconProps) => (\n <span aria-label={statusLabels[status]} className={cn('flex pt-0.5', className)} {...props}>\n {icons[status]}\n </span>\n);\n\nexport interface TaskListRowProps extends ComponentProps<'li'> {\n task: TaskListItem;\n}\n\nexport const TaskListRow = ({ task, className, ...props }: TaskListRowProps) => (\n <li className={cn('flex items-start gap-2 py-0.5', className)} {...props}>\n <TaskListStatusIcon status={task.status} />\n <span className={cn('text-ui-sm leading-ui-sm', textClasses[task.status])}>{taskLabel(task)}</span>\n </li>\n);\n\nconst TaskListSummary = ({ task }: { task: TaskListItem }) => (\n <span className=\"flex min-w-0 flex-1 items-center gap-2\">\n <TaskListStatusIcon status={task.status} className=\"pt-0\" />\n <span className={cn('truncate text-ui-sm leading-ui-sm', textClasses[task.status])}>{taskLabel(task)}</span>\n </span>\n);\n\nconst TaskListTitle = ({ title }: { title: ReactNode }) => (\n <span className=\"flex min-w-0 flex-1 items-center gap-2\">\n <ListChecks className=\"text-accent6 size-4 shrink-0\" />\n <span className=\"text-ui-sm leading-ui-sm text-neutral6 truncate font-medium\">{title}</span>\n </span>\n);\n\nconst scrollTaskIntoView = (node: HTMLLIElement | null) => {\n if (typeof node?.scrollIntoView === 'function') node.scrollIntoView({ block: 'nearest' });\n};\n\nexport interface TaskListProps extends Omit<ComponentProps<typeof TaskListContainer>, 'children' | 'title'> {\n tasks: TaskListItem[];\n title?: ReactNode;\n hideWhenEmpty?: boolean;\n hideWhenComplete?: boolean;\n scrollActiveIntoView?: boolean;\n defaultOpen?: boolean;\n}\n\nexport const TaskList = ({\n tasks,\n title = 'Tasks',\n hideWhenEmpty = true,\n hideWhenComplete = true,\n scrollActiveIntoView = true,\n defaultOpen = true,\n ...props\n}: TaskListProps) => {\n const [open, setOpen] = useState(defaultOpen);\n const activeTask = tasks.find(task => task.status === 'in_progress');\n const summaryTask = activeTask ?? tasks.find(task => task.status === 'pending');\n const completed = tasks.filter(task => task.status === 'completed').length;\n const total = tasks.length;\n\n if ((hideWhenEmpty && total === 0) || (hideWhenComplete && total > 0 && completed === total)) return null;\n\n return (\n <TaskListContainer aria-label=\"Task list\" data-testid=\"task-list\" {...props}>\n <Collapsible open={open} onOpenChange={setOpen}>\n <TaskListHeader>\n <ChevronRight className=\"size-3.5 shrink-0\" />\n {open || !summaryTask ? <TaskListTitle title={title} /> : <TaskListSummary task={summaryTask} />}\n <TaskListCount completed={completed} total={total} />\n </TaskListHeader>\n <CollapsibleContent>\n <TaskListProgress completed={completed} total={total} />\n <ScrollArea maxHeight=\"8rem\" viewPortClassName=\"pr-1\">\n <ul className=\"space-y-1\">\n {tasks.map(task => (\n <TaskListRow\n key={task.id}\n ref={scrollActiveIntoView && task.id === activeTask?.id ? scrollTaskIntoView : undefined}\n task={task}\n />\n ))}\n </ul>\n </ScrollArea>\n </CollapsibleContent>\n </Collapsible>\n </TaskListContainer>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { TaskItem } from '@mastra/core/signals';
|
|
2
2
|
import { ComponentProps, ReactNode } from 'react';
|
|
3
|
+
import { CollapsibleTrigger } from '../../Collapsible';
|
|
3
4
|
export type TaskListItem = TaskItem;
|
|
4
5
|
export declare const TaskListContainer: ({ className, ...props }: ComponentProps<"section">) => import("react").JSX.Element;
|
|
5
|
-
export declare const TaskListHeader: ({ className, ...props }: ComponentProps<
|
|
6
|
+
export declare const TaskListHeader: ({ className, ...props }: ComponentProps<typeof CollapsibleTrigger>) => import("react").JSX.Element;
|
|
6
7
|
export interface TaskListCountProps extends ComponentProps<'span'> {
|
|
7
8
|
completed: number;
|
|
8
9
|
total: number;
|
|
@@ -27,5 +28,6 @@ export interface TaskListProps extends Omit<ComponentProps<typeof TaskListContai
|
|
|
27
28
|
hideWhenEmpty?: boolean;
|
|
28
29
|
hideWhenComplete?: boolean;
|
|
29
30
|
scrollActiveIntoView?: boolean;
|
|
31
|
+
defaultOpen?: boolean;
|
|
30
32
|
}
|
|
31
|
-
export declare const TaskList: ({ tasks, title, hideWhenEmpty, hideWhenComplete, scrollActiveIntoView, ...props }: TaskListProps) => import("react").JSX.Element | null;
|
|
33
|
+
export declare const TaskList: ({ tasks, title, hideWhenEmpty, hideWhenComplete, scrollActiveIntoView, defaultOpen, ...props }: TaskListProps) => import("react").JSX.Element | null;
|
|
@@ -5,5 +5,7 @@ export default meta;
|
|
|
5
5
|
type Story = StoryObj<typeof TaskList>;
|
|
6
6
|
export declare const MixedProgress: Story;
|
|
7
7
|
export declare const OneActiveTask: Story;
|
|
8
|
+
export declare const Collapsed: Story;
|
|
9
|
+
export declare const LongList: Story;
|
|
8
10
|
export declare const Empty: Story;
|
|
9
11
|
export declare const Completed: Story;
|
package/dist/style.css
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/playground-ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "48.0.0",
|
|
4
|
+
"version": "48.1.0-alpha.0",
|
|
5
5
|
"description": "Mastra Playground components",
|
|
6
6
|
"sideEffects": [
|
|
7
7
|
"**/*.css"
|
|
@@ -150,8 +150,8 @@
|
|
|
150
150
|
"react": ">=19.0.0",
|
|
151
151
|
"react-dom": ">=19.0.0",
|
|
152
152
|
"tailwindcss": "^4.0.0",
|
|
153
|
-
"@mastra/client-js": "^1.39.0",
|
|
154
|
-
"@mastra/react": "1.4.
|
|
153
|
+
"@mastra/client-js": "^1.39.1-alpha.0",
|
|
154
|
+
"@mastra/react": "1.4.3-alpha.0"
|
|
155
155
|
},
|
|
156
156
|
"devDependencies": {
|
|
157
157
|
"@storybook/addon-a11y": "^10.4.1",
|
|
@@ -190,10 +190,10 @@
|
|
|
190
190
|
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
191
191
|
"vitest": "4.1.10",
|
|
192
192
|
"@internal/lint": "0.0.122",
|
|
193
|
-
"@mastra/client-js": "^1.39.0",
|
|
193
|
+
"@mastra/client-js": "^1.39.1-alpha.0",
|
|
194
194
|
"@mastra/memory": "1.26.1",
|
|
195
|
-
"@mastra/core": "1.
|
|
196
|
-
"@mastra/react": "1.4.
|
|
195
|
+
"@mastra/core": "1.59.0-alpha.0",
|
|
196
|
+
"@mastra/react": "1.4.3-alpha.0"
|
|
197
197
|
},
|
|
198
198
|
"homepage": "https://mastra.ai",
|
|
199
199
|
"repository": {
|