SeamRule · SeamText · Caret · RegFrame

The signature primitive. Name two hues once and every rule, clipped headline and tick draws from them — canvas effects included.

Install

$ npx shadcn@latest add wisp.pouriah.com/r/seam.json
CSSno JS
Two tokens meet, and the seam talks
--wisp → --lantern

SeamRule · SeamText · Caret · RegFrameesc or double-click to exit full screendouble-tap to exit

primitives/seam.tsx
"use client";

import * as React from "react";
import { cx, useTokenColorExpr } from "@pouriahlabs/wisp-ui";

/**
 * Seam — the signature primitive.
 *
 * Name two hues once and every gradient rule, clipped headline and tick on the
 * page draws from them, canvas effects included. It is the cheapest component
 * here and the one that makes a page look designed rather than assembled,
 * because it forces the accent to be a *relationship* between two tokens
 * instead of a single colour dropped in wherever emphasis is needed.
 */

interface SeamTokens {
  fromToken?: string;
  toToken?: string;
}

function seamVars(fromExpr: string, toExpr: string, angle: string): React.CSSProperties {
  return {
    "--wisp-seam-from": fromExpr,
    "--wisp-seam-to": toExpr,
    "--wisp-seam-angle": angle,
  } as React.CSSProperties;
}

/** A rule that runs from one token to the other. Give it a width or height. */
export function SeamRule({
  fromToken = "--wisp",
  toToken = "--lantern",
  orientation = "vertical",
  className,
  style,
  ...props
}: SeamTokens &
  React.HTMLAttributes<HTMLDivElement> & { orientation?: "vertical" | "horizontal" }) {
  const from = useTokenColorExpr(fromToken);
  const to = useTokenColorExpr(toToken);
  return (
    <div
      aria-hidden
      className={cx("wisp-seam-rule", className)}
      style={{
        ...seamVars(from, to, orientation === "vertical" ? "to bottom" : "to right"),
        ...style,
      }}
      {...props}
    />
  );
}

/**
 * The same gradient, clipped to text. Use it on a clause, not a whole
 * paragraph — clipped text loses contrast against most grounds, so it belongs
 * where emphasis is the job and legibility is already carried by size.
 */
export function SeamText({
  fromToken = "--wisp",
  toToken = "--lantern",
  angle = "92deg",
  as: Tag = "span",
  className,
  style,
  children,
  ...props
}: SeamTokens & React.HTMLAttributes<HTMLElement> & { angle?: string; as?: React.ElementType }) {
  const from = useTokenColorExpr(fromToken);
  const to = useTokenColorExpr(toToken);
  return (
    <Tag
      className={cx("wisp-seam-text", className)}
      style={{ ...seamVars(from, to, angle), ...style }}
      {...props}
    >
      {children}
    </Tag>
  );
}

/**
 * A blinking terminal caret. Takes `currentColor`, so it inherits whatever it
 * sits inside.
 */
export function Caret({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) {
  return <span aria-hidden className={cx("wisp-caret", className)} {...props} />;
}

/** L-shaped corner ticks, like a viewport crop on an engineering drawing. */
export function RegFrame({
  token,
  tick = 10,
  className,
  style,
  children,
  ...props
}: React.HTMLAttributes<HTMLDivElement> & { token?: string; tick?: number }) {
  // Called unconditionally (Rules of Hooks); its result is only applied when a
  // token is named, so the ticks otherwise inherit `currentColor` as before.
  const inkExpr = useTokenColorExpr(token ?? "--wisp");
  return (
    <div
      className={cx("wisp-reg relative", className)}
      style={
        {
          "--wisp-tick": `${tick}px`,
          ...(token ? { "--wisp-tick-ink": inkExpr } : null),
          ...style,
        } as React.CSSProperties
      }
      {...props}
    >
      {children}
    </div>
  );
}

Certified against the contract