Vela UI Docsvenizia.ai

Doc Callout

A tinted note box in four tones - info, warning, danger, success - whose icon cycles the tone.

npx shadcn@latest add @velaui/doc-callout
npx shadcn@latest add @velaui/doc-callout

Examples

  • Default
  • Tones

View code

Doc Callout · Default

Installation

pnpm dlx velaui add @velaui/doc-callout
pnpm dlx velaui add @velaui/doc-callout

Code

doc-callout-default.tsx
import * as React from "react";

import { DocCallout, type DocCalloutTone } from "@/components/ui/doc-callout";

export default function Example() {
  const [tone, setTone] = React.useState<DocCalloutTone>("info");
  const [text, setText] = React.useState("Click the icon to change the tone.");
  return (
    <div className="w-full max-w-xl p-6">
      <DocCallout tone={tone} onToneChange={setTone} value={text} onChange={setText} />
    </div>
  );
}

View code

Doc Callout · Tones

Installation

pnpm dlx velaui add @velaui/doc-callout
pnpm dlx velaui add @velaui/doc-callout

Code

doc-callout-tones.tsx
import { DocCallout, DOC_CALLOUT_TONES } from "@/components/ui/doc-callout";

export default function Example() {
  return (
    <div className="w-full max-w-xl p-6">
      {DOC_CALLOUT_TONES.map((tone) => (
        <DocCallout key={tone} tone={tone} readOnly value={`A ${tone} note.`} />
      ))}
    </div>
  );
}

Usage

import * as React from "react";

import { DocCallout, type DocCalloutTone } from "@/components/ui/doc-callout";

export default function Example() {
  const [tone, setTone] = React.useState<DocCalloutTone>("info");
  const [text, setText] = React.useState("Click the icon to change the tone.");
  return (
    <div className="w-full max-w-xl p-6">
      <DocCallout tone={tone} onToneChange={setTone} value={text} onChange={setText} />
    </div>
  );
}

Props

PropTypeDefault
highlightsstring[]—
onChange(value: string, caret: number) => void—
onToneChange(tone: DocCalloutTone) => void—
toneDocCalloutTone"info"
valuerequiredstring—

Takes these and every prop of DocCalloutProps.

Dependencies

npm
none besides React
Installs with it
Doc Typography4 icons

Source

components/ui/doc-callout.tsx
/* eslint-disable react-refresh/only-export-components */

import { AlertTriangle } from "@/components/icons/alert-triangle";
import { CheckContained } from "@/components/icons/check-contained";
import { CloseCircleContained } from "@/components/icons/close-circle-contained";
import { InformationCircleContained } from "@/components/icons/information-circle-contained";
import { DocTypography, type DocTypographyProps } from "@/components/ui/doc-typography";
import { cn } from "@/lib/utils";

export type DocCalloutTone = "info" | "warning" | "danger" | "success";

export const DOC_CALLOUT_TONES: DocCalloutTone[] = ["info", "warning", "danger", "success"];

const TONE = {
  info: { box: "bg-info text-info-middle", icon: InformationCircleContained },
  warning: { box: "bg-warning text-warning-middle", icon: AlertTriangle },
  danger: { box: "bg-negative text-negative-middle", icon: CloseCircleContained },
  success: { box: "bg-success text-success-middle", icon: CheckContained },
};

export interface DocCalloutProps extends Omit<DocTypographyProps, "type"> {
  tone?: DocCalloutTone;
  /** Clicking the icon asks for the next tone; omit to keep the tone fixed. */
  onToneChange?: (tone: DocCalloutTone) => void;
}

/** A tinted note box: info, warning, danger or success. */
function DocCallout({ tone = "info", onToneChange, readOnly, className, ...props }: DocCalloutProps) {
  const { box, icon: Icon } = TONE[tone];
  const next = DOC_CALLOUT_TONES[(DOC_CALLOUT_TONES.indexOf(tone) + 1) % DOC_CALLOUT_TONES.length];
  return (
    <div className={cn("my-2 flex gap-2 rounded-md p-3", box, className)}>
      <button
        type="button"
        aria-label={`${tone} callout`}
        disabled={readOnly || !onToneChange}
        className="flex h-5 shrink-0 items-center justify-center enabled:cursor-pointer pointer-coarse:-m-3 pointer-coarse:size-11"
        onClick={() => onToneChange?.(next)}
      >
        <Icon size={20} />
      </button>
      <div className="min-w-0 flex-1">
        <DocTypography aria-label={`Callout ${tone}`} readOnly={readOnly} className="text-inherit" {...props} />
      </div>
    </div>
  );
}

export { DocCallout };