Nasaq

Linkify

Small text helpers for user content. Linkify safe links, bidi-isolated UserText, a translation toggle, scroll fades, an optimistic save button and progressive reveal.

PreviewOpen ↗

Code

import { UserText, BookmarkButton } from "@fadymondy/nasaq/web";export function Example({ message }: { message: string }) {  return (    <div className="flex items-start gap-2">      <UserText block lines={3} linkify>{message}</UserText>      <BookmarkButton onSavedChange={async (saved) => { await save(saved); }} />    </div>  );}

Utilities · beta

Live examples and controls: Linkify in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/text-utilities.json

Seven small parts for text people wrote. Linkify turns http, https, www and email addresses into links. UserText isolates a name or message so its direction never scrambles the sentence around it. TranslatableText toggles between the original and a translation. ScrollFade fades the edge of a sideways-scrolling row. BookmarkButton saves optimistically. ProgressiveReveal and ProgressiveList show more on demand.

When to use

  • Chat messages, comments, notes and titles that may contain links and either script: UserText with linkify.
  • A toggle for machine translation: TranslatableText.
  • A chip row or tab row wider than its container: ScrollFade.

When not to use

  • Rich text or Markdown: render it with a sanitising renderer. Linkify only scans plain strings and never parses HTML.

Import

import { Linkify, UserText, TranslatableText, ScrollFade, BookmarkButton, ProgressiveReveal, ProgressiveList } from "@fadymondy/nasaq/web";

Quick start

import { UserText, BookmarkButton } from "@fadymondy/nasaq/web";

export function Example({ message }: { message: string }) {
  return (
    <div className="flex items-start gap-2">
      <UserText block lines={3} linkify>{message}</UserText>
      <BookmarkButton onSavedChange={async (saved) => { await save(saved); }} />
    </div>
  );
}

API

ComponentPropDescription
Linkifychildren: string, emails (true), linkClassName, renderLinkOnly safe schemes. Trailing punctuation is left out of the link. Arabic punctuation ends a URL. Bare domains are not linked.
UserTextblock, lines, linkify, asdir="auto", isolated, aligned to the start edge. lines clamps and puts the full text in title.
TranslatableTextoriginal, translation, sourceLang, targetLang, onTranslate, defaultShowTranslation, lines, linkifyonTranslate runs once, the result is kept. Resolve { error } to show a retry.
ScrollFadefadeSize (32), label, contentClassNameFades only the edge with more content. Direction follows the layout.
BookmarkButtonsaved / defaultSaved, onSavedChange, showLabelFlips at once, reverts if the promise rejects or resolves { error }.
ProgressiveRevealcollapsedHeight (96), expanded / defaultExpanded, onExpandedChangeThe button appears only when the content is taller than the limit.
ProgressiveListitems, initial (3), step (3), onRevealShows the count left.

All take labels (TextUtilitiesLabels) to override the en and ar strings. Pure helpers with no React are also exported: linkifyText, linkifyTrim, scrollFadeState, scrollFadeMask, progressiveNextCount, progressiveRemaining.

Accessibility

  • Links are real anchors with rel="noopener noreferrer".
  • ScrollFade is a labelled, focusable region while it scrolls, so it can be moved with the arrow keys.
  • BookmarkButton uses aria-pressed and a polite live region for saved, removed and failed.
  • ProgressiveReveal drives aria-expanded on a real button.

RTL & i18n

URLs and emails are left to right inside Arabic text. ScrollFade reads the computed direction and uses the absolute scroll offset, so the start fade sits on the right in Arabic. Strings are en and ar.

Styling & tokens

Semantic tokens only. Extend with className, linkClassName and contentClassName.

Do / Don't

  • Do pass plain strings to Linkify and UserText.
  • Do not use dangerouslySetInnerHTML to add links.
  • Do not link bare domains: people write "file.txt" and "e.g".

Lab

https://docs.nasaqui.com/?path=/docs/components-utilities-text-utilities--docs

On this page