npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rightkit/legal-ui

v0.4.1

Published

The one first-run / re-acceptance legal gate screen for Right Suite desktop apps.

Readme

@rightkit/legal-ui

The first-run and re-acceptance legal gate screen for Right Suite desktop apps. LegalGate renders the document links, an eligibility choice (individual or enterprise), one agreement checkbox, and Agree and Quit buttons.

| Item | Value | |---|---| | Where it runs | App webview UI (React) | | Rust pair | None | | Version | see INDEX.md | | License | MIT OR Apache-2.0 |

LegalGate holds only the form state of the decision (eligibility, checkbox, submit). It renders the documents and agreementStatement the host passes in. It has no dependency on @rightkit/legal and does no manifest validation or receipt logic.

Entry points

| Import | Contents | |---|---| | @rightkit/legal-ui | LegalGate; types LegalGateAgreement, LegalGateDocument, LegalGateEligibilityLabels, LegalGateEligibilityBasis, LegalGateProps, LegalGateTheme, LegalGateVariant | | @rightkit/legal-ui (defaults) | policyGateDocuments(rendered, urls?) maps the @rightkit/legal default policy texts to inline LegalGate documents | | @rightkit/legal-ui/legal-ui.css | Stylesheet. Import it under a strict CSP. |

Peer dependency: react >=18 <21.

Example

import { LegalGate } from "@rightkit/legal-ui";
import "@rightkit/legal-ui/legal-ui.css";

<LegalGate
  theme={{
    bg: "#F7F3EC", surface: "#FFFFFF", border: "#E4DCDA", text: "#272322",
    muted: "#686160", accent: "#DF3400", accentContrast: "#FFFFFF",
    fontDisplay: "Tanker, sans-serif", fontBody: "'Hanken Grotesk', sans-serif",
  }}
  appName="Example App"
  trustLine="Example trust statement."
  documents={[{ title: "License", url: "https://example.com/license/" }]}
  agreementStatement="I have read and agree to the License."
  variant="first-run"
  onAgree={({ eligibilityBasis }) => saveAcceptance(eligibilityBasis)}
  onQuit={() => quit()}
/>

Props: appName, trustLine, documents, agreementStatement, variant, onAgree, onQuit, and optional theme, version, manifestSha256, eligibilityLabels, lockup, dbaLine, tradingNameNotice, parentLogoSrc, wordmarkFontUrl, agreeLabel, showQuit, quitLabel, eyebrow, heading, renderError, onError, footer.

onAgree receives one object, { version, acceptedAt, manifestSha256, eligibilityBasis }; acceptedAt is a UTC ISO string taken at acceptance, and version/manifestSha256 echo the props. It may return a Promise. eligibilityLabels overrides the eligibility copy. lockup replaces the publisher lockup (null hides it). The gate forces no light or dark theme: it sets no data-theme or color-scheme, so pass host tokens (or var(--token) references) in theme and the host's data-theme applies. While it is pending the button shows aria-busy.

Customising the gate (0.2.2)

Every prop below is optional. With none of them set, the gate renders the 0.2.1 screen.

| Prop | Default | Effect | |---|---|---| | agreeLabel | "Agree & continue" | Idle text of the primary button. The pending text stays "Saving…". | | showQuit | true | false removes the Quit button. | | quitLabel | "Quit" | Text of the Quit button. | | tradingNameNotice | the trading-name line (or dbaLine) | string replaces the line; false hides it. | | eyebrow | none | ReactNode shown above the heading. | | heading | the app wordmark | ReactNode replacing the wordmark. | | renderError | "Couldn’t save your acceptance. Try again." | (error: unknown) => ReactNode. Its output replaces the default text inside the same role="alert" container. | | onError | none | (error: unknown) => void. Called with the rejection value when onAgree rejects or throws. | | footer | none | ReactNode rendered below the actions and any error. |

Notes:

  • tradingNameNotice is legal copy. The default line names the trading entity. Hiding or replacing it is the app's decision; the gate does not check the wording.
  • Error handling. A rejection or throw from onAgree shows the alert and re-enables Agree, so the user can retry. onError runs first, so you can log the failure. A throw inside onError is not caught.
  • Empty eligibility descriptions. An option whose description is "" renders no description element. An omitted description keeps the default text, as in 0.2.1. Pass "" to hide it.
<LegalGate
  // ...required props
  agreeLabel="Accept and continue"
  showQuit={false}
  eyebrow="Right Suite Desktop License v1.1"
  heading="Before you use MailRight"
  tradingNameNotice="Example Trading Co is a trading name of Example Ltd."
  renderError={(error) => `Could not save: ${String(error)}`}
  onError={(error) => log("legal.save_failed", error)}
  footer={<a href="mailto:[email protected]">Contact legal</a>}
/>

Known issues

  • Peer React is <21, the same range as doc-render, i18n, media-ui and pdf-ui (package.json:28).
  • Under a strict CSP without 'unsafe-inline', the gate injects no style element only when legal-ui.css is imported. Without the import, the gate injects its layout at runtime and needs style-src 'unsafe-inline'.

Standalone legal documents (Unreleased)

Package root exports LegalDocumentBody & types LegalDocumentBodyProps, LegalContentFormat. Use host layout & styles around its content:

import { LegalDocumentBody } from "@rightkit/legal-ui";

<div className="legal-document">
  <LegalDocumentBody content={documentText} format="markdown" title={viewerTitle} />
</div>

content & format ("markdown" | "text") are required. Optional title omits matching leading Markdown headings when viewer already displays them. Markdown supports headings (h2–h6), paragraphs, lists, rules, emphasis, code & safe http(s)/mailto links. Default markdown: "legacy" matches 0.3.0 output exactly. Opt in with markdown: "extended" to omit HTML comments, keep indented list continuations in their item & honour two-space hard breaks; emphasis spans soft line breaks in both modes. Text mode preserves line breaks inside pre.rk-legal-gate__doc-text. Content is escaped React text; raw HTML is never injected.