Components
AI Steps
A plain status list for an agent's task execution. Purely presentational — no Morphos equivalent.
Installation
npx kosmesis add ai-stepspnpm dlx kosmesis add ai-stepsyarn dlx kosmesis add ai-stepsbunx kosmesis add ai-stepsInstall the following dependencies:
npm install @morphos/iconspnpm add @morphos/iconsyarn add @morphos/iconsbun add @morphos/iconsCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Icon } from "@morphos/icons";import { cn } from "@/lib/utils";export interface AiStepsProps { class?: string; id?: string; children?: Children;}@Component()export class AiSteps extends StatelessComponent<AiStepsProps> { render() { const { class: cls, id, children } = this.props; return ( <div id={id} data-slot="ai-steps" class={cn("flex flex-col gap-2", cls)}> {children} </div> ); }}export type AiStepStatus = "pending" | "running" | "done" | "error";export interface AiStepProps { status?: AiStepStatus; class?: string; children?: Children;}@Component()export class AiStep extends StatelessComponent<AiStepProps> { render() { const { status = "done", class: cls, children } = this.props; return ( <div data-status={status} class={cn("flex items-center gap-2 text-sm", cls)}> <span class={cn( "flex size-4 shrink-0 items-center justify-center rounded-full text-[10px] leading-none", "in-data-[status=done]:bg-primary in-data-[status=done]:text-primary-foreground", "in-data-[status=running]:animate-pulse in-data-[status=running]:bg-primary/30", "in-data-[status=pending]:bg-muted", "in-data-[status=error]:bg-destructive in-data-[status=error]:text-destructive-foreground", )} > {status === "done" ? <Icon name="Check" size={10} /> : status === "error" ? <Icon name="X" size={10} /> : ""} </span> <span class="in-data-[status=pending]:text-muted-foreground">{children}</span> </div> ); }}Install the following dependencies:
npm install @praxisjs/css @morphos/iconspnpm add @praxisjs/css @morphos/iconsyarn add @praxisjs/css @morphos/iconsbun add @praxisjs/css @morphos/iconsCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Icon } from "@morphos/icons";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class AiStepsStyles extends Stylesheet { $root = this.css({ display: "flex", flexDirection: "column", gap: "0.5rem" }); $step = this.css({ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.875rem" }); $dot = this.css({ display: "flex", height: "1rem", width: "1rem", flexShrink: 0, alignItems: "center", justifyContent: "center", borderRadius: "9999px", fontSize: "0.625rem", lineHeight: 1, backgroundColor: t.muted, }) .on('[data-status="done"] &', { backgroundColor: t.primary, color: t.primaryForeground }) .on('[data-status="running"] &', { backgroundColor: `color-mix(in oklab, ${t.primary} 30%, transparent)` }) .on('[data-status="error"] &', { backgroundColor: t.destructive, color: t.destructiveForeground }); $label = this.css({}).on('[data-status="pending"] &', { color: t.mutedForeground });}export interface AiStepsProps { class?: string; id?: string; children?: Children;}@Component()export class AiSteps extends StatelessComponent<AiStepsProps> { @Styled(AiStepsStyles) $s!: AiStepsStyles; render() { const { class: cls, id, children } = this.props; return ( <div id={id} data-slot="ai-steps" class={cx(this.$s.$root, cls)}> {children} </div> ); }}export type AiStepStatus = "pending" | "running" | "done" | "error";export interface AiStepProps { status?: AiStepStatus; class?: string; children?: Children;}@Component()export class AiStep extends StatelessComponent<AiStepProps> { @Styled(AiStepsStyles) $s!: AiStepsStyles; render() { const { status = "done", class: cls, children } = this.props; return ( <div data-status={status} class={cx(this.$s.$step, cls)}> <span class={this.$s.$dot}> {status === "done" ? <Icon name="Check" size={10} /> : status === "error" ? <Icon name="X" size={10} /> : ""} </span> <span class={this.$s.$label}>{children}</span> </div> ); }}Examples
About
Purely presentational — no Morphos equivalent. Distinct from the generic Steps component
(numbered, connecting rail, meant for wizards/onboarding): AiSteps is a plain non-collapsible
status list meant for showing an agent's live task execution (tool calls, running commands, ...).
Usage
import { AiStep, AiSteps } from "@/components/ui/ai-steps";
<AiSteps>
<AiStep status="done">Read repository</AiStep>
<AiStep status="running">Running tests</AiStep>
<AiStep status="pending">Open pull request</AiStep>
</AiSteps>Props
AiStep
| Prop | Type | Default |
|---|---|---|
status | "pending" | "running" | "done" | "error" | "done" |
class | string | — |
AiSteps accepts class, id, and children only.