Anchor Port

Port marker for object inputs, outputs, and bidirectional links on the canvas.

Signaler un bug

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/anchor-port.json
bash

Storybook

Explorez les variantes, controles et verifications d'accessibilite dans le playground Storybook interactif.

Voir dans Storybook

Code

import { forwardRef } from "react";

import { cn } from "../../lib/utils";

export type AnchorPortProps = React.ComponentPropsWithoutRef<"span"> & {
  side?: "bottom" | "left" | "right" | "top";
  state?: "active" | "blocked" | "idle";
  tone?: "bidirectional" | "input" | "output";
};

const toneClasses: Record<NonNullable<AnchorPortProps["tone"]>, string> = {
  bidirectional:
    "border-violet-500/40 bg-violet-500/15 text-violet-700 dark:text-violet-300",
  input: "border-sky-500/40 bg-sky-500/15 text-sky-700 dark:text-sky-300",
  output:
    "border-emerald-500/40 bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
};

const stateClasses: Record<NonNullable<AnchorPortProps["state"]>, string> = {
  active: "scale-100 opacity-100",
  blocked: "opacity-60 saturate-50",
  idle: "opacity-80",
};

const sideClasses: Record<NonNullable<AnchorPortProps["side"]>, string> = {
  bottom: "self-end",
  left: "self-start",
  right: "self-end",
  top: "self-start",
};

const AnchorPort = forwardRef<HTMLSpanElement, AnchorPortProps>(
  (
    {
      className,
      side = "right",
      state = "idle",
      tone = "bidirectional",
      ...props
    },
    ref,
  ) => (
    <span
      aria-label={props["aria-label"] ?? `${tone} ${side} port ${state}`}
      className={cn(
        "inline-flex size-7 items-center justify-center rounded-full border shadow-sm",
        toneClasses[tone],
        stateClasses[state],
        sideClasses[side],
        className,
      )}
      data-side={side}
      data-state={state}
      data-tone={tone}
      ref={ref}
      role="img"
      {...props}
    >
      <span className="size-2.5 rounded-full bg-current" />
    </span>
  ),
);

AnchorPort.displayName = "AnchorPort";

export { AnchorPort };
typescript

Dependances

  • @vllnt/ui@^0.2.1