Merge pull request #6591 from Kilo-Org/mark/prompt-input-stories

feat(vscode): add prompt input Storybook stories with visual regression
This commit is contained in:
Mark IJbema
2026-03-04 13:26:13 +01:00
committed by GitHub
7 changed files with 143 additions and 2 deletions
@@ -61,6 +61,11 @@ test.describe("Visual Regression", () => {
test("all stories", async ({ page }) => {
if (IS_DARWIN) return
for (const story of stories) {
// Narrow stories (IDs ending in "-200") use a 200px viewport
// The "-200" suffix comes from the export name convention (e.g. Default200, WithThinking200)
const narrow = story.id.endsWith("-200")
await page.setViewportSize({ width: narrow ? 200 : 420, height: 720 })
// Use kilo-vscode theme by default (matched to the preview initialGlobals)
await page.goto(
`/iframe.html?id=${story.id}&viewMode=story&globals=colorScheme:dark;theme:kilo-vscode;vscodeTheme:dark-modern`,
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3149642961d81ad2ce327cde45c702c143484602a0a51ff1801a6c469afb57ed
size 4490
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c130d85a62ccc9e042285e3cb4cf27c2cad41da8a152d7babb0eaba7eedce5b8
size 5210
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:da8a087a227ff2d10a4e63208499e563d74e50415ce2ae037479f69dddf2c73c
size 5332
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:27383118522850a8d49f40b9e92e1030127840cdef344175cdd3a548670d163a
size 6453
@@ -64,7 +64,12 @@ export function mockSessionValue(overrides?: {
return {
currentSessionID: () => id,
currentSession: () => ({ id, title: "Story session", createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }),
currentSession: () => ({
id,
title: "Story session",
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
}),
setCurrentSessionID: noop,
sessions: () => [],
status: () => status,
@@ -124,6 +129,8 @@ interface StoryProvidersProps {
questions?: QuestionRequest[]
status?: string
sessionID?: string
/** When true, renders children without the default 12px padding wrapper */
noPadding?: boolean
}
export const StoryProviders: ParentComponent<StoryProvidersProps> = (props) => {
@@ -152,7 +159,7 @@ export const StoryProviders: ParentComponent<StoryProvidersProps> = (props) => {
<DiffComponentProvider component={Diff}>
<CodeComponentProvider component={Code}>
<MarkedProvider>
<div style={{ padding: "12px" }}>{props.children}</div>
{props.noPadding ? props.children : <div style={{ padding: "12px" }}>{props.children}</div>}
</MarkedProvider>
</CodeComponentProvider>
</DiffComponentProvider>
@@ -0,0 +1,117 @@
/** @jsxImportSource solid-js */
/**
* Stories for the PromptInput component.
*
* Covers the main prompt bar including the mode switcher, model dropdown,
* and the thinking-effort (variant) dropdown that appears for models that
* support reasoning variants.
*
* Two viewport widths are captured for each scenario:
* - 420 px — typical sidebar width
* - 200 px — narrow / collapsed sidebar
*/
import type { Meta, StoryObj } from "storybook-solidjs-vite"
import { type ParentComponent } from "solid-js"
import { StoryProviders, mockSessionValue } from "./StoryProviders"
import { SessionContext } from "../context/session"
import { VSCodeProvider } from "../context/vscode"
import { ServerProvider } from "../context/server"
import { ConfigProvider } from "../context/config"
import { ProviderProvider } from "../context/provider"
import { PromptInput } from "../components/chat/PromptInput"
// ---------------------------------------------------------------------------
// Providers — wraps StoryProviders with the extra providers PromptInput needs
// (VSCode/Server/Config/ProviderProvider are not in StoryProviders because
// composite stories only render display components that don't need them)
// ---------------------------------------------------------------------------
const agents = [
{ name: "code", description: "Write, edit and review code", mode: "primary" as const },
{ name: "ask", description: "Answer questions without making changes", mode: "primary" as const },
{ name: "architect", description: "Plan and design before implementation", mode: "primary" as const },
]
const PromptProviders: ParentComponent<{ variants?: boolean }> = (props) => {
const base = mockSessionValue({ status: "idle" })
const session = {
...base,
agents: () => agents,
selectedAgent: () => "code",
variantList: () => (props.variants ? ["low", "medium", "high"] : []),
currentVariant: () => (props.variants ? ("medium" as string | undefined) : undefined),
}
return (
<VSCodeProvider>
<ServerProvider>
<ConfigProvider>
<ProviderProvider>
<StoryProviders noPadding>
{/* overflow:hidden prevents margin-collapse so top/bottom borders are captured in screenshots */}
<div style={{ overflow: "hidden" }}>
<SessionContext.Provider value={session as any}>{props.children}</SessionContext.Provider>
</div>
</StoryProviders>
</ProviderProvider>
</ConfigProvider>
</ServerProvider>
</VSCodeProvider>
)
}
// ---------------------------------------------------------------------------
// Meta — fullscreen so the screenshot is exactly the component width
// ---------------------------------------------------------------------------
const meta: Meta = {
title: "Prompt Input",
parameters: { layout: "fullscreen" },
}
export default meta
type Story = StoryObj
// ---------------------------------------------------------------------------
// Stories — standard model (no thinking variants)
// ---------------------------------------------------------------------------
export const Default420: Story = {
name: "Default — 420px",
render: () => (
<PromptProviders>
<PromptInput />
</PromptProviders>
),
}
export const Default200: Story = {
name: "Default — 200px",
render: () => (
<PromptProviders>
<PromptInput />
</PromptProviders>
),
}
// ---------------------------------------------------------------------------
// Stories — model with thinking-effort variants (ThinkingSelector visible)
// ---------------------------------------------------------------------------
export const WithThinking420: Story = {
name: "With thinking selector — 420px",
render: () => (
<PromptProviders variants>
<PromptInput />
</PromptProviders>
),
}
export const WithThinking200: Story = {
name: "With thinking selector — 200px",
render: () => (
<PromptProviders variants>
<PromptInput />
</PromptProviders>
),
}