-
Notifications
You must be signed in to change notification settings - Fork 45
packages rang overview
@clean-jsdoc-theme/rang is the Preact component library that
dwar server-renders and bundles. It owns every byte
of page-shell HTML — the Layout,
Header,
and Footer —
the hydratable islands that add progressive enhancement, the MDX element →
component map, and the shadcn-style primitives styled with Tailwind utilities
that reference CSS variables.
Note
Why the name? rang (रंग) is Hindi/Sanskrit for color — apt for the package that owns the theme's entire visual surface: layout, components, and styling.
The package depends only on the browser-safe contract package
(@clean-jsdoc-theme/utils) plus
preact, class-variance-authority,
clsx,
tailwind-merge, and
lucide-preact — see
package.json.
If you just want to use the theme, you never install this package. It's an internal building block that dwar bundles for you. See the Packages section for the pieces you actually install.
The pipeline is deliberately split: setu produces a SiteManifest, dwar renders
it, and all the markup lives in rang. Pulling the component layer into its
own package buys the project a clean seam:
-
rang owns the markup; dwar owns the orchestration. dwar's
layout.tsxadds no chrome of its own — itsSsrLayoutcomposes rang'sLayoutthrough itsheaderControls/sidebar/toc/tocMobileslots and does nothing but wrap each interactive component in a<div data-island="…">hydration marker. As that file's own doc comment puts it: "The chrome markup (header, grid shell, asides, footer) lives entirely in rang'sLayout. dwar's only job here is hydration." -
Browser-safe by construction. Components run in the browser, so rang only
imports the node-free
utilscontract — never the build side. The same components render to a string on the server (preact-render-to-string) and hydrate in the browser. -
One styling convention. Components style themselves with Tailwind utility
classes that reference CSS variables (e.g.
bg-background,text-(--clean-fg),border-(--clean-border)). dwar plumbs the theme tokens into those variables on:root, so the same markup re-themes without a recompile. Seelib/cn.ts— the shadcncn()helper that composesclsx+tailwind-mergeso a caller-supplied class always wins a Tailwind conflict.
This is the central distinction in rang.
Chrome is pure, static SSR markup with no client JavaScript. The
Layout
shell — header + a 3-column grid (sidebar · main · toc) + footer — never
references an island itself. It renders whatever nodes the caller drops into its
slots. Header, Footer, and Brand are likewise static.
Islands are the interactive pieces. They render as plain HTML on the server,
then dwar mounts a small per-island JS chunk that hydrates just that subtree —
progressive enhancement, not a whole-page SPA. The full set of islands is the
authoritative ISLAND_REGISTRY in
islands.ts,
a Record<IslandName, ComponentType> keyed by the island name dwar marks the
DOM with:
Island name (IslandName) |
Component |
|---|---|
sidebar |
Sidebar |
mobile-nav |
MobileNav |
toc |
TOC |
toc-mobile |
TocPopover |
cmdk |
CtrlK |
code-tabs |
CodeTabs |
code-viewer |
CodeViewer |
embed |
EmbedBody |
copy-btn |
CopyBtn |
copy-page |
CopyPageButton |
theme-toggle |
ThemeToggle |
settings |
Settings |
tabs |
Tabs |
Two of those entries are worth a note, straight from the registry's own comments:
-
embedmaps toEmbedBody(not theEmbedMDX wrapper): the loader mountsEmbedBodyonto thedata-island="embed"marker and reads its config from the marker'sdata-*attributes. -
tabsis fully SSR-rendered — theTabsmarkup (ARIA tablist + panels) is emitted on the server and only DOM-enhanced on the client (the panel content is arbitrary SSR HTML, so it's enhanced, not re-hydrated). Its entry exists "purely to satisfyRecord<IslandName, …>."
A third group is SSR-only and not islands:
Steps
/ Step (a static numbered stepper) and
PageNav
(the prev/next pager) are pure markup with no client JS — they are exported and
used in MDX/layout, but they never appear in ISLAND_REGISTRY. Heading anchors
are similar: the markup is SSR-only and a delegated inline script handles the
click (see
mdx-utils.tsx).
When dwar compiles a page's MDX, it renders it with rang's
defaultMdxComponents — the element-name → component registry in
mdx-components.tsx.
It maps the intrinsic tags MDX emits (h1–h6, a, img, p, pre, code,
lists, blockquote, tables, hr) onto styled renderers from
mdx-tags.tsx
and
CodeBlock.tsx,
plus the capitalized components setu emits so they route through the map:
Callout, Embed, SourceLink, MemberMeta, MemberHeading, Steps /
Step, and Tabs / Tab. (For the user-facing side of these, see
Callouts and Tabs.)
dwar imports rang both at render time and at bundle time:
-
SSR.
dwar/src/layout.tsximports rang'sLayoutand the chrome islands (Sidebar,MobileNav,TOC,TocPopover,CtrlK,ThemeToggle,Settings), wraps each in adata-islandmarker viarenderIsland, records its props for the per-page payload, and hands the wrapped nodes toLayout's slots. -
Hydration.
dwar/src/islands-bundle.tsruns a single split esbuild build with every island as an entry point. esbuild hoists the code shared across entries (Preact, rang's registry, shared helpers) into onechunk-<hash>.jsthat each island chunk imports — which is what cuts the emitted_islands/payload from ~4.74 MB to ~0.40 MB. The island sources import@clean-jsdoc-theme/rangfrom dwar's ownnode_modules.
The maintainer wants you sent to the code — start here:
- Package directory: packages/rang · packages/rang/src
-
The public barrel:
src/index.ts -
The two registries:
islands.ts(the island name → component map) ·mdx-components.tsx(the MDX element → component map) -
The chrome:
Layout.tsx·Header.tsx·Footer.tsx -
The MDX renderers + styling helper:
mdx-tags.tsx·mdx-utils.tsx·CodeBlock.tsx·lib/cn.ts -
How dwar uses it:
dwar/src/layout.tsx·dwar/src/islands-bundle.ts
- rang Examples — concrete snippets using these exports.
- dwar Overview — the package that renders and bundles rang.
- utils Overview — the browser-safe contract rang imports.
This wiki is auto-generated from docs-site/docs. Edit there — changes sync automatically. Full docs: https://ankdev.me/clean-jsdoc-theme/