Kosmesis
Components

Source

A collapsible list of citation links backing an AI response. Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add source
pnpm dlx kosmesis add source
yarn dlx kosmesis add source
bunx kosmesis add source

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.

source.tsx
import { StatefulComponent, StatelessComponent } 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 SourcesProps {  defaultOpen?: boolean;  class?: string;  children?: Children;}@Component()export class Sources extends StatefulComponent {  @Prop() defaultOpen = false;  @Prop() class?: string;  @Prop() children?: Children;  @State() _open = false;  onBeforeMount() {    this._open = this.defaultOpen;  }  toggle(): void {    this._open = !this._open;  }  render() {    return (      <div data-slot="sources" class={cn("text-sm", this.class)}>        <button          type="button"          class="flex items-center gap-1.5 text-muted-foreground hover:text-foreground"          onClick={() => { this.toggle(); }}        >          <span class={() => cn("inline-block transition-transform", this._open && "rotate-90")}>            <Icon name="ChevronRight" size={14} />          </span>          Sources        </button>        <div          data-state={() => (this._open ? "open" : "closed")}          class="mt-2 flex flex-col gap-1 data-[state=closed]:hidden"        >          {this.children}        </div>      </div>    );  }}export interface SourceProps {  href: string;  class?: string;  children?: Children;}@Component()export class Source extends StatelessComponent<SourceProps> {  render() {    const { href, class: cls, children } = this.props;    return (      <a        href={href}        target="_blank"        rel="noopener noreferrer"        class={cn(          "flex items-center gap-2 truncate rounded-md border px-2 py-1.5 text-xs text-muted-foreground hover:bg-accent hover:text-accent-foreground",          cls,        )}      >        <span class="truncate">{children ?? href}</span>      </a>    );  }}

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.

source.tsx
import { StatefulComponent, StatelessComponent } 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 SourcesStyles extends Stylesheet {  $root = this.css({ fontSize: "0.875rem" });  $trigger = this.css({    display: "flex",    alignItems: "center",    gap: "0.375rem",    color: t.mutedForeground,    cursor: "pointer",  }).on("&:hover", { color: t.foreground });  $chevron = this.css({ display: "inline-block", transition: "transform 150ms ease" }).on("&[data-open]", {    transform: "rotate(90deg)",  });  $content = this.css({ marginTop: "0.5rem", display: "flex", flexDirection: "column", gap: "0.25rem" }).on(    '&[data-state="closed"]',    { display: "none" },  );  $source = this.css({    display: "flex",    alignItems: "center",    gap: "0.5rem",    overflow: "hidden",    textOverflow: "ellipsis",    whiteSpace: "nowrap",    borderRadius: "0.375rem",    border: `1px solid ${t.border}`,    padding: "0.375rem 0.5rem",    fontSize: "0.75rem",    color: t.mutedForeground,  }).on("&:hover", { backgroundColor: t.accent, color: t.accentForeground });}export interface SourcesProps {  defaultOpen?: boolean;  class?: string;  children?: Children;}@Component()export class Sources extends StatefulComponent {  @Styled(SourcesStyles) $s!: SourcesStyles;  @Prop() defaultOpen = false;  @Prop() class?: string;  @Prop() children?: Children;  @State() _open = false;  onBeforeMount() {    this._open = this.defaultOpen;  }  toggle(): void {    this._open = !this._open;  }  render() {    return (      <div data-slot="sources" class={cx(this.$s.$root, this.class)}>        <button type="button" class={this.$s.$trigger} onClick={() => { this.toggle(); }}>          <span data-open={() => (this._open ? "" : undefined)} class={this.$s.$chevron}>            <Icon name="ChevronRight" size={14} />          </span>          Sources        </button>        <div data-state={() => (this._open ? "open" : "closed")} class={this.$s.$content}>          {this.children}        </div>      </div>    );  }}export interface SourceProps {  href: string;  class?: string;  children?: Children;}@Component()export class Source extends StatelessComponent<SourceProps> {  @Styled(SourcesStyles) $s!: SourcesStyles;  render() {    const { href, class: cls, children } = this.props;    return (      <a href={href} target="_blank" rel="noopener noreferrer" class={cx(this.$s.$source, cls)}>        {children ?? href}      </a>    );  }}

Examples

About

Purely presentational — no Morphos equivalent. Sources is the collapsible wrapper; each Source is a plain external link styled as a small chip, defaulting its label to the href if no children are given.

Usage

import { Source, Sources } from "@/components/ui/source";

<Sources defaultOpen>
  <Source href="https://example.com/docs">Example Docs</Source>
  <Source href="https://example.com" />
</Sources>

Props

Sources

PropTypeDefault
defaultOpenbooleanfalse
classstring

Source

PropTypeDefault
hrefstring
classstring

On this page