Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/animate-tool-card-reveals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---

Animate tool-call and reasoning details when expanding and collapsing.
58 changes: 55 additions & 3 deletions packages/kilo-ui/src/components/basic-tool.css
Original file line number Diff line number Diff line change
Expand Up @@ -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"] {
Expand Down Expand Up @@ -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;
Comment thread
Drixled marked this conversation as resolved.
}
}
}
18 changes: 10 additions & 8 deletions packages/kilo-ui/src/components/basic-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
)
}
54 changes: 43 additions & 11 deletions packages/kilo-ui/src/components/message-part.css
Original file line number Diff line number Diff line change
Expand Up @@ -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"] {
Expand Down Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -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"] {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Comment thread
Drixled marked this conversation as resolved.
}
}
6 changes: 4 additions & 2 deletions packages/kilo-ui/src/components/message-part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
13 changes: 11 additions & 2 deletions packages/ui/src/components/basic-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface BasicToolProps {
defaultOpen?: boolean
forceOpen?: boolean
defer?: boolean
retainDetails?: boolean // kilocode_change
hasDetails?: boolean // kilocode_change
locked?: boolean
animated?: boolean
Expand Down Expand Up @@ -125,7 +126,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
}

Expand Down Expand Up @@ -175,6 +176,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"
Expand Down Expand Up @@ -299,7 +308,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>
Expand Down
Loading