Skip to content

Terminal-safe OSC 8 Link component for Tinky applications

Notifications You must be signed in to change notification settings

ByteLandTechnology/tinky-link

Repository files navigation

README.md / README.zh-CN.md / README.ja-JP.md

tinky-link

tinky-link provides a terminal-safe Link component for Tinky applications. It renders OSC 8 hyperlinks when the terminal supports them, and uses safe fallback behavior otherwise.

Project positioning

Link is a focused terminal UI component designed to make terminal hyperlinks usable without scattering protocol-specific formatting logic across your app code. It also exposes small utility APIs for policy checks and formatting.

Core features

  • OSC 8 hyperlink rendering for terminals that support it.
  • Built-in href validation and normalization.
  • Explicit unsafe fallback control: render plain text or throw.
  • Accessibility handling for screen readers.
  • Theme hooks through tinky-theme with safety-state-aware style slots.
  • Small, typed utility exports for integrations.

Installation and quick start

Install dependencies (use your actual package name if different):

npm install tinky-link tinky tinky-theme react
import { render } from "tinky";
import { Link } from "tinky-link";

function App() {
  return <Link href="https://example.com/docs">Open docs</Link>;
}

render(<App />);

Link props and exported API

Link props

Prop Type Default Description
href string | URL required Link destination.
children ReactNode normalized href Visible text. Uses normalized href if omitted.
variant "primary" | "muted" | "danger" "primary" Visual variant passed to theme.
disabled boolean false Disables hyperlink output and renders plain text.
showHref boolean false Appends (<href>) in unsafe or non-hyperlink mode.
unsafeHrefBehavior "render-text" | "throw" "render-text" Fallback policy for unsafe href input.
wrap TextProps["wrap"] "wrap" Forwarded to Tinky Text wrapping behavior.
aria-label string undefined Accessibility label.
aria-hidden boolean undefined Hide from screen readers when true.

Exports

The entrypoint currently exports:

  • Link and LinkProps
  • useHyperlinkSupport
  • validateHref, normalizeHref, HrefValidationReason, HrefValidationResult, LinkHref
  • OSC8_PREFIX, wrapWithOsc8
  • Theme exports: LINK_COMPONENT_NAME, defaultLinkTheme, LinkComponentTheme, LinkTheme, LinkThemeProps, LinkVariant

Safety model

Link validates href input before wrapping with OSC 8.

Validation is implemented by validateHref(rawHref) with this pipeline:

  1. Normalize input by trimming (string or URL to string)
  2. Reject empty values (reason: "empty")
  3. Reject OSC terminators (BEL, ESC\\, \u009C, reason: "contains-osc-terminator")
  4. Reject control characters (C0 and C1, reason: "contains-control-char")

Fallback behavior:

  • unsafeHrefBehavior="render-text" (default): render plain text, optional suffix.
  • unsafeHrefBehavior="throw": throw Unsafe href rejected (<reason>).
  • If terminal/feature does not support OSC 8 or disabled is true: render plain text.

Terminal support detection logic

useHyperlinkSupport() determines OSC 8 availability:

  1. Read FORCE_HYPERLINK from app env first.
    • "1" => force enable
    • "0" => force disable
  2. Read terminal name via useTermcap(). Enable for known names such as kitty, wezterm, iterm, xterm, alacritty, ghostty, contour, foot, vscode, tabby, hyper, mintty.
  3. Fallback to environment indicators:
    • WT_SESSION
    • ITERM_SESSION_ID
    • TERM_PROGRAM values: iTerm.app, WezTerm, vscode, Hyper, mintty
    • VTE_VERSION >= 5000
  4. Default is false.

The link component uses this flag and screen reader mode to decide whether to emit OSC 8 sequences.

Theme customization

The component reads styles from tinky-theme under the component key LINK_COMPONENT_NAME ("Link"). Theme slot props include:

  • variant
  • disabled
  • showHref
  • isUnsafe
  • isHyperlinkEnabled

Available style slots: container, label, href.

import { ThemeProvider } from "tinky-theme";
import { Link, defaultLinkTheme } from "tinky-link";

const appTheme = {
  components: {
    Link: {
      ...defaultLinkTheme,
      styles: {
        ...defaultLinkTheme.styles,
        label: (props) => ({
          ...defaultLinkTheme.styles.label(props),
          color: props.isUnsafe ? "yellow" : "green",
          bold: props.isHyperlinkEnabled,
        }),
      },
    },
  },
};

function App() {
  return (
    <ThemeProvider theme={appTheme}>
      <Link href="https://example.com">Custom theme link</Link>
    </ThemeProvider>
  );
}

Development commands

Scripts defined in this repository:

  • npm run test
  • npm run lint
  • npm run docs
  • npm run build
  • npm run demo (runs demo/index.mjs)

License

This package is released under the MIT License. See LICENSE.

About

Terminal-safe OSC 8 Link component for Tinky applications

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors