@seed-ship/mcp-ui-solid 2.8.1 → 2.8.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ScratchpadPanel.js","sources":["../../src/components/ScratchpadPanel.tsx"],"sourcesContent":["/**\n * ScratchpadPanel — HITL shared workspace between agent and human\n * v2.7.0: Renders scratchpad sections, editable filters, preview, agent messages\n *\n * @experimental — This component may change without major bump until v2.5.0 stabilization.\n */\n\nimport { Component, Show, For, Switch, Match, createSignal } from 'solid-js'\nimport type { ScratchpadState, ScratchpadSection } from '../types/chat-bus'\n\nexport interface ScratchpadPanelProps {\n state: ScratchpadState\n /** Called when human modifies filters */\n onFilterChange?: (filters: Record<string, string | string[]>) => void\n /** Called when human clicks an action button */\n onAction?: (action: string, data?: unknown) => void\n /** Called when human edits a section */\n onSectionEdit?: (sectionId: string, content: unknown) => void\n}\n\nconst STATUS_BADGES: Record<ScratchpadState['status'], { label: string; class: string }> = {\n loading: { label: 'Loading...', class: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400' },\n ready: { label: 'Ready', class: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400' },\n waiting_human: { label: 'Your turn', class: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 animate-pulse' },\n processing: { label: 'Processing...', class: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400' },\n complete: { label: 'Complete', class: 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400' },\n}\n\n/**\n * @experimental\n */\nexport const ScratchpadPanel: Component<ScratchpadPanelProps> = (props) => {\n const badge = () => STATUS_BADGES[props.state.status] || STATUS_BADGES.loading\n\n return (\n <div class=\"w-full bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-visible\">\n {/* Header */}\n <div class=\"flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-700\">\n <div class=\"flex items-center gap-2\">\n <span class=\"text-base\">&#128221;</span>\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{props.state.title}</h3>\n </div>\n <span class={`px-2 py-0.5 text-xs font-medium rounded-full ${badge().class}`}>\n {badge().label}\n </span>\n </div>\n\n {/* Sections */}\n <div class=\"divide-y divide-gray-100 dark:divide-gray-700\">\n <For each={props.state.sections}>\n {(section) => (\n <SectionRenderer\n section={section}\n filters={props.state.filters}\n onFilterChange={props.onFilterChange}\n onAction={props.onAction}\n onSectionEdit={props.onSectionEdit}\n />\n )}\n </For>\n </div>\n\n {/* Agent messages */}\n <Show when={props.state.agentMessages.length > 0}>\n <div class=\"px-4 py-3 border-t border-gray-100 dark:border-gray-700 space-y-2\">\n <For each={props.state.agentMessages}>\n {(msg) => (\n <div class={`flex items-start gap-2 text-sm ${\n msg.type === 'warning' ? 'text-amber-600 dark:text-amber-400'\n : msg.type === 'question' ? 'text-blue-600 dark:text-blue-400'\n : 'text-gray-600 dark:text-gray-400'\n }`}>\n <span class=\"flex-shrink-0 mt-0.5\">\n {msg.type === 'warning' ? '⚠️' : msg.type === 'question' ? '💬' : 'ℹ️'}\n </span>\n <p>{msg.text}</p>\n </div>\n )}\n </For>\n </div>\n </Show>\n\n {/* Preview */}\n <Show when={props.state.preview}>\n <div class=\"px-4 py-3 border-t border-gray-100 dark:border-gray-700\">\n <div class=\"flex items-center gap-2 mb-2\">\n <span class=\"text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide\">Preview</span>\n <span class=\"px-1.5 py-0.5 text-xs font-bold bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded\">\n {props.state.preview!.count.toLocaleString()}\n </span>\n </div>\n <p class=\"text-sm text-gray-700 dark:text-gray-300\">{props.state.preview!.summary}</p>\n <Show when={props.state.preview!.rows && props.state.preview!.rows!.length > 0}>\n <div class=\"mt-2 overflow-x-auto\">\n <table class=\"min-w-full text-xs\">\n <thead>\n <tr>\n <For each={Object.keys(props.state.preview!.rows![0])}>\n {(key) => <th class=\"px-2 py-1 text-left font-medium text-gray-500 dark:text-gray-400\">{key}</th>}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={props.state.preview!.rows!.slice(0, 5)}>\n {(row) => (\n <tr class=\"border-t border-gray-100 dark:border-gray-700\">\n <For each={Object.values(row)}>\n {(val) => <td class=\"px-2 py-1 text-gray-700 dark:text-gray-300\">{String(val)}</td>}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n </Show>\n </div>\n </Show>\n </div>\n )\n}\n\n// ─── Section Renderer ────────────────────────────────────────\n\nconst SectionRenderer: Component<{\n section: ScratchpadSection\n filters: Record<string, string | string[]>\n onFilterChange?: (filters: Record<string, string | string[]>) => void\n onAction?: (action: string, data?: unknown) => void\n onSectionEdit?: (sectionId: string, content: unknown) => void\n}> = (props) => {\n return (\n <div class=\"px-4 py-3\">\n <div class=\"flex items-center gap-2 mb-2\">\n <h4 class=\"text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide\">{props.section.title}</h4>\n <Show when={props.section.editable}>\n <span class=\"text-[10px] text-blue-500 dark:text-blue-400\">(editable)</span>\n </Show>\n </div>\n\n <Switch>\n {/* Data section — key-value or compact table */}\n <Match when={props.section.type === 'data'}>\n <DataSection content={props.section.content} />\n </Match>\n\n {/* Filter section — editable chips */}\n <Match when={props.section.type === 'filter'}>\n <FilterSection\n filters={props.filters}\n onFilterChange={props.onFilterChange}\n />\n </Match>\n\n {/* Message section */}\n <Match when={props.section.type === 'message'}>\n <p class=\"text-sm text-gray-700 dark:text-gray-300\">{String(props.section.content)}</p>\n </Match>\n\n {/* Action section — buttons */}\n <Match when={props.section.type === 'action'}>\n <ActionSection content={props.section.content} onAction={props.onAction} />\n </Match>\n\n {/* Steps section */}\n <Match when={props.section.type === 'steps'}>\n <StepsSection content={props.section.content} />\n </Match>\n\n {/* Fallback */}\n <Match when={true}>\n <pre class=\"text-xs text-gray-500 dark:text-gray-400 overflow-auto\">\n {JSON.stringify(props.section.content, null, 2)}\n </pre>\n </Match>\n </Switch>\n </div>\n )\n}\n\n// ─── Sub-components ──────────────────────────────────────────\n\nconst DataSection: Component<{ content: unknown }> = (props) => {\n const entries = () => {\n if (typeof props.content !== 'object' || !props.content) return []\n return Object.entries(props.content as Record<string, unknown>)\n }\n\n return (\n <div class=\"space-y-1\">\n <For each={entries()}>\n {([key, value]) => (\n <div class=\"flex gap-2 text-sm\">\n <span class=\"text-gray-500 dark:text-gray-400 font-mono text-xs min-w-[120px]\">{key}:</span>\n <span class=\"text-gray-900 dark:text-white text-xs\">\n {Array.isArray(value) ? value.join(', ') : String(value)}\n </span>\n </div>\n )}\n </For>\n </div>\n )\n}\n\nconst FilterSection: Component<{\n filters: Record<string, string | string[]>\n onFilterChange?: (filters: Record<string, string | string[]>) => void\n}> = (props) => {\n const removeFilter = (key: string) => {\n const next = { ...props.filters }\n delete next[key]\n props.onFilterChange?.(next)\n }\n\n const entries = () => Object.entries(props.filters)\n\n return (\n <div class=\"flex flex-wrap gap-1.5\">\n <For each={entries()}>\n {([key, value]) => (\n <span class=\"inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full\">\n <span class=\"text-blue-500 dark:text-blue-400\">{key}:</span>\n {Array.isArray(value) ? value.join(', ') : String(value)}\n <button\n type=\"button\"\n onClick={() => removeFilter(key)}\n class=\"ml-0.5 hover:text-blue-900 dark:hover:text-blue-100\"\n aria-label={`Remove filter ${key}`}\n >\n &times;\n </button>\n </span>\n )}\n </For>\n </div>\n )\n}\n\nconst ActionSection: Component<{\n content: unknown\n onAction?: (action: string, data?: unknown) => void\n}> = (props) => {\n const actions = () => {\n if (Array.isArray(props.content)) return props.content as Array<{ label: string; action: string; variant?: string }>\n return []\n }\n\n return (\n <div class=\"flex flex-wrap gap-2\">\n <For each={actions()}>\n {(item) => (\n <button\n type=\"button\"\n onClick={() => props.onAction?.(item.action)}\n class={`px-3 py-1.5 text-sm font-medium rounded-lg transition-colors ${\n item.variant === 'primary'\n ? 'bg-blue-600 text-white hover:bg-blue-700'\n : item.variant === 'danger'\n ? 'bg-red-600 text-white hover:bg-red-700'\n : 'border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'\n }`}\n >\n {item.label}\n </button>\n )}\n </For>\n </div>\n )\n}\n\nconst StepsSection: Component<{ content: unknown }> = (props) => {\n const steps = () => {\n if (Array.isArray(props.content)) return props.content as Array<{ label: string; status: 'done' | 'active' | 'pending' }>\n return []\n }\n\n return (\n <div class=\"flex items-center gap-1\">\n <For each={steps()}>\n {(step, i) => (\n <>\n <Show when={i() > 0}>\n <div class={`w-6 h-px ${step.status === 'pending' ? 'bg-gray-300 dark:bg-gray-600' : 'bg-blue-400'}`} />\n </Show>\n <div class={`flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium ${\n step.status === 'done' ? 'text-green-600 dark:text-green-400'\n : step.status === 'active' ? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'\n : 'text-gray-400'\n }`}>\n {step.status === 'done' ? '✓' : step.status === 'active' ? '●' : '○'}\n {step.label}\n </div>\n </>\n )}\n </For>\n </div>\n )\n}\n"],"names":["STATUS_BADGES","loading","label","class","ready","waiting_human","processing","complete","ScratchpadPanel","props","badge","state","status","_el$","_$getNextElement","_tmpl$4","_el$2","firstChild","_el$3","_el$4","_el$5","nextSibling","_el$6","_el$7","_el$19","_el$20","_co$2","_$getNextMarker","_el$21","_el$22","_co$3","_$insert","title","_$createComponent","For","each","sections","children","section","SectionRenderer","filters","onFilterChange","onAction","onSectionEdit","Show","when","agentMessages","length","_el$8","_tmpl$","msg","_el$23","_tmpl$5","_el$24","_el$25","_c$","_$memo","type","text","_$effect","_$className","preview","_el$9","_tmpl$3","_el$0","_el$1","_el$10","_el$11","_el$17","_el$18","_co$","count","toLocaleString","summary","rows","_el$12","_tmpl$2","_el$13","_el$14","_el$15","_el$16","Object","keys","key","_el$26","_tmpl$6","slice","row","_el$27","_tmpl$7","values","val","_el$28","_tmpl$8","String","_el$29","_tmpl$10","_el$30","_el$31","_el$33","_el$34","_co$4","_el$37","_el$38","_co$5","editable","_tmpl$9","Switch","Match","DataSection","content","FilterSection","_el$35","_tmpl$0","ActionSection","StepsSection","_el$36","_tmpl$1","JSON","stringify","entries","_el$39","_tmpl$11","value","_el$40","_tmpl$12","_el$41","_el$43","_el$44","_co$6","_el$45","_c$2","Array","isArray","join","removeFilter","next","_el$46","_tmpl$13","_el$47","_tmpl$14","_el$48","_el$50","_el$51","_co$7","_el$53","_el$54","_co$8","_el$52","_c$3","$$click","_$setAttribute","_$runHydrationEvents","actions","_el$55","_tmpl$15","item","_el$56","_tmpl$16","action","variant","steps","_el$57","_tmpl$17","step","i","_el$58","_tmpl$18","_el$59","_tmpl$19","_el$60","_el$61","_co$9","_el$62","_el$63","_co$0","_c$4","_$delegateEvents"],"mappings":"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"}
1
+ {"version":3,"file":"ScratchpadPanel.js","sources":["../../src/components/ScratchpadPanel.tsx"],"sourcesContent":["/**\n * ScratchpadPanel v2 — HITL/AITL shared workspace\n * v2.8.2: Close button, collapsible, auto-close, empty state, animations\n *\n * @experimental\n */\n\nimport { Component, Show, For, Switch, Match, createSignal, createEffect, onCleanup } from 'solid-js'\nimport type { ScratchpadState, ScratchpadSection } from '../types/chat-bus'\n\nexport interface ScratchpadPanelProps {\n state: ScratchpadState\n /** Called when human modifies filters */\n onFilterChange?: (filters: Record<string, string | string[]>) => void\n /** Called when human clicks an action button */\n onAction?: (action: string, data?: unknown) => void\n /** Called when human edits a section */\n onSectionEdit?: (sectionId: string, content: unknown) => void\n /** Called when user closes the panel */\n onClose?: () => void\n /** Show close button (default: true) */\n closable?: boolean\n /** Auto-close delay in ms after status=complete (default: undefined = no auto-close) */\n autoCloseDelay?: number\n /** Allow collapsing body by clicking header (default: true) */\n collapsible?: boolean\n /** CSS max-height for scrollable body (default: \"400px\") */\n maxHeight?: string\n}\n\nconst STATUS_BADGES: Record<ScratchpadState['status'], { label: string; class: string }> = {\n loading: { label: 'Loading...', class: 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400' },\n ready: { label: 'Ready', class: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400' },\n waiting_human: { label: 'Your turn', class: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 animate-pulse' },\n processing: { label: 'Processing...', class: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400' },\n complete: { label: 'Complete', class: 'bg-green-100 text-green-600 dark:bg-green-900/30 dark:text-green-400' },\n}\n\n/**\n * @experimental\n */\nexport const ScratchpadPanel: Component<ScratchpadPanelProps> = (props) => {\n const [collapsed, setCollapsed] = createSignal(false)\n const badge = () => STATUS_BADGES[props.state.status] || STATUS_BADGES.loading\n const isClosable = () => props.closable !== false\n const isCollapsible = () => props.collapsible !== false\n\n // Auto-close on complete\n createEffect(() => {\n if (props.state.status === 'complete' && props.autoCloseDelay) {\n const timer = setTimeout(() => props.onClose?.(), props.autoCloseDelay)\n onCleanup(() => clearTimeout(timer))\n }\n })\n\n const handleHeaderClick = () => {\n if (isCollapsible()) setCollapsed(!collapsed())\n }\n\n return (\n <div\n class=\"w-full bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-visible\"\n style={{ animation: 'scratchpad-slide-down 0.2s ease-out' }}\n >\n {/* Header */}\n <div\n class={`flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-700 ${isCollapsible() ? 'cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-750' : ''}`}\n onClick={handleHeaderClick}\n >\n <div class=\"flex items-center gap-2\">\n <span class=\"text-base\">&#128221;</span>\n <h3 class=\"text-sm font-semibold text-gray-900 dark:text-white\">{props.state.title}</h3>\n <Show when={isCollapsible()}>\n <svg class={`w-3.5 h-3.5 text-gray-400 transition-transform ${collapsed() ? '-rotate-90' : ''}`} fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </Show>\n </div>\n <div class=\"flex items-center gap-2\">\n <span class={`px-2 py-0.5 text-xs font-medium rounded-full ${badge().class}`}>\n {badge().label}\n </span>\n <Show when={isClosable() && props.onClose}>\n <button\n onClick={(e) => { e.stopPropagation(); props.onClose?.() }}\n class=\"p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors\"\n aria-label=\"Close scratchpad\"\n >\n <svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n </button>\n </Show>\n </div>\n </div>\n\n {/* Body — collapsible */}\n <Show when={!collapsed()}>\n <div style={{ \"max-height\": props.maxHeight || \"400px\", \"overflow-y\": \"auto\" }}>\n {/* Sections */}\n <div class=\"divide-y divide-gray-100 dark:divide-gray-700\">\n <For each={props.state.sections}>\n {(section) => (\n <SectionRenderer\n section={section}\n filters={props.state.filters}\n onFilterChange={props.onFilterChange}\n onAction={props.onAction}\n onSectionEdit={props.onSectionEdit}\n />\n )}\n </For>\n </div>\n\n {/* Agent messages */}\n <Show when={props.state.agentMessages.length > 0}>\n <div class=\"px-4 py-3 border-t border-gray-100 dark:border-gray-700 space-y-2\">\n <For each={props.state.agentMessages}>\n {(msg) => (\n <div class={`flex items-start gap-2 text-sm rounded-lg px-3 py-2 ${\n msg.type === 'warning' ? 'bg-amber-50 dark:bg-amber-900/10 text-amber-700 dark:text-amber-400'\n : msg.type === 'question' ? 'bg-blue-50 dark:bg-blue-900/10 text-blue-700 dark:text-blue-400 border border-blue-200 dark:border-blue-800'\n : 'bg-gray-50 dark:bg-gray-700/50 text-gray-600 dark:text-gray-400'\n }`}>\n <span class=\"flex-shrink-0 mt-0.5\">\n {msg.type === 'warning' ? '⚠️' : msg.type === 'question' ? '❓' : 'ℹ️'}\n </span>\n <p>{msg.text}</p>\n </div>\n )}\n </For>\n </div>\n </Show>\n\n {/* Preview */}\n <Show when={props.state.preview}>\n <div class=\"px-4 py-3 border-t border-gray-100 dark:border-gray-700\">\n <Show when={props.state.preview!.count === 0} fallback={\n <>\n <div class=\"flex items-center gap-2 mb-2\">\n <span class=\"text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide\">Preview</span>\n <span class=\"px-1.5 py-0.5 text-xs font-bold bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded\">\n {props.state.preview!.count.toLocaleString()}\n </span>\n </div>\n <p class=\"text-sm text-gray-700 dark:text-gray-300\">{props.state.preview!.summary}</p>\n <Show when={props.state.preview!.rows && props.state.preview!.rows!.length > 0}>\n <div class=\"mt-2 overflow-x-auto\">\n <table class=\"min-w-full text-xs\">\n <thead>\n <tr>\n <For each={Object.keys(props.state.preview!.rows![0])}>\n {(key) => <th class=\"px-2 py-1 text-left font-medium text-gray-500 dark:text-gray-400\">{key}</th>}\n </For>\n </tr>\n </thead>\n <tbody>\n <For each={props.state.preview!.rows!.slice(0, 5)}>\n {(row) => (\n <tr class=\"border-t border-gray-100 dark:border-gray-700\">\n <For each={Object.values(row)}>\n {(val) => <td class=\"px-2 py-1 text-gray-700 dark:text-gray-300\">{String(val)}</td>}\n </For>\n </tr>\n )}\n </For>\n </tbody>\n </table>\n </div>\n </Show>\n </>\n }>\n {/* Empty state */}\n <div class=\"flex flex-col items-center gap-2 py-4 text-center\">\n <span class=\"text-2xl\">&#128269;</span>\n <p class=\"text-sm text-gray-500 dark:text-gray-400\">No results for these filters</p>\n <Show when={props.onFilterChange}>\n <button\n type=\"button\"\n onClick={() => props.onAction?.('refine_filters')}\n class=\"px-3 py-1.5 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors\"\n >\n Modify filters\n </button>\n </Show>\n </div>\n </Show>\n </div>\n </Show>\n </div>\n </Show>\n\n <style>{`\n @keyframes scratchpad-slide-down {\n from { opacity: 0; transform: translateY(-8px); }\n to { opacity: 1; transform: translateY(0); }\n }\n `}</style>\n </div>\n )\n}\n\n// ─── Section Renderer ────────────────────────────────────────\n\nconst SectionRenderer: Component<{\n section: ScratchpadSection\n filters: Record<string, string | string[]>\n onFilterChange?: (filters: Record<string, string | string[]>) => void\n onAction?: (action: string, data?: unknown) => void\n onSectionEdit?: (sectionId: string, content: unknown) => void\n}> = (props) => {\n return (\n <div class=\"px-4 py-3\">\n <h4 class=\"text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide mb-2\">{props.section.title}</h4>\n\n <Switch>\n <Match when={props.section.type === 'data'}>\n <DataSection content={props.section.content} />\n </Match>\n <Match when={props.section.type === 'filter'}>\n <FilterSection filters={props.filters} onFilterChange={props.onFilterChange} />\n </Match>\n <Match when={props.section.type === 'message'}>\n <p class=\"text-sm text-gray-700 dark:text-gray-300\">{String(props.section.content)}</p>\n </Match>\n <Match when={props.section.type === 'action'}>\n <ActionSection content={props.section.content} onAction={props.onAction} />\n </Match>\n <Match when={props.section.type === 'steps'}>\n <StepsSection content={props.section.content} />\n </Match>\n <Match when={true}>\n <pre class=\"text-xs text-gray-500 dark:text-gray-400 overflow-auto\">\n {JSON.stringify(props.section.content, null, 2)}\n </pre>\n </Match>\n </Switch>\n </div>\n )\n}\n\n// ─── Sub-components ──────────────────────────────────────────\n\nconst DataSection: Component<{ content: unknown }> = (props) => {\n const entries = () => {\n if (typeof props.content !== 'object' || !props.content) return []\n return Object.entries(props.content as Record<string, unknown>)\n }\n\n return (\n <div class=\"space-y-1\">\n <For each={entries()}>\n {([key, value]) => (\n <div class=\"flex gap-2 text-sm\">\n <span class=\"text-gray-500 dark:text-gray-400 font-mono text-xs min-w-[120px]\">{key}:</span>\n <span class=\"text-gray-900 dark:text-white text-xs\">\n {Array.isArray(value) ? value.join(', ') : String(value)}\n </span>\n </div>\n )}\n </For>\n </div>\n )\n}\n\nconst FilterSection: Component<{\n filters: Record<string, string | string[]>\n onFilterChange?: (filters: Record<string, string | string[]>) => void\n}> = (props) => {\n const removeFilter = (key: string) => {\n const next = { ...props.filters }\n delete next[key]\n props.onFilterChange?.(next)\n }\n\n const entries = () => Object.entries(props.filters)\n\n return (\n <div class=\"flex flex-wrap gap-1.5\">\n <For each={entries()}>\n {([key, value]) => (\n <span class=\"inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full\">\n <span class=\"text-blue-500 dark:text-blue-400\">{key}:</span>\n {Array.isArray(value) ? value.join(', ') : String(value)}\n <Show when={props.onFilterChange}>\n <button\n type=\"button\"\n onClick={() => removeFilter(key)}\n class=\"ml-0.5 hover:text-blue-900 dark:hover:text-blue-100 transition-colors\"\n aria-label={`Remove filter ${key}`}\n >\n &times;\n </button>\n </Show>\n </span>\n )}\n </For>\n <Show when={entries().length === 0}>\n <p class=\"text-xs text-gray-400 italic\">No filters applied</p>\n </Show>\n </div>\n )\n}\n\nconst ActionSection: Component<{\n content: unknown\n onAction?: (action: string, data?: unknown) => void\n}> = (props) => {\n const actions = () => {\n if (Array.isArray(props.content)) return props.content as Array<{ label: string; value?: string; action?: string; variant?: string; icon?: string }>\n return []\n }\n\n return (\n <div class=\"flex flex-wrap gap-2\">\n <For each={actions()}>\n {(item) => (\n <button\n type=\"button\"\n onClick={() => props.onAction?.(item.value || item.action || item.label, item)}\n class={`px-3 py-1.5 text-sm font-medium rounded-lg transition-colors ${\n item.variant === 'primary'\n ? 'bg-blue-600 text-white hover:bg-blue-700'\n : item.variant === 'danger'\n ? 'bg-red-600 text-white hover:bg-red-700'\n : 'border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'\n }`}\n >\n <Show when={item.icon}><span class=\"mr-1\">{item.icon}</span></Show>\n {item.label}\n </button>\n )}\n </For>\n </div>\n )\n}\n\nconst StepsSection: Component<{ content: unknown }> = (props) => {\n const steps = () => {\n if (Array.isArray(props.content)) return props.content as Array<{ label: string; status: 'done' | 'active' | 'pending' }>\n return []\n }\n\n return (\n <div class=\"flex items-center gap-1\">\n <For each={steps()}>\n {(step, i) => (\n <>\n <Show when={i() > 0}>\n <div class={`w-6 h-px ${step.status === 'pending' ? 'bg-gray-300 dark:bg-gray-600' : 'bg-blue-400'}`} />\n </Show>\n <div class={`flex items-center gap-1.5 px-2 py-1 rounded text-xs font-medium ${\n step.status === 'done' ? 'text-green-600 dark:text-green-400'\n : step.status === 'active' ? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'\n : 'text-gray-400'\n }`}>\n {step.status === 'done' ? '✓' : step.status === 'active' ? '●' : '○'}\n {step.label}\n </div>\n </>\n )}\n </For>\n </div>\n )\n}\n"],"names":["STATUS_BADGES","loading","label","class","ready","waiting_human","processing","complete","ScratchpadPanel","props","collapsed","setCollapsed","createSignal","badge","state","status","isClosable","closable","isCollapsible","collapsible","createEffect","autoCloseDelay","timer","setTimeout","onClose","onCleanup","clearTimeout","handleHeaderClick","_el$","_$getNextElement","_tmpl$8","_el$2","firstChild","_el$3","_el$4","_el$5","nextSibling","_el$7","_el$8","_co$","_$getNextMarker","_el$9","_el$0","_el$10","_el$11","_co$2","_el$27","_el$28","_co$6","$$click","_$insert","title","_$createComponent","Show","when","children","_el$6","_tmpl$","_$effect","_$setAttribute","_$memo","_el$1","_tmpl$2","e","stopPropagation","_$runHydrationEvents","_el$12","_tmpl$7","_el$13","_el$22","_el$23","_co$4","_el$24","_el$25","_co$5","For","each","sections","section","SectionRenderer","filters","onFilterChange","onAction","onSectionEdit","agentMessages","length","_el$14","_tmpl$3","msg","_el$29","_tmpl$9","_el$30","_el$31","_c$","type","text","_$className","preview","_el$15","_tmpl$6","count","fallback","_el$32","_tmpl$0","_el$33","_el$34","toLocaleString","_el$35","_tmpl$1","summary","rows","_el$36","_tmpl$10","_el$37","_el$38","_el$39","_el$40","Object","keys","key","_el$41","_tmpl$11","slice","row","_el$42","_tmpl$12","values","val","_el$43","_tmpl$13","String","_el$16","_tmpl$5","_el$17","_el$18","_el$20","_el$21","_co$3","_el$19","_tmpl$4","_$p","_$setStyleProperty","maxHeight","_p$","_v$","_v$2","t","undefined","_el$44","_tmpl$15","_el$45","_el$48","_el$49","_co$7","Switch","Match","DataSection","content","FilterSection","_el$46","ActionSection","StepsSection","_el$47","_tmpl$14","JSON","stringify","entries","_el$50","_tmpl$16","value","_el$51","_tmpl$17","_el$52","_el$54","_el$55","_co$8","_el$56","_c$2","Array","isArray","join","removeFilter","next","_el$57","_tmpl$19","_el$59","_el$60","_co$9","_el$61","_el$62","_co$0","_el$63","_tmpl$21","_el$64","_el$66","_el$67","_co$1","_el$69","_el$70","_co$10","_el$71","_el$72","_co$11","_c$3","_el$68","_tmpl$20","_tmpl$18","actions","_el$73","_tmpl$22","item","_el$74","_tmpl$24","_el$76","_el$77","_co$12","_el$78","_el$79","_co$13","action","icon","_el$75","_tmpl$23","variant","steps","_el$80","_tmpl$25","step","i","_el$81","_tmpl$26","_el$82","_tmpl$27","_el$83","_el$84","_co$14","_el$85","_el$86","_co$15","_c$4","_$delegateEvents"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seed-ship/mcp-ui-solid",
3
- "version": "2.8.1",
3
+ "version": "2.8.3",
4
4
  "description": "SolidJS components for rendering MCP-generated UI resources",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -1,11 +1,11 @@
1
1
  /**
2
- * ScratchpadPanel — HITL shared workspace between agent and human
3
- * v2.7.0: Renders scratchpad sections, editable filters, preview, agent messages
2
+ * ScratchpadPanel v2 — HITL/AITL shared workspace
3
+ * v2.8.2: Close button, collapsible, auto-close, empty state, animations
4
4
  *
5
- * @experimental — This component may change without major bump until v2.5.0 stabilization.
5
+ * @experimental
6
6
  */
7
7
 
8
- import { Component, Show, For, Switch, Match, createSignal } from 'solid-js'
8
+ import { Component, Show, For, Switch, Match, createSignal, createEffect, onCleanup } from 'solid-js'
9
9
  import type { ScratchpadState, ScratchpadSection } from '../types/chat-bus'
10
10
 
11
11
  export interface ScratchpadPanelProps {
@@ -16,6 +16,16 @@ export interface ScratchpadPanelProps {
16
16
  onAction?: (action: string, data?: unknown) => void
17
17
  /** Called when human edits a section */
18
18
  onSectionEdit?: (sectionId: string, content: unknown) => void
19
+ /** Called when user closes the panel */
20
+ onClose?: () => void
21
+ /** Show close button (default: true) */
22
+ closable?: boolean
23
+ /** Auto-close delay in ms after status=complete (default: undefined = no auto-close) */
24
+ autoCloseDelay?: number
25
+ /** Allow collapsing body by clicking header (default: true) */
26
+ collapsible?: boolean
27
+ /** CSS max-height for scrollable body (default: "400px") */
28
+ maxHeight?: string
19
29
  }
20
30
 
21
31
  const STATUS_BADGES: Record<ScratchpadState['status'], { label: string; class: string }> = {
@@ -23,99 +33,169 @@ const STATUS_BADGES: Record<ScratchpadState['status'], { label: string; class: s
23
33
  ready: { label: 'Ready', class: 'bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400' },
24
34
  waiting_human: { label: 'Your turn', class: 'bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 animate-pulse' },
25
35
  processing: { label: 'Processing...', class: 'bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400' },
26
- complete: { label: 'Complete', class: 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400' },
36
+ complete: { label: 'Complete', class: 'bg-green-100 text-green-600 dark:bg-green-900/30 dark:text-green-400' },
27
37
  }
28
38
 
29
39
  /**
30
40
  * @experimental
31
41
  */
32
42
  export const ScratchpadPanel: Component<ScratchpadPanelProps> = (props) => {
43
+ const [collapsed, setCollapsed] = createSignal(false)
33
44
  const badge = () => STATUS_BADGES[props.state.status] || STATUS_BADGES.loading
45
+ const isClosable = () => props.closable !== false
46
+ const isCollapsible = () => props.collapsible !== false
47
+
48
+ // Auto-close on complete
49
+ createEffect(() => {
50
+ if (props.state.status === 'complete' && props.autoCloseDelay) {
51
+ const timer = setTimeout(() => props.onClose?.(), props.autoCloseDelay)
52
+ onCleanup(() => clearTimeout(timer))
53
+ }
54
+ })
55
+
56
+ const handleHeaderClick = () => {
57
+ if (isCollapsible()) setCollapsed(!collapsed())
58
+ }
34
59
 
35
60
  return (
36
- <div class="w-full bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-visible">
61
+ <div
62
+ class="w-full bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 shadow-lg overflow-visible"
63
+ style={{ animation: 'scratchpad-slide-down 0.2s ease-out' }}
64
+ >
37
65
  {/* Header */}
38
- <div class="flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-700">
66
+ <div
67
+ class={`flex items-center justify-between px-4 py-3 border-b border-gray-100 dark:border-gray-700 ${isCollapsible() ? 'cursor-pointer select-none hover:bg-gray-50 dark:hover:bg-gray-750' : ''}`}
68
+ onClick={handleHeaderClick}
69
+ >
39
70
  <div class="flex items-center gap-2">
40
71
  <span class="text-base">&#128221;</span>
41
72
  <h3 class="text-sm font-semibold text-gray-900 dark:text-white">{props.state.title}</h3>
73
+ <Show when={isCollapsible()}>
74
+ <svg class={`w-3.5 h-3.5 text-gray-400 transition-transform ${collapsed() ? '-rotate-90' : ''}`} fill="none" viewBox="0 0 24 24" stroke="currentColor">
75
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
76
+ </svg>
77
+ </Show>
78
+ </div>
79
+ <div class="flex items-center gap-2">
80
+ <span class={`px-2 py-0.5 text-xs font-medium rounded-full ${badge().class}`}>
81
+ {badge().label}
82
+ </span>
83
+ <Show when={isClosable() && props.onClose}>
84
+ <button
85
+ onClick={(e) => { e.stopPropagation(); props.onClose?.() }}
86
+ class="p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
87
+ aria-label="Close scratchpad"
88
+ >
89
+ <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
90
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
91
+ </svg>
92
+ </button>
93
+ </Show>
42
94
  </div>
43
- <span class={`px-2 py-0.5 text-xs font-medium rounded-full ${badge().class}`}>
44
- {badge().label}
45
- </span>
46
95
  </div>
47
96
 
48
- {/* Sections */}
49
- <div class="divide-y divide-gray-100 dark:divide-gray-700">
50
- <For each={props.state.sections}>
51
- {(section) => (
52
- <SectionRenderer
53
- section={section}
54
- filters={props.state.filters}
55
- onFilterChange={props.onFilterChange}
56
- onAction={props.onAction}
57
- onSectionEdit={props.onSectionEdit}
58
- />
59
- )}
60
- </For>
61
- </div>
97
+ {/* Body — collapsible */}
98
+ <Show when={!collapsed()}>
99
+ <div style={{ "max-height": props.maxHeight || "400px", "overflow-y": "auto" }}>
100
+ {/* Sections */}
101
+ <div class="divide-y divide-gray-100 dark:divide-gray-700">
102
+ <For each={props.state.sections}>
103
+ {(section) => (
104
+ <SectionRenderer
105
+ section={section}
106
+ filters={props.state.filters}
107
+ onFilterChange={props.onFilterChange}
108
+ onAction={props.onAction}
109
+ onSectionEdit={props.onSectionEdit}
110
+ />
111
+ )}
112
+ </For>
113
+ </div>
62
114
 
63
- {/* Agent messages */}
64
- <Show when={props.state.agentMessages.length > 0}>
65
- <div class="px-4 py-3 border-t border-gray-100 dark:border-gray-700 space-y-2">
66
- <For each={props.state.agentMessages}>
67
- {(msg) => (
68
- <div class={`flex items-start gap-2 text-sm ${
69
- msg.type === 'warning' ? 'text-amber-600 dark:text-amber-400'
70
- : msg.type === 'question' ? 'text-blue-600 dark:text-blue-400'
71
- : 'text-gray-600 dark:text-gray-400'
72
- }`}>
73
- <span class="flex-shrink-0 mt-0.5">
74
- {msg.type === 'warning' ? '⚠️' : msg.type === 'question' ? '💬' : 'ℹ️'}
75
- </span>
76
- <p>{msg.text}</p>
77
- </div>
78
- )}
79
- </For>
80
- </div>
81
- </Show>
115
+ {/* Agent messages */}
116
+ <Show when={props.state.agentMessages.length > 0}>
117
+ <div class="px-4 py-3 border-t border-gray-100 dark:border-gray-700 space-y-2">
118
+ <For each={props.state.agentMessages}>
119
+ {(msg) => (
120
+ <div class={`flex items-start gap-2 text-sm rounded-lg px-3 py-2 ${
121
+ msg.type === 'warning' ? 'bg-amber-50 dark:bg-amber-900/10 text-amber-700 dark:text-amber-400'
122
+ : msg.type === 'question' ? 'bg-blue-50 dark:bg-blue-900/10 text-blue-700 dark:text-blue-400 border border-blue-200 dark:border-blue-800'
123
+ : 'bg-gray-50 dark:bg-gray-700/50 text-gray-600 dark:text-gray-400'
124
+ }`}>
125
+ <span class="flex-shrink-0 mt-0.5">
126
+ {msg.type === 'warning' ? '⚠️' : msg.type === 'question' ? '' : 'ℹ️'}
127
+ </span>
128
+ <p>{msg.text}</p>
129
+ </div>
130
+ )}
131
+ </For>
132
+ </div>
133
+ </Show>
82
134
 
83
- {/* Preview */}
84
- <Show when={props.state.preview}>
85
- <div class="px-4 py-3 border-t border-gray-100 dark:border-gray-700">
86
- <div class="flex items-center gap-2 mb-2">
87
- <span class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide">Preview</span>
88
- <span class="px-1.5 py-0.5 text-xs font-bold bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded">
89
- {props.state.preview!.count.toLocaleString()}
90
- </span>
91
- </div>
92
- <p class="text-sm text-gray-700 dark:text-gray-300">{props.state.preview!.summary}</p>
93
- <Show when={props.state.preview!.rows && props.state.preview!.rows!.length > 0}>
94
- <div class="mt-2 overflow-x-auto">
95
- <table class="min-w-full text-xs">
96
- <thead>
97
- <tr>
98
- <For each={Object.keys(props.state.preview!.rows![0])}>
99
- {(key) => <th class="px-2 py-1 text-left font-medium text-gray-500 dark:text-gray-400">{key}</th>}
100
- </For>
101
- </tr>
102
- </thead>
103
- <tbody>
104
- <For each={props.state.preview!.rows!.slice(0, 5)}>
105
- {(row) => (
106
- <tr class="border-t border-gray-100 dark:border-gray-700">
107
- <For each={Object.values(row)}>
108
- {(val) => <td class="px-2 py-1 text-gray-700 dark:text-gray-300">{String(val)}</td>}
109
- </For>
110
- </tr>
111
- )}
112
- </For>
113
- </tbody>
114
- </table>
135
+ {/* Preview */}
136
+ <Show when={props.state.preview}>
137
+ <div class="px-4 py-3 border-t border-gray-100 dark:border-gray-700">
138
+ <Show when={props.state.preview!.count === 0} fallback={
139
+ <>
140
+ <div class="flex items-center gap-2 mb-2">
141
+ <span class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide">Preview</span>
142
+ <span class="px-1.5 py-0.5 text-xs font-bold bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded">
143
+ {props.state.preview!.count.toLocaleString()}
144
+ </span>
145
+ </div>
146
+ <p class="text-sm text-gray-700 dark:text-gray-300">{props.state.preview!.summary}</p>
147
+ <Show when={props.state.preview!.rows && props.state.preview!.rows!.length > 0}>
148
+ <div class="mt-2 overflow-x-auto">
149
+ <table class="min-w-full text-xs">
150
+ <thead>
151
+ <tr>
152
+ <For each={Object.keys(props.state.preview!.rows![0])}>
153
+ {(key) => <th class="px-2 py-1 text-left font-medium text-gray-500 dark:text-gray-400">{key}</th>}
154
+ </For>
155
+ </tr>
156
+ </thead>
157
+ <tbody>
158
+ <For each={props.state.preview!.rows!.slice(0, 5)}>
159
+ {(row) => (
160
+ <tr class="border-t border-gray-100 dark:border-gray-700">
161
+ <For each={Object.values(row)}>
162
+ {(val) => <td class="px-2 py-1 text-gray-700 dark:text-gray-300">{String(val)}</td>}
163
+ </For>
164
+ </tr>
165
+ )}
166
+ </For>
167
+ </tbody>
168
+ </table>
169
+ </div>
170
+ </Show>
171
+ </>
172
+ }>
173
+ {/* Empty state */}
174
+ <div class="flex flex-col items-center gap-2 py-4 text-center">
175
+ <span class="text-2xl">&#128269;</span>
176
+ <p class="text-sm text-gray-500 dark:text-gray-400">No results for these filters</p>
177
+ <Show when={props.onFilterChange}>
178
+ <button
179
+ type="button"
180
+ onClick={() => props.onAction?.('refine_filters')}
181
+ class="px-3 py-1.5 text-xs font-medium text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 rounded-lg transition-colors"
182
+ >
183
+ Modify filters
184
+ </button>
185
+ </Show>
186
+ </div>
187
+ </Show>
115
188
  </div>
116
189
  </Show>
117
190
  </div>
118
191
  </Show>
192
+
193
+ <style>{`
194
+ @keyframes scratchpad-slide-down {
195
+ from { opacity: 0; transform: translateY(-8px); }
196
+ to { opacity: 1; transform: translateY(0); }
197
+ }
198
+ `}</style>
119
199
  </div>
120
200
  )
121
201
  }
@@ -131,43 +211,24 @@ const SectionRenderer: Component<{
131
211
  }> = (props) => {
132
212
  return (
133
213
  <div class="px-4 py-3">
134
- <div class="flex items-center gap-2 mb-2">
135
- <h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide">{props.section.title}</h4>
136
- <Show when={props.section.editable}>
137
- <span class="text-[10px] text-blue-500 dark:text-blue-400">(editable)</span>
138
- </Show>
139
- </div>
214
+ <h4 class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide mb-2">{props.section.title}</h4>
140
215
 
141
216
  <Switch>
142
- {/* Data section — key-value or compact table */}
143
217
  <Match when={props.section.type === 'data'}>
144
218
  <DataSection content={props.section.content} />
145
219
  </Match>
146
-
147
- {/* Filter section — editable chips */}
148
220
  <Match when={props.section.type === 'filter'}>
149
- <FilterSection
150
- filters={props.filters}
151
- onFilterChange={props.onFilterChange}
152
- />
221
+ <FilterSection filters={props.filters} onFilterChange={props.onFilterChange} />
153
222
  </Match>
154
-
155
- {/* Message section */}
156
223
  <Match when={props.section.type === 'message'}>
157
224
  <p class="text-sm text-gray-700 dark:text-gray-300">{String(props.section.content)}</p>
158
225
  </Match>
159
-
160
- {/* Action section — buttons */}
161
226
  <Match when={props.section.type === 'action'}>
162
227
  <ActionSection content={props.section.content} onAction={props.onAction} />
163
228
  </Match>
164
-
165
- {/* Steps section */}
166
229
  <Match when={props.section.type === 'steps'}>
167
230
  <StepsSection content={props.section.content} />
168
231
  </Match>
169
-
170
- {/* Fallback */}
171
232
  <Match when={true}>
172
233
  <pre class="text-xs text-gray-500 dark:text-gray-400 overflow-auto">
173
234
  {JSON.stringify(props.section.content, null, 2)}
@@ -221,17 +282,22 @@ const FilterSection: Component<{
221
282
  <span class="inline-flex items-center gap-1 px-2.5 py-1 text-xs font-medium bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 rounded-full">
222
283
  <span class="text-blue-500 dark:text-blue-400">{key}:</span>
223
284
  {Array.isArray(value) ? value.join(', ') : String(value)}
224
- <button
225
- type="button"
226
- onClick={() => removeFilter(key)}
227
- class="ml-0.5 hover:text-blue-900 dark:hover:text-blue-100"
228
- aria-label={`Remove filter ${key}`}
229
- >
230
- &times;
231
- </button>
285
+ <Show when={props.onFilterChange}>
286
+ <button
287
+ type="button"
288
+ onClick={() => removeFilter(key)}
289
+ class="ml-0.5 hover:text-blue-900 dark:hover:text-blue-100 transition-colors"
290
+ aria-label={`Remove filter ${key}`}
291
+ >
292
+ &times;
293
+ </button>
294
+ </Show>
232
295
  </span>
233
296
  )}
234
297
  </For>
298
+ <Show when={entries().length === 0}>
299
+ <p class="text-xs text-gray-400 italic">No filters applied</p>
300
+ </Show>
235
301
  </div>
236
302
  )
237
303
  }
@@ -241,7 +307,7 @@ const ActionSection: Component<{
241
307
  onAction?: (action: string, data?: unknown) => void
242
308
  }> = (props) => {
243
309
  const actions = () => {
244
- if (Array.isArray(props.content)) return props.content as Array<{ label: string; action: string; variant?: string }>
310
+ if (Array.isArray(props.content)) return props.content as Array<{ label: string; value?: string; action?: string; variant?: string; icon?: string }>
245
311
  return []
246
312
  }
247
313
 
@@ -251,7 +317,7 @@ const ActionSection: Component<{
251
317
  {(item) => (
252
318
  <button
253
319
  type="button"
254
- onClick={() => props.onAction?.(item.action)}
320
+ onClick={() => props.onAction?.(item.value || item.action || item.label, item)}
255
321
  class={`px-3 py-1.5 text-sm font-medium rounded-lg transition-colors ${
256
322
  item.variant === 'primary'
257
323
  ? 'bg-blue-600 text-white hover:bg-blue-700'
@@ -260,6 +326,7 @@ const ActionSection: Component<{
260
326
  : 'border border-gray-200 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700'
261
327
  }`}
262
328
  >
329
+ <Show when={item.icon}><span class="mr-1">{item.icon}</span></Show>
263
330
  {item.label}
264
331
  </button>
265
332
  )}