Skip to main content
0.0.x

@netscript/fresh-ui

Fresh UI registry seams and interactive foundations for NetScript. This page is written against the package public surface reported by deno doc. For the full index of packages and plugins return to the reference overview.

The root entrypoint (@netscript/fresh-ui) intentionally stays small: copy-based registry components and islands remain on workspace-local deep paths so applications can own and evolve them after copy. The root module exposes only the supported helper utilities that are safe to consume as package runtime dependencies. Five sub-path exports carry the package runtime seams:

Class-name helper

Symbol Signature Description
cn function cn(...inputs: ClassValue[]): string Combines clsx and tailwind-merge for optimal class merging.

Icon primitive

Icon is a first-class stroke-SVG icon primitive, re-exported at the package root alongside its supporting types from @netscript/fresh-ui/primitives.

Symbol Kind Description
Icon component Renders a named stroke-SVG icon (IconName) at a given IconSize, forwarding standard SVG attributes.
ICON_PATHS const The stroke-path lookup table backing every IconName.
IconName / IconSize / IconProps / IconSvgAttributes / IconSvgAttributeValue type aliases / interface Supporting types for the Icon primitive.

DataGrid

DataGrid is a generic, templated data-grid component exported from the package root (@netscript/fresh-ui) — the successor to the earlier DataTable registry block. Unlike the copy-source registry items, DataGrid is a runtime export you import directly; you do not netscript ui:add it. It renders a token-styled role="grid" region from a columns contract and a rows contract, and supports plain, button, and Fresh client-navigation rows.

DataGrid props

Prop Type Description
columns readonly DataGridColumn<T>[] Ordered column definitions (required).
rows readonly DataGridRow<T>[] Ordered row definitions (required).
label string Accessible label applied as aria-label on the grid region.
class string Additional class names appended to the ns-data-grid root.
[attribute: string] unknown Any further native attributes are forwarded to the grid root.

DataGridColumn<T>

Field Type Description
key string Property key used for fallback cell content and stable cell identity.
header string Visible column header text.
width string CSS grid track width, e.g. 2fr or minmax(0, 12rem). Defaults to minmax(0, 1fr).
cell DataGridCellVariant Optional built-in cell treatment: "strong" (bold) or "num" (monospace, right-aligned).
render (row: T) => DataGridRenderable Optional per-column template receiving the row payload.

DataGridRow<T>

Every row carries a stable id, a caller-owned data: T payload, and an optional selected flag. A row renders differently based on which navigation field is present — the three shapes are mutually exclusive (supply at most one of onSelect or href):

Shape Distinguishing field Renders as
Plain neither onSelect nor href a role="row" <div>.
Button onSelect: () => void a role="row" <button> that calls onSelect on click.
Link href: string a role="row" <a f-client-nav> for Fresh client navigation.

DataGrid symbols

Symbol Kind Description
DataGrid component Generic templated data grid; renders DataGridColumn definitions over DataGridRow data.
DATA_GRID_CELL_VARIANTS const The supported cell-treatment names: ["strong", "num"].
DataGridColumn<T> / DataGridProps<T> / DataGridRow<T> interfaces / types Column, props, and row contracts.
DataGridNode / DataGridRenderable / DataGridCellVariant types Structural node, renderable cell content, and the cell-variant union.

DataGrid example

import { DataGrid, type DataGridColumn, type DataGridRow } from "@netscript/fresh-ui";

interface Invoice {
  id: string;
  customer: string;
  total: number;
}

const columns: DataGridColumn<Invoice>[] = [
  { key: "customer", header: "Customer", width: "2fr", cell: "strong" },
  { key: "total", header: "Total", cell: "num", render: (row) => `$${row.total.toFixed(2)}` },
];

const rows: DataGridRow<Invoice>[] = [
  { id: "inv-1", data: { id: "inv-1", customer: "Acme", total: 420 }, href: "/invoices/inv-1" },
  { id: "inv-2", data: { id: "inv-2", customer: "Globex", total: 130 }, selected: true, href: "/invoices/inv-2" },
];

export function InvoiceGrid() {
  return <DataGrid label="Invoices" columns={columns} rows={rows} />;
}

A column with cell: "num" renders monospace and right-aligned; cell: "strong" renders bold. A column without render falls back to row.data[column.key] when that key holds a string, number, bigint, boolean, null, or undefined.

Rows are keyed by id. Supply a stable id per row so Preact can reconcile rows across re-renders, and provide at most one of onSelect or href — the row shapes are mutually exclusive, and a link row navigates through Fresh (f-client-nav) rather than a full page load.

Dropzone (registry component)

Dropzone is a copy-source registry component, not a package export — install it with netscript ui:add dropzone, after which it lives at components/ui/dropzone.tsx in your app and is yours to edit. It renders a dashed file-drop target (<label class="ns-dropzone">) that ingests files from three sources — drag-and-drop, focused clipboard paste, and the native file picker — and filters each ingest through a shared accept / multiple policy before calling back.

Dropzone props

