Components
Alert
A static inline notification with Title/Description parts, wrapping Morphos's Alert primitive.
Installation
npx kosmesis add alertpnpm dlx kosmesis add alertyarn dlx kosmesis add alertbunx kosmesis add alertInstall the following dependencies:
npm install @morphos/feedback class-variance-authoritypnpm add @morphos/feedback class-variance-authorityyarn add @morphos/feedback class-variance-authoritybun add @morphos/feedback class-variance-authorityCopy and paste the following code into your project.
import { cva, type VariantProps } from "class-variance-authority";import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import type { Children } from "@praxisjs/shared";import { Alert as MorphosAlert, type AlertProps as MorphosAlertProps } from "@morphos/feedback";import { cn } from "@/lib/utils";export const alertVariants = cva( "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", { variants: { variant: { default: "bg-card text-card-foreground", destructive: "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", }, }, defaultVariants: { variant: "default", }, },);export interface AlertProps extends Omit<MorphosAlertProps, "variant">, VariantProps<typeof alertVariants> {}@Component()export class Alert extends StatelessComponent<AlertProps> { render() { const { variant, class: cls, title, children, ...rest } = this.props; return ( <MorphosAlert class={cn(alertVariants({ variant }), cls)} variant={variant === "destructive" ? "error" : "info"} title={title} {...rest} > {children} </MorphosAlert> ); }}export interface AlertSlotProps { class?: string; id?: string; children?: Children;}@Component()export class AlertTitle extends StatelessComponent<AlertSlotProps> { render() { const { class: cls, id, children } = this.props; return ( <div id={id} data-slot="alert-title" class={cn("col-start-2 min-h-4 font-medium tracking-tight", cls)}> {children} </div> ); }}@Component()export class AlertDescription extends StatelessComponent<AlertSlotProps> { render() { const { class: cls, id, children } = this.props; return ( <div id={id} data-slot="alert-description" class={cn("col-start-2 grid justify-items-start gap-1 text-sm text-muted-foreground [&_p]:leading-relaxed", cls)} > {children} </div> ); }}Install the following dependencies:
npm install @morphos/feedback @praxisjs/csspnpm add @morphos/feedback @praxisjs/cssyarn add @morphos/feedback @praxisjs/cssbun add @morphos/feedback @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 type { Children } from "@praxisjs/shared";import { Alert as MorphosAlert, type AlertProps as MorphosAlertProps } from "@morphos/feedback";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);class AlertStyles extends Stylesheet { $root = this.css({ position: "relative", display: "grid", width: "100%", gridTemplateColumns: "0 1fr", alignItems: "start", rowGap: "0.125rem", borderRadius: "0.5rem", border: `1px solid ${t.border}`, padding: "0.75rem 1rem", fontSize: "0.875rem", }) .has(">svg", { gridTemplateColumns: "1rem 1fr", columnGap: "0.75rem" }) .on("& > svg", { width: "1rem", height: "1rem", transform: "translateY(0.125rem)", color: "currentColor" }); $variantDefault = this.css({ backgroundColor: t.card, color: t.cardForeground }); $variantDestructive = this.css({ backgroundColor: t.card, color: t.destructive }).on("& > svg", { color: "currentColor", }); $title = this.css({ gridColumnStart: 2, minHeight: "1rem", fontWeight: 500, letterSpacing: "-0.01em" }); $description = this.css({ gridColumnStart: 2, display: "grid", justifyItems: "start", rowGap: "0.25rem", fontSize: "0.875rem", color: t.mutedForeground, }).on("& p", { lineHeight: 1.6 });}export type AlertVariant = "default" | "destructive";export interface AlertProps extends Omit<MorphosAlertProps, "variant"> { variant?: AlertVariant;}@Component()export class Alert extends StatelessComponent<AlertProps> { @Styled(AlertStyles) $s!: AlertStyles; render() { const { variant = "default", class: cls, title, children, ...rest } = this.props; const variants: Record<AlertVariant, string> = { default: this.$s.$variantDefault, destructive: this.$s.$variantDestructive, }; return ( <MorphosAlert class={cx(this.$s.$root, variants[variant], cls)} variant={variant === "destructive" ? "error" : "info"} title={title} {...rest} > {children} </MorphosAlert> ); }}export interface AlertSlotProps { class?: string; id?: string; children?: Children;}@Component()export class AlertTitle extends StatelessComponent<AlertSlotProps> { @Styled(AlertStyles) $s!: AlertStyles; render() { const { class: cls, id, children } = this.props; return ( <div id={id} data-slot="alert-title" class={cx(this.$s.$title, cls)}> {children} </div> ); }}@Component()export class AlertDescription extends StatelessComponent<AlertSlotProps> { @Styled(AlertStyles) $s!: AlertStyles; render() { const { class: cls, id, children } = this.props; return ( <div id={id} data-slot="alert-description" class={cx(this.$s.$description, cls)}> {children} </div> ); }}Examples
Usage
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
<Alert>
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>You can add components using the CLI.</AlertDescription>
</Alert>
<Alert variant="destructive">
<AlertTitle>Error</AlertTitle>
<AlertDescription>Your session has expired. Please log in again.</AlertDescription>
</Alert>Props
| Prop | Type | Default |
|---|---|---|
variant | "default" | "destructive" | "default" |
variant="destructive" maps to Morphos's variant="error" under the hood (and sets
aria-live="assertive" accordingly); variant="default" maps to Morphos's "info".