Components
Stock Badge
A product stock-level badge. Purely presentational — no Morphos equivalent.
Installation
npx kosmesis add stock-badgepnpm dlx kosmesis add stock-badgeyarn dlx kosmesis add stock-badgebunx kosmesis add stock-badgeCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { cn } from "@/lib/utils";export type StockStatus = "in-stock" | "low-stock" | "out-of-stock";export interface StockBadgeProps { status: StockStatus; count?: number; class?: string;}@Component()export class StockBadge extends StatelessComponent<StockBadgeProps> { render() { const { status, count, class: cls } = this.props; const labels: Record<StockStatus, string> = { "in-stock": "In stock", "low-stock": count !== undefined ? `Only ${String(count)} left` : "Low stock", "out-of-stock": "Out of stock", }; return ( <span data-status={status} class={cn( "inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium", "data-[status=in-stock]:bg-emerald-500/10 data-[status=in-stock]:text-emerald-600 dark:data-[status=in-stock]:text-emerald-400", "data-[status=low-stock]:bg-yellow-500/10 data-[status=low-stock]:text-yellow-600 dark:data-[status=low-stock]:text-yellow-400", "data-[status=out-of-stock]:bg-muted data-[status=out-of-stock]:text-muted-foreground", cls, )} > <span class="size-1.5 rounded-full bg-current" /> {labels[status]} </span> ); }}Install the following dependencies:
npm install @praxisjs/csspnpm add @praxisjs/cssyarn add @praxisjs/cssbun add @praxisjs/cssCopy 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 { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class StockBadgeStyles extends Stylesheet { $badge = this.css({ display: "inline-flex", alignItems: "center", gap: "0.375rem", borderRadius: "9999px", padding: "0.125rem 0.5rem", fontSize: "0.75rem", fontWeight: 500, }) .on('&[data-status="in-stock"]', { backgroundColor: "color-mix(in oklab, #10b981 10%, transparent)", color: "#10b981" }) .on('&[data-status="low-stock"]', { backgroundColor: "color-mix(in oklab, #eab308 10%, transparent)", color: "#a16207" }) .on('&[data-status="out-of-stock"]', { backgroundColor: t.muted, color: t.mutedForeground }); $dot = this.css({ height: "0.375rem", width: "0.375rem", borderRadius: "9999px", backgroundColor: "currentColor" });}export type StockStatus = "in-stock" | "low-stock" | "out-of-stock";export interface StockBadgeProps { status: StockStatus; count?: number; class?: string;}@Component()export class StockBadge extends StatelessComponent<StockBadgeProps> { @Styled(StockBadgeStyles) $s!: StockBadgeStyles; render() { const { status, count, class: cls } = this.props; const labels: Record<StockStatus, string> = { "in-stock": "In stock", "low-stock": count !== undefined ? `Only ${String(count)} left` : "Low stock", "out-of-stock": "Out of stock", }; return ( <span data-status={status} class={cx(this.$s.$badge, cls)}> <span class={this.$s.$dot} /> {labels[status]} </span> ); }}Examples
About
Purely presentational — no Morphos equivalent. count only affects the label when
status="low-stock" (renders "Only N left"); it's ignored for the other two statuses.
Usage
import { StockBadge } from "@/components/ui/stock-badge";
<StockBadge status="low-stock" count={3} />Props
| Prop | Type | Default |
|---|---|---|
status | "in-stock" | "low-stock" | "out-of-stock" | — |
count | number | — |
class | string | — |