Prop Type Description
label string Primary call-to-action text. Defaults to "Drop files or click to upload".
hint string Secondary hint line (accepted types, size limits).
icon Renderable Leading glyph or icon node. Defaults to .
active boolean Forces the drag-over (data-active) visual state.
accept string Native accept string applied to drop, paste, and picker ingest.
multiple boolean Whether one ingest event may accept more than one file. Defaults to false.
onFile (file: File, details: DropzoneIngestDetails) => void Called with the first accepted file — the simple single-file path.
onFiles (files: readonly File[], details: DropzoneIngestDetails) => void Called with every accepted file.
onReject (files: readonly DropzoneRejectedFile[], details: DropzoneIngestDetails) => void Called with every rejected file.
onDrop / onDragOver / onPaste event handlers Optional passthrough handlers invoked after the built-in ingest runs.
children Renderable Additional content rendered inside the label.
class string Additional class names appended to the ns-dropzone root.

DropzoneProps also extends JSX.HTMLAttributes<HTMLLabelElement> (minus class, onDrop, onDragOver, and onPaste, which the component owns), so standard label attributes pass through.

Dropzone ingest types

Symbol Kind Description
DROPZONE_INGEST_SOURCES const The ingest source names: ["drop", "paste", "picker"].
DROPZONE_REJECTED_REASONS const The rejection reason names: ["type", "too-many"].
DropzoneIngestSource type "drop" | "paste" | "picker".
DropzoneRejectedReason type "type" | "too-many".
DropzoneRejectedFile interface A rejected file, its reason, and the ingest source that supplied it.
DropzoneIngestDetails interface acceptedFiles, rejectedFiles, the ingest source, and the original event.
DropzoneProps interface The full prop contract documented above.

Dropzone example

import { Dropzone, type DropzoneIngestDetails } from "@app/components/ui/dropzone.tsx";

export function AvatarUpload() {
  function handleFiles(files: readonly File[], details: DropzoneIngestDetails) {
    console.log(`Accepted ${files.length} file(s) via ${details.source}`);
    for (const rejected of details.rejectedFiles) {
      console.warn(`Rejected ${rejected.file.name}: ${rejected.reason}`);
    }
  }

  return (
    <Dropzone
      label="Drop images or click to upload"
      hint="PNG or JPG, up to 5 MB"
      accept="image/png,image/jpeg"
      multiple
      onFiles={handleFiles}
    />
  );
}

Rejections are reported, not silent: a file whose type falls outside accept is rejected with reason "type", and — when multiple is false — every file after the first is rejected with reason "too-many". Each ingest also updates a visually-rendered aria-live status node so assistive technology hears how many files were accepted or rejected.

Paste ingest requires focus. Clipboard paste only fires while the dropzone (or a child) holds focus, so pair it with a focusable affordance. The picker <input> clears its value after each selection, so re-selecting the same file still triggers onFile / onFiles.

Redirect-flash (toast) helpers

Symbol Signature Description
getToast function getToast(url: URL): RegistryToast | undefined Reads a toast payload from a URL when redirect-flash query parameters are present.
withToast function withToast(path: string, toast: RegistryToast): string Appends a toast payload to a relative application path.
stripToastFromUrl function stripToastFromUrl(url: URL): string Removes all toast query parameters from a URL while preserving path and hash.
REGISTRY_TOAST_QUERY_KEYS const REGISTRY_TOAST_QUERY_KEYS: { message: string; title: string; type: string } Query-string keys reserved by the redirect-flash helpers.

Toast types

Symbol Kind Description
RegistryToast interface Redirect-flash payload persisted in URL query parameters (message, optional title, type).
RegistryToastType type alias Toast semantic variants: "success" | "error" | "warning" | "info".

Interactive namespaces

Exported from the @netscript/fresh-ui/interactive sub-path. Each is a compound namespace bundling a root component with its structural subcomponents. The namespace types are package-internal (see note below).

Symbol Signature Description
Accordion const Accordion: AccordionNamespace Compound accordion namespace with root and item subcomponents.
Dialog const Dialog: DialogNamespace Compound dialog namespace with root and structural subcomponents.
Drawer const Drawer: DrawerNamespace Compound drawer namespace with root and structural subcomponents.
Popover const Popover: PopoverNamespace Compound popover namespace with root and positioning subcomponents.
Sheet const Sheet: SheetNamespace Compound sheet namespace — side-docked inspection panel.
Tabs const Tabs: TabsNamespace Compound tabs namespace with root, list, trigger, and content subcomponents.
Tooltip const Tooltip: TooltipNamespace Compound tooltip namespace with root and positioning subcomponents.

Surface note: the *Namespace types backing these exports are currently package-internal. deno doc --lint reports them as private-type-ref errors; making them public is planned for a future release. The runtime exports themselves are stable.

L0 primitives

Exported from the @netscript/fresh-ui/primitives sub-path. L0 stays small: prefer Preact intrinsic elements and platform attributes, using these helpers only where they encapsulate real behavior.

Symbol Signature Description
Show function Show<T>({ when, fallback, children }: ShowProps<T>): PrimitiveChildren Conditionally renders children without introducing an extra DOM wrapper.
VisuallyHidden function VisuallyHidden({ children, style, ...props }: VisuallyHiddenProps): PrimitiveNode Renders content for assistive technology while keeping it visually hidden.
SrOnly function SrOnly(props: VisuallyHiddenProps): PrimitiveNode Alias for VisuallyHidden using the common screen-reader naming.

