Kosmesis
Components

AI Image

An image the AI generated or referenced, with a fade-in once loaded. Purely presentational — no Morphos equivalent.

Installation

npx kosmesis add ai-image
pnpm dlx kosmesis add ai-image
yarn dlx kosmesis add ai-image
bunx kosmesis add ai-image

Copy and paste the following code into your project.

ai-image.tsx
import { StatefulComponent } from "@praxisjs/core";import { Component, Prop, State } from "@praxisjs/decorators";import { cn } from "@/lib/utils";export interface AiImageProps {  src: string;  alt: string;  caption?: string;  class?: string;}@Component()export class AiImage extends StatefulComponent {  @Prop() src = "";  @Prop() alt = "";  @Prop() caption?: string;  @Prop() class?: string;  @State() _loaded = false;  render() {    return (      <figure data-slot="ai-image" class={cn("overflow-hidden rounded-lg border bg-muted", this.class)}>        <img          src={this.src}          alt={this.alt}          data-loaded={() => (this._loaded ? "" : undefined)}          class="block w-full object-cover opacity-0 transition-opacity duration-300 data-[loaded]:opacity-100"          onLoad={() => { this._loaded = true; }}        />        {this.caption && <figcaption class="border-t px-3 py-2 text-xs text-muted-foreground">{this.caption}</figcaption>}      </figure>    );  }}

Install the following dependencies:

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

Copy and paste the following code into your project.

ai-image.tsx
import { StatefulComponent } from "@praxisjs/core";import { cx, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component, Prop, State } from "@praxisjs/decorators";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class AiImageStyles extends Stylesheet {  $root = this.css({ overflow: "hidden", borderRadius: "0.5rem", border: `1px solid ${t.border}`, backgroundColor: t.muted });  $image = this.css({ display: "block", width: "100%", objectFit: "cover", opacity: 0, transition: "opacity 300ms ease" }).on(    "&[data-loaded]",    { opacity: 1 },  );  $caption = this.css({    borderTop: `1px solid ${t.border}`,    padding: "0.5rem 0.75rem",    fontSize: "0.75rem",    color: t.mutedForeground,  });}export interface AiImageProps {  src: string;  alt: string;  caption?: string;  class?: string;}@Component()export class AiImage extends StatefulComponent {  @Styled(AiImageStyles) $s!: AiImageStyles;  @Prop() src = "";  @Prop() alt = "";  @Prop() caption?: string;  @Prop() class?: string;  @State() _loaded = false;  render() {    return (      <figure data-slot="ai-image" class={cx(this.$s.$root, this.class)}>        <img          src={this.src}          alt={this.alt}          data-loaded={() => (this._loaded ? "" : undefined)}          class={this.$s.$image}          onLoad={() => { this._loaded = true; }}        />        {this.caption && <figcaption class={this.$s.$caption}>{this.caption}</figcaption>}      </figure>    );  }}

Examples

About

Purely presentational — no Morphos equivalent. The <img> starts at opacity-0 and fades in on its native load event, so a slow/generated image doesn't pop in abruptly.

Usage

import { AiImage } from "@/components/ui/ai-image";

<AiImage src={generatedUrl} alt="Generated preview" caption="Generated with your prompt" />

Props

PropTypeDefault
srcstring
altstring
captionstring
classstring

On this page