mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 19:11:03 +08:00
Merge pull request #11487 from Kilo-Org/feat/vscode-tool-call-animations
feat(vscode): animate tool call previews
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"kilo-code": patch
|
||||
---
|
||||
|
||||
Animate tool-call and reasoning details when expanding and collapsing.
|
||||
@@ -129,19 +129,62 @@ html[data-theme="kilo-vscode"] [data-component="tool-trigger"] {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tool-card-down {
|
||||
from {
|
||||
grid-template-rows: 0fr;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
grid-template-rows: 1fr;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tool-card-up {
|
||||
from {
|
||||
grid-template-rows: 1fr;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
grid-template-rows: 0fr;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Card styling for tool calls in the VS Code sidebar theme */
|
||||
html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-type="tool"] {
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
overflow: visible;
|
||||
|
||||
/* Header trigger — add bottom border when the collapsible is open */
|
||||
[data-component="collapsible"].tool-collapsible {
|
||||
gap: 0;
|
||||
border-radius: 0;
|
||||
|
||||
&:has([data-slot="collapsible-trigger"][aria-expanded="true"]) {
|
||||
gap: 6px;
|
||||
> [data-slot="collapsible-content"] {
|
||||
display: grid;
|
||||
overflow: visible;
|
||||
clip-path: inset(0 -6px);
|
||||
|
||||
> * {
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> [data-slot="collapsible-content"][data-expanded] {
|
||||
animation: tool-card-down 220ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
|
||||
> [data-slot="collapsible-content"][data-closed] {
|
||||
animation: tool-card-up 160ms cubic-bezier(0.77, 0, 0.175, 1);
|
||||
}
|
||||
|
||||
[data-slot="basic-tool-details"]::before {
|
||||
display: block;
|
||||
height: 6px;
|
||||
content: "";
|
||||
}
|
||||
|
||||
[data-slot="collapsible-trigger"] {
|
||||
@@ -409,3 +452,12 @@ html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html[data-theme="kilo-vscode"] [data-component="tool-part-wrapper"][data-part-type="tool"] {
|
||||
[data-component="collapsible"].tool-collapsible > [data-slot="collapsible-content"][data-expanded],
|
||||
[data-component="collapsible"].tool-collapsible > [data-slot="collapsible-content"][data-closed] {
|
||||
animation-duration: 0.01ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,16 @@ export function initialOpen(props: OpenProps) {
|
||||
export function BasicTool(props: BasicToolProps) {
|
||||
const key = () => toolOpenKey(props)
|
||||
const initial = () => initialOpen(props)
|
||||
const change = (open: boolean) => {
|
||||
writeToolOpen(key(), open)
|
||||
props.onOpenChange?.(open)
|
||||
}
|
||||
if (!("children" in props)) {
|
||||
return <Base {...props} defaultOpen={initial()} retainDetails={props.defer} onOpenChange={change} />
|
||||
}
|
||||
return (
|
||||
<Base
|
||||
{...props}
|
||||
defaultOpen={initial()}
|
||||
onOpenChange={(open) => {
|
||||
writeToolOpen(key(), open)
|
||||
props.onOpenChange?.(open)
|
||||
}}
|
||||
/>
|
||||
<Base {...props} defaultOpen={initial()} retainDetails={props.defer} onOpenChange={change}>
|
||||
<div data-slot="basic-tool-details">{props.children}</div>
|
||||
</Base>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -477,6 +477,30 @@ html[data-theme="kilo-vscode"] [data-component="todos"] {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
@keyframes reasoning-card-down {
|
||||
from {
|
||||
grid-template-rows: 0fr;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
grid-template-rows: 1fr;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes reasoning-card-up {
|
||||
from {
|
||||
grid-template-rows: 1fr;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
grid-template-rows: 0fr;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reasoning block: visually distinct from normal agent output.
|
||||
Reasoning stays open unless the user explicitly collapses it. */
|
||||
[data-component="reasoning-part"] {
|
||||
@@ -550,22 +574,21 @@ html[data-theme="kilo-vscode"] [data-component="todos"] {
|
||||
}
|
||||
}
|
||||
|
||||
/* Collapse/expand animation via Kobalte's CSS variable.
|
||||
Uses grid trick: the outer wrapper transitions grid-template-rows
|
||||
between 0fr (collapsed) and 1fr (expanded) so the content smoothly
|
||||
collapses without needing to know the pixel height up front. */
|
||||
[data-slot="collapsible-content"] {
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows 250ms ease-out;
|
||||
overflow: hidden;
|
||||
|
||||
> * {
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&[data-expanded] {
|
||||
grid-template-rows: 1fr;
|
||||
animation: reasoning-card-down 220ms cubic-bezier(0.23, 1, 0.32, 1);
|
||||
}
|
||||
|
||||
&[data-closed] {
|
||||
animation: reasoning-card-up 160ms cubic-bezier(0.77, 0, 0.175, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,10 +621,6 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
|
||||
[data-component="collapsible"].tool-collapsible {
|
||||
gap: 0;
|
||||
border-radius: 0;
|
||||
|
||||
&:has([data-slot="collapsible-trigger"][aria-expanded="true"]) {
|
||||
gap: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
[data-slot="collapsible-trigger"] {
|
||||
@@ -667,6 +686,12 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
|
||||
width: calc(100% + 12px);
|
||||
}
|
||||
|
||||
[data-slot="reasoning-details"]::before {
|
||||
display: block;
|
||||
height: 6px;
|
||||
content: "";
|
||||
}
|
||||
|
||||
[data-slot="reasoning-content"] {
|
||||
padding: 8px 12px 10px;
|
||||
border: 0;
|
||||
@@ -712,3 +737,10 @@ html[data-theme="kilo-vscode"] [data-component="reasoning-part"] {
|
||||
line-height: var(--line-height-large);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-component="reasoning-part"] [data-slot="collapsible-content"][data-expanded],
|
||||
[data-component="reasoning-part"] [data-slot="collapsible-content"][data-closed] {
|
||||
animation-duration: 0.01ms;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1591,8 +1591,10 @@ PART_MAPPING["reasoning"] = function ReasoningPartDisplay(props: MessagePartProp
|
||||
<Collapsible.Arrow />
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
<div data-slot="reasoning-content" ref={ref} onScroll={onScroll} onWheel={onWheel}>
|
||||
<Markdown text={view().body} cacheKey={id} streaming={!done()} />
|
||||
<div data-slot="reasoning-details">
|
||||
<div data-slot="reasoning-content" ref={ref} onScroll={onScroll} onWheel={onWheel}>
|
||||
<Markdown text={view().body} cacheKey={id} streaming={!done()} />
|
||||
</div>
|
||||
</div>
|
||||
</Collapsible.Content>
|
||||
</Collapsible>
|
||||
|
||||
@@ -33,6 +33,7 @@ export interface BasicToolProps {
|
||||
onOpenChange?: (open: boolean) => void
|
||||
forceOpen?: boolean
|
||||
defer?: boolean
|
||||
retainDetails?: boolean // kilocode_change
|
||||
hasDetails?: boolean // kilocode_change
|
||||
locked?: boolean
|
||||
animated?: boolean
|
||||
@@ -133,7 +134,7 @@ export function BasicTool(props: BasicToolProps) {
|
||||
if (!props.defer) return
|
||||
if (!value) {
|
||||
cancel()
|
||||
setState("ready", false)
|
||||
if (!props.retainDetails) setState("ready", false) // kilocode_change
|
||||
return
|
||||
}
|
||||
|
||||
@@ -183,6 +184,14 @@ export function BasicTool(props: BasicToolProps) {
|
||||
props.onOpenChange?.(value) // kilocode_change
|
||||
}
|
||||
|
||||
// kilocode_change start
|
||||
const end = (event: AnimationEvent) => {
|
||||
if (event.target !== event.currentTarget) return
|
||||
if (!props.retainDetails || open()) return
|
||||
setState("ready", false)
|
||||
}
|
||||
// kilocode_change end
|
||||
|
||||
const trigger = () => (
|
||||
<div
|
||||
data-component="tool-trigger"
|
||||
@@ -307,7 +316,7 @@ export function BasicTool(props: BasicToolProps) {
|
||||
</Show>
|
||||
{/* kilocode_change start */}
|
||||
<Show when={!props.animated && (hasChildren() || hasDetails()) && !props.hideDetails}>
|
||||
<Collapsible.Content>
|
||||
<Collapsible.Content onAnimationEnd={end}>
|
||||
<Show when={!props.defer || ready()}>{props.children}</Show>
|
||||
</Collapsible.Content>
|
||||
</Show>
|
||||
|
||||
Reference in New Issue
Block a user