Primitive types

Symbol Kind Description
PrimitiveNode interface Structural node returned by element-producing L0 primitives (type, props, key).
ShowProps<T> interface Props accepted by Show (when, optional fallback, children).
VisuallyHiddenProps interface Props accepted by VisuallyHidden and SrOnly (children, style, arbitrary attributes).
PrimitiveChild type alias Primitive value that can be rendered by an L0 helper.
PrimitiveChildren type alias Renderable content accepted by L0 primitives (a child or readonly array of children).
VisuallyHiddenStyle type alias Inline style accepted by visually-hidden primitives.

Generative UI renderer (@netscript/fresh-ui/ai/render-ui)

Exported from @netscript/fresh-ui/ai/render-ui. This module provides a safe, bounded generative-UI renderer that converts structured render_ui tool payloads into standard Preact DOM nodes.

Input contract: The renderer consumes input already validated by @netscript/ai/tools (RenderUiToolInput). It does not validate arbitrary model output; callers must parse and validate raw model payloads with @netscript/ai/tools before passing them to the renderer.

Allowed block categories

The renderer restricts markup generation to a curated 8-block allowlist across three categories (RENDER_UI_BLOCK_CATEGORIES):

Category Allowed block types Description
layout stack, grid, section Container elements that layout child blocks.
viz chart, metric Visual presentation blocks for stats and trend data.
data table, list, card Data presentation blocks for tabular and item lists.

Depth bounds and fallback reasons

To protect against deeply nested or malformed model payloads, rendering is bounded by maxDepth (defaults to RENDER_UI_MAX_DEPTH = 6). When a payload cannot be rendered safely, a styled fallback element is emitted with a specific RenderUiFallbackReason:

  • 'max-depth': Payload nesting exceeded the configured maximum depth limit.
  • 'unknown-type': Block type is outside the accepted 8-block allowlist.
  • 'invalid-node': Node payload is malformed or unrenderable.

Renderer symbols

Symbol Kind Description
renderUiPayload function function renderUiPayload(payload: RenderUiToolInput, options?: RenderUiOptions): RenderUiNode — Renders a validated payload into safe Preact DOM.
RenderUiSurface component function RenderUiSurface(props: RenderUiSurfaceProps): RenderUiNode — JSX component wrapper around renderUiPayload.
RENDER_UI_MAX_DEPTH const 6 Default maximum recursive block depth.
RENDER_UI_BLOCK_CATEGORIES const Map of accepted categories to block type names (layout, viz, data).
RenderUiToolInput type alias Re-exported validated payload type from @netscript/ai/tools.
RenderUiOptions / RenderUiSurfaceProps interfaces Renderer configuration and component prop contracts (maxDepth, payload).
RenderUiFallbackReason type alias Union of fallback reasons: 'max-depth' | 'unknown-type' | 'invalid-node'.

Renderer example

import { RenderUiSurface, renderUiPayload } from "@netscript/fresh-ui/ai/render-ui";

const payload = {
  component: "section",
  title: "System Performance",
  props: {
    children: [
      {
        type: "grid",
        props: {
          children: [
            {
              type: "metric",
              props: { label: "P99 Latency", value: "24 ms", detail: "healthy" },
            },
            {
              type: "metric",
              props: { label: "Error Rate", value: "0.01%", detail: "normal" },
            },
          ],
        },
      },
      {
        type: "table",
        title: "Active Services",
        props: {
          columns: [
            { key: "name", header: "Service" },
            { key: "status", header: "Status" },
          ],
          rows: [
            { name: "auth-service", status: "healthy" },
            { name: "payment-gateway", status: "healthy" },
          ],
        },
      },
    ],
  },
};

export function PerformanceWidget() {
  return <RenderUiSurface payload={payload} maxDepth={6} />;
}

Sub-path exports

The following 6 entrypoints are published as declared in the package export map:

Export Entrypoint Purpose
@netscript/fresh-ui ./mod.ts Stable runtime helpers (cn, redirect-flash toast helpers, the Icon primitive, and DataGrid — documented above).
@netscript/fresh-ui/ai/render-ui ./src/ai/render-ui.tsx Safe, bounded generative-UI renderer (renderUiPayload, RenderUiSurface, block vocabulary — documented above).
@netscript/fresh-ui/desktop ./desktop.ts Browser-safe native desktop chrome helpers and IPC bridge definitions (createDesktopChrome).
@netscript/fresh-ui/interactive ./interactive.ts Package-owned interactive compound namespaces (Accordion, Dialog, Drawer, Popover, Sheet, Tabs, Tooltip — documented above).
@netscript/fresh-ui/primitives ./primitives.tsx L0 platform-contract primitives (Show, VisuallyHidden, SrOnly — documented above).
@netscript/fresh-ui/registry ./registry.ts Embedded Fresh UI copy-registry manifest and file content (freshUiRegistryManifest, FRESH_UI_REGISTRY_CONTENT).

Back to the reference overview.