Kosmesis
Components

Branch

Navigable alternate responses (regenerations) for one AI turn. Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add branch
pnpm dlx kosmesis add branch
yarn dlx kosmesis add branch
bunx kosmesis add branch

Install the following dependencies:

npm install @morphos/icons
pnpm add @morphos/icons
yarn add @morphos/icons
bun add @morphos/icons

Copy and paste the following code into your project.

branch.tsx
import { StatefulComponent } from "@praxisjs/core";import { Component, Prop, State } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Icon } from "@morphos/icons";import { cn } from "@/lib/utils";export interface BranchProps {  branches: Children[];  class?: string;}// All branches render up front and toggle via `data-active`; a reactive children-thunk can't// return a bare `Children` value.@Component()export class Branch extends StatefulComponent {  @Prop() branches: Children[] = [];  @Prop() class?: string;  @State() _index = 0;  prev(): void {    this._index = Math.max(0, this._index - 1);  }  next(): void {    this._index = Math.min(this.branches.length - 1, this._index + 1);  }  render() {    return (      <div data-slot="branch" class={cn("flex flex-col gap-2", this.class)}>        <div>          {this.branches.map((branch, i) => (            <div key={i} data-active={() => (this._index === i ? "" : undefined)} class="hidden data-[active]:block">              {branch}            </div>          ))}        </div>        {this.branches.length > 1 && (          <div class="flex items-center gap-2 text-xs text-muted-foreground">            <button              type="button"              aria-label="Previous branch"              disabled={() => this._index === 0}              class="rounded p-1 hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-30"              onClick={() => { this.prev(); }}            >              <Icon name="ChevronLeft" size={14} />            </button>            <span>{() => `${String(this._index + 1)} / ${String(this.branches.length)}`}</span>            <button              type="button"              aria-label="Next branch"              disabled={() => this._index === this.branches.length - 1}              class="rounded p-1 hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-30"              onClick={() => { this.next(); }}            >              <Icon name="ChevronRight" size={14} />            </button>          </div>        )}      </div>    );  }}

Install the following dependencies:

npm install @praxisjs/css @morphos/icons
pnpm add @praxisjs/css @morphos/icons
yarn add @praxisjs/css @morphos/icons
bun add @praxisjs/css @morphos/icons

Copy and paste the following code into your project.

branch.tsx
import { StatefulComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component, Prop, State } 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 BranchStyles extends Stylesheet {  $root = this.css({ display: "flex", flexDirection: "column", gap: "0.5rem" });  $branch = this.css({ display: "none" }).on("&[data-active]", { display: "block" });  $nav = this.css({ display: "flex", alignItems: "center", gap: "0.5rem", fontSize: "0.75rem", color: t.mutedForeground });  $navButton = this.css({ borderRadius: "0.25rem", padding: "0.25rem", cursor: "pointer" })    .on("&:hover", { backgroundColor: t.accent, color: t.accentForeground })    .on("&:disabled", { pointerEvents: "none", opacity: 0.3 });}export interface BranchProps {  branches: Children[];  class?: string;}// All branches render up front and toggle via `data-active`; a reactive children-thunk can't// return a bare `Children` value.@Component()export class Branch extends StatefulComponent {  @Styled(BranchStyles) $s!: BranchStyles;  @Prop() branches: Children[] = [];  @Prop() class?: string;  @State() _index = 0;  prev(): void {    this._index = Math.max(0, this._index - 1);  }  next(): void {    this._index = Math.min(this.branches.length - 1, this._index + 1);  }  render() {    return (      <div data-slot="branch" class={cx(this.$s.$root, this.class)}>        <div>          {this.branches.map((branch, i) => (            <div key={i} data-active={() => (this._index === i ? "" : undefined)} class={this.$s.$branch}>              {branch}            </div>          ))}        </div>        {this.branches.length > 1 && (          <div class={this.$s.$nav}>            <button type="button" aria-label="Previous branch" disabled={() => this._index === 0} class={this.$s.$navButton} onClick={() => { this.prev(); }}>              <Icon name="ChevronLeft" size={14} />            </button>            <span>{() => `${String(this._index + 1)} / ${String(this.branches.length)}`}</span>            <button              type="button"              aria-label="Next branch"              disabled={() => this._index === this.branches.length - 1}              class={this.$s.$navButton}              onClick={() => { this.next(); }}            >              <Icon name="ChevronRight" size={14} />            </button>          </div>        )}      </div>    );  }}

Examples

About

Purely presentational — no Morphos equivalent. Every branch is rendered up front and toggled via a data-active attribute (not swapped in/out), the same pattern StickyScroll's panel uses, since a reactive children-thunk can't return a bare Children value. The prev/next nav only renders when there's more than one branch.

Usage

import { Branch } from "@/components/ui/branch";

<Branch branches={[responseA, responseB, responseC]} />

Props

PropTypeDefault
branchesChildren[]
classstring

On this page