@dowel-ui/registry 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/custom.ts","../src/agent-docs.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { z } from \"zod\";\n\nimport { hashContent } from \"./hash\";\nimport {\n REGISTRY_VERSION,\n registryAccessSchema,\n registryIndexSchema,\n registryItemSchema,\n registryItemTypeSchema,\n type RegistryFile,\n type RegistryFileType,\n type RegistryItem,\n} from \"./schema\";\n\n/**\n * Building a registry of your own components.\n *\n * The CLI has always been able to install from any registry — `--registry`\n * takes a URL or a directory — but producing one meant reimplementing this\n * package. So an organisation that wanted its own components installed the same\n * way had the consumer half and none of the producer half.\n *\n * The authoring shape is declared here rather than imported from the component\n * package, because the registry *is* the contract. A team publishing their own\n * components should not have to depend on somebody else's component library to\n * describe their own.\n */\n\n/** Where an item's files are written in the consuming project. */\nexport const itemGroupSchema = z.enum([\"ui\", \"blocks\", \"lib\", \"hooks\"]);\n\nexport type ItemGroup = z.infer<typeof itemGroupSchema>;\n\nconst GROUP_FILE_TYPE: Record<ItemGroup, RegistryFileType> = {\n ui: \"registry:ui\",\n blocks: \"registry:block\",\n lib: \"registry:lib\",\n hooks: \"registry:hook\",\n};\n\nexport const itemSourceSchema = z.object({\n name: z.string().regex(/^[a-z][a-z0-9-]*$/),\n title: z.string().min(1),\n description: z.string().min(10),\n category: z.string().min(1),\n status: z.enum([\"stable\", \"beta\", \"experimental\"]).default(\"stable\"),\n /** Where the files land. Defaults to `ui`. */\n group: itemGroupSchema.default(\"ui\"),\n /** npm packages the source imports. */\n dependencies: z.array(z.string()).default([]),\n /** Other registry items this one imports, upstream ones included. */\n registryDependencies: z.array(z.string()).default([]),\n /** Files to publish, relative to the item's own directory. */\n files: z.array(z.string().min(1)).min(1),\n a11y: z.string().optional(),\n access: registryAccessSchema,\n /**\n * Overrides where the item's directory is, relative to the registry root.\n * Defaults to `<group>/<name>`, which is the layout this repository uses.\n */\n directory: z.string().optional(),\n});\n\nexport type ItemSource = z.input<typeof itemSourceSchema>;\n\nexport const registryConfigSchema = z.object({\n /** Absolute path the item directories are resolved against. */\n root: z.string().min(1),\n items: z.array(itemSourceSchema).min(1),\n /**\n * A registry to layer on top of — a URL, or a directory on disk.\n *\n * The reason a private registry is worth having at all: one URL that serves\n * both the upstream components and yours, so a consumer configures one place\n * and `add` resolves across both.\n */\n extends: z.string().min(1).optional(),\n /** Written into the index, so a consumer can see what produced it. */\n generatedFrom: z.string().min(1).default(\"custom-registry\"),\n});\n\nexport type RegistryConfig = z.input<typeof registryConfigSchema>;\n\n/** Identity helper, for editor autocomplete inside a config file. */\nexport function defineRegistryConfig(config: RegistryConfig): RegistryConfig {\n return config;\n}\n\nexport interface BuildResult {\n items: RegistryItem[];\n /**\n * Names that exist upstream and were replaced by a local item.\n *\n * Reported rather than applied silently. Overriding upstream's Button is a\n * legitimate thing to want and a catastrophic thing to do by accident, and\n * the difference is entirely whether anyone was told.\n */\n overridden: string[];\n /** How many items came from upstream unchanged. */\n inherited: number;\n}\n\n/**\n * Every `@/...` import a source file makes, as `[group, rest]`.\n *\n * Published source is authored against the library's own aliases and rewritten\n * at install time to wherever the consuming project keeps things. Both checks\n * below depend on reading those imports.\n */\nfunction authoredImports(content: string): { group: string; rest: string }[] {\n const found: { group: string; rest: string }[] = [];\n const pattern = /[\"']@\\/(components|lib|hooks|blocks)\\/([^\"']+)[\"']/g;\n\n for (const match of content.matchAll(pattern)) {\n if (match[1] && match[2]) found.push({ group: match[1], rest: match[2] });\n }\n\n return found;\n}\n\n/**\n * Catches source written against the *installed* paths instead of the authored\n * ones.\n *\n * `@/components/ui/badge` looks right — it is where the file ends up — and\n * rewrites to `@/components/ui/ui/badge`, because the rewriter maps\n * `@/components/` to wherever the project keeps its components. The result\n * compiles nowhere and the doubled segment is easy to stare past. The authored\n * form is `@/components/badge`.\n */\nfunction assertAuthoredPaths(name: string, content: string): void {\n const groups = new Set<string>([\"ui\", \"blocks\", \"lib\", \"hooks\"]);\n\n const mistaken = authoredImports(content)\n .filter((entry) => groups.has(entry.rest.split(\"/\")[0] ?? \"\"))\n .map((entry) => `@/${entry.group}/${entry.rest}`);\n\n if (mistaken.length > 0) {\n throw new Error(\n `Item \"${name}\" imports from an installed path rather than an authored one:\\n` +\n ` ${[...new Set(mistaken)].join(\"\\n \")}\\n` +\n \"Write `@/components/badge`, not `@/components/ui/badge` — the leading group is \" +\n \"rewritten to wherever the consuming project keeps its components, so naming it \" +\n \"twice produces a path that resolves nowhere.\",\n );\n }\n}\n\n/**\n * Catches a component importing something it never declared.\n *\n * The undeclared dependency is not installed alongside it, so the install\n * succeeds and the project fails to build — in someone else's repository, where\n * it is hardest to trace back to here.\n */\nfunction assertDeclaredDependencies(\n source: z.infer<typeof itemSourceSchema>,\n content: string,\n): void {\n const declared = new Set([...source.registryDependencies, source.name]);\n\n const undeclared = authoredImports(content)\n .filter((entry) => entry.group === \"components\" || entry.group === \"blocks\")\n // `@/lib/utils` and `@/lib/styles` are written by `init`, so they are\n // present before any component is and are never declared.\n .map((entry) => entry.rest.split(\"/\")[0] ?? \"\")\n .filter((imported) => imported.length > 0 && !declared.has(imported));\n\n if (undeclared.length > 0) {\n throw new Error(\n `Item \"${source.name}\" imports ${[...new Set(undeclared)].join(\", \")} but does not ` +\n \"list them in registryDependencies. They would not be installed alongside it, and \" +\n \"the failure would surface as a build error in the consuming project.\",\n );\n }\n}\n\nfunction toItem(root: string, source: z.infer<typeof itemSourceSchema>): RegistryItem {\n const directory = source.directory ?? join(source.group, source.name);\n const itemDir = join(root, directory);\n\n const files: RegistryFile[] = source.files.map((file) => {\n const path = join(itemDir, file);\n if (!existsSync(path)) {\n throw new Error(\n `Item \"${source.name}\" lists ${file}, but ${path} does not exist. ` +\n \"A registry that names a file it cannot read produces a broken install \" +\n \"in someone else's project, where it is hardest to diagnose.\",\n );\n }\n\n const content = readFileSync(path, \"utf8\");\n assertAuthoredPaths(source.name, content);\n assertDeclaredDependencies(source, content);\n\n return {\n path: `${source.group}/${file}`,\n type: GROUP_FILE_TYPE[source.group],\n content,\n hash: hashContent(content),\n };\n });\n\n return registryItemSchema.parse({\n registryVersion: REGISTRY_VERSION,\n name: source.name,\n type: registryItemTypeSchema.parse(GROUP_FILE_TYPE[source.group]),\n title: source.title,\n description: source.description,\n category: source.category,\n status: source.status,\n dependencies: source.dependencies,\n registryDependencies: source.registryDependencies,\n files,\n a11y: source.a11y,\n access: source.access,\n });\n}\n\nasync function readUpstream(base: string): Promise<RegistryItem[]> {\n const isHttp = base.startsWith(\"http://\") || base.startsWith(\"https://\");\n\n const load = async (file: string): Promise<unknown> => {\n if (!isHttp) {\n const root = base.startsWith(\"file:\") ? fileURLToPath(base) : base;\n const path = join(root, file);\n if (!existsSync(path)) throw new Error(`Upstream registry has no ${file} at ${path}.`);\n return JSON.parse(readFileSync(path, \"utf8\"));\n }\n\n const url = `${base.replace(/\\/$/, \"\")}/${file}`;\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Upstream registry returned ${String(response.status)} for ${url}.`);\n }\n return await response.json();\n };\n\n const index = registryIndexSchema.parse(await load(\"index.json\"));\n\n const items: RegistryItem[] = [];\n for (const entry of index.items) {\n // Licensed upstream items have no public body to inherit. They stay out of\n // the derived registry rather than appearing in it as something that cannot\n // be fetched, which would fail at install time instead of at build time.\n if (entry.access === \"pro\") continue;\n items.push(registryItemSchema.parse(await load(`${entry.name}.json`)));\n }\n\n return items;\n}\n\n/**\n * Every `registryDependencies` name must exist in the finished registry.\n *\n * Checked here, once, rather than discovered by a consumer whose `add` walks\n * into a name nothing serves. This is the single most common way a\n * hand-assembled registry is broken, and it is invisible until someone installs.\n */\nexport function assertResolvable(items: RegistryItem[]): void {\n const known = new Set(items.map((item) => item.name));\n const missing: string[] = [];\n\n for (const item of items) {\n for (const dependency of item.registryDependencies) {\n if (!known.has(dependency)) missing.push(`${item.name} → ${dependency}`);\n }\n }\n\n if (missing.length > 0) {\n throw new Error(\n `These registry dependencies are not in the registry:\\n ${missing.join(\"\\n \")}\\n` +\n \"Add them, or extend a registry that has them.\",\n );\n }\n}\n\nexport async function buildCustomRegistry(config: RegistryConfig): Promise<BuildResult> {\n const parsed = registryConfigSchema.parse(config);\n const local = parsed.items.map((item) => toItem(parsed.root, item));\n\n const duplicates = local\n .map((item) => item.name)\n .filter((name, index, all) => all.indexOf(name) !== index);\n if (duplicates.length > 0) {\n throw new Error(`Declared more than once: ${[...new Set(duplicates)].join(\", \")}.`);\n }\n\n if (!parsed.extends) {\n assertResolvable(local);\n return { items: local, overridden: [], inherited: 0 };\n }\n\n const upstream = await readUpstream(parsed.extends);\n const localNames = new Set(local.map((item) => item.name));\n const overridden = upstream\n .filter((item) => localNames.has(item.name))\n .map((item) => item.name);\n\n // Local wins. That is the point of extending rather than mirroring: an\n // organisation replaces the components it has opinions about and inherits the\n // rest.\n const inherited = upstream.filter((item) => !localNames.has(item.name));\n const items = [...inherited, ...local].sort((a, b) => a.name.localeCompare(b.name));\n\n assertResolvable(items);\n\n return { items, overridden, inherited: inherited.length };\n}\n","import type { RegistryIndex, RegistryIndexEntry, RegistryItem } from \"./schema\";\n\n/**\n * Documentation written for coding agents rather than for people.\n *\n * This lives beside the registry rather than in the CLI or the docs site\n * because all three need to emit the same text: the CLI writes it into a\n * consumer's repository, the site serves it at /llms.txt, and the MCP server\n * answers with it. Three hand-maintained copies would disagree within a\n * release, and an agent acting on a stale catalogue writes code that does not\n * compile.\n *\n * Everything here is derived from the registry index. Nothing is a hardcoded\n * list of component names — that is the failure mode this replaces.\n */\n\nexport interface AgentDocsContext {\n index: RegistryIndex;\n /**\n * Full registry items, when the caller has them.\n *\n * The index carries no accessibility notes, so callers that can afford to\n * fetch every item (the docs build, the MCP server) get richer output than\n * ones that cannot (the CLI, which would otherwise make 81 requests).\n */\n items?: RegistryItem[];\n /** Base URL the CLI installs from. */\n registryUrl: string;\n /** Base URL of the documentation site, no trailing slash. */\n docsUrl: string;\n /** npm package name of the CLI, e.g. `@dowel-ui/cli`. */\n cliPackage: string;\n libraryName: string;\n /** Registry names already present in the project, if known. */\n installed?: string[];\n /**\n * What components are imported from in this project.\n *\n * Source-first installs resolve to the project's own alias; the published\n * package is a separate, supported way to consume the same components. An\n * agent told the wrong one writes imports that do not resolve.\n */\n importFrom: string;\n}\n\nconst CATEGORY_LABELS: Record<string, string> = {\n foundation: \"Foundation\",\n form: \"Forms\",\n overlay: \"Overlays\",\n navigation: \"Navigation\",\n display: \"Display\",\n data: \"Data\",\n feedback: \"Feedback\",\n layout: \"Layout\",\n ai: \"AI\",\n};\n\nconst CATEGORY_ORDER = [\n \"foundation\",\n \"form\",\n \"overlay\",\n \"navigation\",\n \"display\",\n \"data\",\n \"feedback\",\n \"layout\",\n \"ai\",\n];\n\nfunction label(category: string): string {\n return CATEGORY_LABELS[category] ?? category;\n}\n\n/** Ordered by curation where curated, alphabetical for anything new. */\nfunction categoriesOf(entries: RegistryIndexEntry[]): string[] {\n const present = new Set(entries.map((entry) => entry.category));\n const known = CATEGORY_ORDER.filter((category) => present.has(category));\n const rest = [...present].filter((category) => !CATEGORY_ORDER.includes(category)).sort();\n return [...known, ...rest];\n}\n\nfunction byType(index: RegistryIndex, type: RegistryIndexEntry[\"type\"]): RegistryIndexEntry[] {\n return index.items\n .filter((entry) => entry.type === type)\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction components(index: RegistryIndex) {\n return byType(index, \"registry:ui\");\n}\n\nfunction blocks(index: RegistryIndex) {\n return byType(index, \"registry:block\");\n}\n\n/**\n * Accessibility rules that differ from what a model has seen elsewhere.\n *\n * An agent trained on every other React library will reach for `disabled` on a\n * loading button and a live region on every alert. Stating only the deltas is\n * deliberate: a general accessibility lecture is ignored, a short list of\n * \"here this is different\" is followed.\n */\nconst ACCESSIBILITY_DELTAS = [\n \"A loading `Button` uses `aria-disabled` + `aria-busy` and guards its own click handler. Never add `disabled` to it — disabling a control mid-action strands keyboard focus.\",\n '`Alert` is not a live region by default. One that exists on first paint announces for no reason. Opt in with `live=\"polite\"` or `live=\"assertive\"` only when the alert appears in response to something.',\n \"`Separator`, `Skeleton` and `Spinner` are decorative and stay out of the accessibility tree unless given a label. Do not add `role` or `aria-label` to them by reflex.\",\n '`PopoverContent` carries `role=\"dialog\"` and warns in development without an accessible name. Always give it `aria-label` or `aria-labelledby`.',\n \"Never use colour as the only signal. The `monochrome` preset exists as a standing check on exactly this — if a state is unreadable under it, the component is wrong.\",\n];\n\nconst TOKEN_RULES = [\n \"Use semantic tokens (`bg-background`, `text-foreground`, `border-border`, `ring-ring`, `bg-primary`, `text-muted-foreground`). Never raw hex, and never Tailwind's own palette (`bg-slate-900`, `text-gray-500`) — those do not follow the theme and break every preset and dark mode.\",\n \"Spacing, radius and type come from the scale. `rounded-md` and `rounded-lg` re-proportion with `--radius-scale`; an arbitrary `rounded-[7px]` does not.\",\n \"Durations derive from `--motion-scale`. Do not hardcode transition timings.\",\n \"Compose class names with `cn()` from the project's utils, so consumer overrides win over defaults.\",\n];\n\nexport function conventionsDoc(context: AgentDocsContext): string {\n const { libraryName, cliPackage, importFrom, docsUrl } = context;\n\n return `# ${libraryName} — conventions\n\nRules for writing code in this project. ${libraryName} is **source-first**: its\ncomponents are files in this repository, not a dependency you can reason about\nfrom its README. They are yours to edit, and edits are preserved across updates.\n\n## The rule that matters most\n\n**Do not hand-write a component that ${libraryName} already has.** Check the\ncatalogue in \\`components.md\\` first. Writing a second Button — with different\nfocus rings, different disabled semantics, different tokens — is the single\nmost common and most damaging thing to do here.\n\n## Adding a component\n\n\\`\\`\\`bash\nnpx ${cliPackage} add <name>\n\\`\\`\\`\n\nThis writes the source into the project and installs whatever it depends on.\n\\`add\\` is safe to re-run: an untouched file is left alone, an edited one is\nnever overwritten without \\`--overwrite\\`.\n\nDo not \\`npm install\\` a component. Do not copy source out of the documentation\nby hand — the CLI resolves the dependency graph and rewrites imports to this\nproject's path alias, and doing it manually gets both wrong.\n\n## Importing\n\n\\`\\`\\`tsx\nimport { Button, Card, CardContent } from \"${importFrom}\";\n\\`\\`\\`\n\n## Styling\n\n${TOKEN_RULES.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Accessibility\n\nTargeted at WCAG 2.2 AA, verified with axe per component. Where ${libraryName}\ndiffers from what you have seen in other libraries:\n\n${ACCESSIBILITY_DELTAS.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Before you build a page\n\nCheck \\`components.md\\` for a **block** that already covers it. A block is a\nwhole section — a login form, a settings page, a chat surface — and installing\none brings every component it is assembled from. Building a dashboard out of\nindividual primitives when \\`add dashboard\\` exists is wasted work.\n\n## Reference\n\n- Documentation: ${docsUrl}\n- Full text for models: ${docsUrl}/llms-full.txt\n`;\n}\n\nexport function componentsDoc(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, installed } = context;\n const have = new Set(installed ?? []);\n const known = installed !== undefined;\n const ui = components(index);\n const blk = blocks(index);\n\n const lines: string[] = [\n `# ${libraryName} — catalogue`,\n \"\",\n `${String(ui.length)} components and ${String(blk.length)} blocks, generated from ` +\n `\\`${index.generatedFrom}\\`. This is the complete list — anything not here does not exist.`,\n \"\",\n ];\n\n if (known) {\n lines.push(\n \"`✓` marks what is already installed in this project. Everything else needs\",\n `\\`npx ${cliPackage} add <name>\\` before it can be imported.`,\n \"\",\n );\n }\n\n const mark = (entry: RegistryIndexEntry) =>\n known ? (have.has(entry.name) ? \"✓ \" : \" \") : \"\";\n\n for (const category of categoriesOf(ui)) {\n lines.push(`## ${label(category)}`, \"\");\n for (const entry of ui.filter((item) => item.category === category)) {\n const status = entry.status === \"stable\" ? \"\" : ` _(${entry.status})_`;\n lines.push(`- ${mark(entry)}**${entry.name}** — ${entry.description}${status}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\n \"## Blocks\",\n \"\",\n \"Whole sections. Installing one installs every component it is built from.\",\n \"\",\n );\n for (const entry of blk) {\n const deps = entry.registryDependencies.length;\n const resolves = deps > 0 ? ` _(resolves ${String(deps)} components)_` : \"\";\n lines.push(`- ${mark(entry)}**${entry.name}** — ${entry.description}${resolves}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\nexport function aiDoc(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage } = context;\n const ai = components(index).filter((entry) => entry.category === \"ai\");\n\n return `# ${libraryName} — AI components\n\n${String(ai.length)} surfaces for AI features. Reach for these before building\nanything custom for a model-facing interface.\n\nMost component sets ship a chat transcript and stop. Real AI features are\nextraction, enrichment, autofill and agents that *change things* — so the parts\nthat matter are the ones around the transcript, not the transcript itself.\n\n${ai.map((entry) => `- **${entry.name}** — ${entry.description}`).join(\"\\n\")}\n\n## Choosing between them\n\n- Rendering a conversation → \\`ai-conversation\\` with \\`ai-message\\` and \\`ai-response\\`.\n- The composer → \\`ai-prompt-input\\`, with \\`ai-model-selector\\` if the model is switchable.\n- A tool the model called → \\`ai-tool\\`. Its arguments and result belong there, not in prose.\n- Asking permission *before* a tool runs → \\`ai-approval-request\\`.\n- Reporting what it did *after* → \\`ai-action-ledger\\`, which is also where reversibility belongs. A deletion can be undone, a refund can only be offset, a sent email cannot be taken back — the ledger is where that distinction is shown.\n- An object streaming in field by field → \\`ai-structured-output\\`, which reserves layout up front so nothing jumps.\n- Ghost text in a real textarea → \\`ai-inline-completion\\`. Escape always returns Tab to focus management, so a keyboard user is never trapped.\n- A value the model proposes for a form field → \\`ai-suggested-value\\`.\n- Reviewing what was pulled out of a document → \\`ai-extraction-review\\`.\n- Long-running work → \\`ai-agent-status\\` and \\`ai-agent-plan\\`.\n- Where an answer came from → \\`ai-sources\\`. Cost → \\`ai-token-usage\\`. Chain of thought → \\`ai-reasoning\\`.\n\n## Whole surface at once\n\n\\`\\`\\`bash\nnpx ${cliPackage} add ai-chat\n\\`\\`\\`\n`;\n}\n\nexport function themesDoc(context: AgentDocsContext): string {\n const { libraryName } = context;\n\n return `# ${libraryName} — theming\n\nTokens are two-tier. **Tier 1** is raw scales: an OKLCH neutral ramp, a radius\nladder, a 15px-base type scale, elevation, motion. **Tier 2** is semantic\naliases — \\`--primary\\`, \\`--background\\`, \\`--border\\`, \\`--ring\\` — and components\nconsume Tier 2 *exclusively*.\n\nRe-skinning the system means reassigning Tier 2. It never means editing a\ncomponent file. If you find yourself changing a colour inside a component, the\nchange belongs in the token layer instead.\n\n## Presets\n\n\\`default\\`, \\`ocean\\`, \\`emerald\\`, \\`violet\\`, \\`rose\\`, \\`amber\\`, \\`monochrome\\`.\n\n\\`\\`\\`html\n<html data-theme=\"ocean\" class=\"dark\">\n\\`\\`\\`\n\n\\`data-theme\\` selects the preset; the \\`dark\\` class selects the mode. They are\nindependent — every preset works in both.\n\n\\`monochrome\\` is not only a style. It is a standing check that no component uses\ncolour as its only signal, so verify new work under it.\n\n## Two properties that re-proportion everything\n\n- \\`--radius-scale\\` — one multiplier behind every corner in the system. \\`1\\` is the designed default, \\`0\\` is fully square.\n- \\`--motion-scale\\` — one multiplier every duration derives from. Under \\`prefers-reduced-motion\\` it collapses, but indicators that report ongoing state are *slowed* rather than stopped via \\`--motion-scale-indicator\\`, because a frozen spinner reads as a hung application.\n\n## Contrast\n\nAll semantic pairs are verified against WCAG 2.2 AA across both modes and every\npreset, in CI. A new token pair has to pass the same check — do not introduce\none without running \\`audit:contrast\\`.\n`;\n}\n\n/** Frontmatter-carrying skill file for Claude Code. */\nexport function skillDoc(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, importFrom } = context;\n const ui = components(index);\n const blk = blocks(index);\n const names = ui.map((entry) => entry.name).join(\", \");\n\n return `---\nname: ${libraryName.toLowerCase()}-ui\ndescription: >-\n Build React interfaces with ${libraryName}, the source-first component system\n installed in this project. Use whenever writing or editing React UI here —\n any button, form, dialog, table, dashboard or AI surface. Covers the\n ${String(ui.length)}-component catalogue, the ${String(blk.length)} blocks, design tokens, theming\n and the accessibility rules that differ from other libraries.\n---\n\n# ${libraryName}\n\nSource-first React components. They are **files in this repository**, not a\ndependency — installed with a CLI, then owned and edited like any other code.\n\n## Do this first\n\nNever hand-write a component ${libraryName} already has. The catalogue:\n\n${names}\n\nBlocks (whole sections, each resolving its own components):\n${blk.map((entry) => entry.name).join(\", \")}\n\n## Adding one\n\n\\`\\`\\`bash\nnpx ${cliPackage} add button card dialog\n\\`\\`\\`\n\nResolves dependencies, installs npm packages, rewrites imports to this\nproject's alias. Safe to re-run — it will not overwrite a file you have edited\nwithout \\`--overwrite\\`.\n\n## Importing\n\n\\`\\`\\`tsx\nimport { Button, Card, CardContent } from \"${importFrom}\";\n\\`\\`\\`\n\n## Styling rules\n\n${TOKEN_RULES.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Accessibility rules that differ here\n\n${ACCESSIBILITY_DELTAS.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Reference files\n\n- \\`.dowel/components.md\\` — the full catalogue with descriptions\n- \\`.dowel/ai.md\\` — the AI components and when to use each\n- \\`.dowel/themes.md\\` — tokens, presets, radius and motion scales\n- \\`.dowel/conventions.md\\` — the rules above, in full\n`;\n}\n\n/** Cursor project rule (`.cursor/rules/*.mdc`). */\nexport function cursorRule(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, importFrom } = context;\n const ui = components(index);\n\n return `---\ndescription: ${libraryName} component system — use for all React UI in this project\nglobs: [\"**/*.tsx\", \"**/*.jsx\"]\nalwaysApply: false\n---\n\n${libraryName} is source-first: its ${String(ui.length)} components are files in this\nrepository. Never hand-write one that already exists.\n\nAdd: \\`npx ${cliPackage} add <name>\\`\nImport: \\`import { Button } from \"${importFrom}\"\\`\n\nAvailable: ${ui.map((entry) => entry.name).join(\", \")}\n\n${TOKEN_RULES.map((rule) => `- ${rule}`).join(\"\\n\")}\n${ACCESSIBILITY_DELTAS.map((rule) => `- ${rule}`).join(\"\\n\")}\n\nFull catalogue and reasoning: \\`.dowel/\\`\n`;\n}\n\nexport const AGENTS_MARKER_START = \"<!-- dowel:start -->\";\nexport const AGENTS_MARKER_END = \"<!-- dowel:end -->\";\n\n/**\n * The block written into a project's AGENTS.md.\n *\n * Marker-wrapped rather than written as a whole file: AGENTS.md belongs to the\n * project and usually already says things about the project. Replacing it would\n * destroy that; appending without markers would duplicate the section on every\n * regeneration.\n */\nexport function agentsSection(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, importFrom } = context;\n const ui = components(index);\n\n return `${AGENTS_MARKER_START}\n\n## UI components — ${libraryName}\n\nThis project uses ${libraryName}, a **source-first** component system: its\n${String(ui.length)} components live in this repository as editable files.\n\n- **Never hand-write a component that already exists.** The full catalogue is in \\`.dowel/components.md\\`.\n- Add one with \\`npx ${cliPackage} add <name>\\` — never \\`npm install\\`, never copy source by hand.\n- Import from \\`${importFrom}\\`.\n- Style with semantic tokens only (\\`bg-background\\`, \\`text-muted-foreground\\`), never raw hex and never Tailwind's own palette.\n- Building a page? Check \\`.dowel/components.md\\` for a **block** first.\n- Building an AI feature? \\`.dowel/ai.md\\` lists surfaces you will not find elsewhere.\n- Accessibility deltas from other libraries are in \\`.dowel/conventions.md\\`. Read them before adding ARIA by reflex.\n\n${AGENTS_MARKER_END}`;\n}\n\n/** Replaces the marked block, or appends it if there is none. */\nexport function upsertAgentsSection(existing: string, section: string): string {\n const start = existing.indexOf(AGENTS_MARKER_START);\n const end = existing.indexOf(AGENTS_MARKER_END);\n\n if (start !== -1 && end !== -1 && end > start) {\n return existing.slice(0, start) + section + existing.slice(end + AGENTS_MARKER_END.length);\n }\n\n const base = existing.trimEnd();\n return base.length > 0 ? `${base}\\n\\n${section}\\n` : `${section}\\n`;\n}\n\n/**\n * The llms.txt index.\n *\n * Deliberately a map rather than a dump: it names every component and points at\n * the one URL that carries everything, so a model with a small budget can find\n * the right page and one with a large budget can take the lot.\n */\nexport function llmsTxt(context: AgentDocsContext): string {\n const { index, libraryName, docsUrl, cliPackage } = context;\n const ui = components(index);\n const blk = blocks(index);\n\n const lines = [\n `# ${libraryName}`,\n \"\",\n `> Source-first React components for SaaS and AI products. ${String(ui.length)} components ` +\n `and ${String(blk.length)} blocks, installed as code you own rather than imported from a ` +\n `dependency. Built on Tailwind v4 and OKLCH design tokens, targeted at WCAG 2.2 AA.`,\n \"\",\n `Install: \\`npx ${cliPackage} add <name>\\` writes the component's source into your project.`,\n \"Re-running is safe — files you have edited are never overwritten without `--overwrite`.\",\n \"\",\n `Generated from ${index.generatedFrom}.`,\n \"\",\n \"## Start here\",\n \"\",\n `- [Everything, in one file](${docsUrl}/llms-full.txt): the complete catalogue with descriptions, accessibility notes and conventions`,\n `- [Installation](${docsUrl}/docs/installation)`,\n `- [CLI](${docsUrl}/docs/cli)`,\n `- [Theming](${docsUrl}/docs/themes)`,\n `- [Accessibility](${docsUrl}/docs/accessibility)`,\n \"\",\n ];\n\n for (const category of categoriesOf(ui)) {\n lines.push(`## ${label(category)}`, \"\");\n for (const entry of ui.filter((item) => item.category === category)) {\n lines.push(\n `- [${entry.name}](${docsUrl}/docs/components/${entry.name}): ${entry.description}`,\n );\n }\n lines.push(\"\");\n }\n\n lines.push(\"## Blocks\", \"\");\n for (const entry of blk) {\n lines.push(`- [${entry.name}](${docsUrl}/docs/blocks/${entry.name}): ${entry.description}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Everything an agent needs, in one request. */\nexport function llmsFullTxt(context: AgentDocsContext): string {\n const { index, items, libraryName, docsUrl } = context;\n const detail = new Map((items ?? []).map((item) => [item.name, item]));\n\n const parts = [\n conventionsDoc(context),\n componentsDoc({ ...context, installed: undefined }),\n aiDoc(context),\n themesDoc(context),\n ];\n\n const lines = [\n `# ${libraryName} — full reference`,\n \"\",\n `Generated from ${index.generatedFrom}. Canonical source: ${docsUrl}`,\n \"\",\n \"---\",\n \"\",\n parts.join(\"\\n---\\n\\n\"),\n ];\n\n if (detail.size > 0) {\n lines.push(\"---\", \"\", \"# Per-component detail\", \"\");\n\n for (const entry of components(index)) {\n const item = detail.get(entry.name);\n lines.push(`## ${entry.title} \\`${entry.name}\\``, \"\", entry.description, \"\");\n lines.push(\n `- Category: ${label(entry.category)} · Status: ${entry.status}`,\n `- Install: \\`add ${entry.name}\\``,\n );\n if (entry.registryDependencies.length > 0) {\n lines.push(`- Also installs: ${entry.registryDependencies.join(\", \")}`);\n }\n if (entry.dependencies.length > 0) {\n lines.push(`- npm: ${entry.dependencies.join(\", \")}`);\n }\n if (item?.a11y) {\n lines.push(`- Accessibility: ${item.a11y}`);\n }\n lines.push(\"\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/custom.ts","../src/agent-docs.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { z } from \"zod\";\n\nimport { hashContent } from \"./hash\";\nimport {\n REGISTRY_VERSION,\n registryAccessSchema,\n registryIndexSchema,\n registryItemSchema,\n registryItemTypeSchema,\n type RegistryFile,\n type RegistryFileType,\n type RegistryItem,\n} from \"./schema\";\n\n/**\n * Building a registry of your own components.\n *\n * The CLI has always been able to install from any registry — `--registry`\n * takes a URL or a directory — but producing one meant reimplementing this\n * package. So an organisation that wanted its own components installed the same\n * way had the consumer half and none of the producer half.\n *\n * The authoring shape is declared here rather than imported from the component\n * package, because the registry *is* the contract. A team publishing their own\n * components should not have to depend on somebody else's component library to\n * describe their own.\n */\n\n/** Where an item's files are written in the consuming project. */\nexport const itemGroupSchema = z.enum([\"ui\", \"blocks\", \"lib\", \"hooks\"]);\n\nexport type ItemGroup = z.infer<typeof itemGroupSchema>;\n\nconst GROUP_FILE_TYPE: Record<ItemGroup, RegistryFileType> = {\n ui: \"registry:ui\",\n blocks: \"registry:block\",\n lib: \"registry:lib\",\n hooks: \"registry:hook\",\n};\n\nexport const itemSourceSchema = z.object({\n name: z.string().regex(/^[a-z][a-z0-9-]*$/),\n title: z.string().min(1),\n description: z.string().min(10),\n category: z.string().min(1),\n status: z.enum([\"stable\", \"beta\", \"experimental\"]).default(\"stable\"),\n /** Where the files land. Defaults to `ui`. */\n group: itemGroupSchema.default(\"ui\"),\n /** npm packages the source imports. */\n dependencies: z.array(z.string()).default([]),\n /** Other registry items this one imports, upstream ones included. */\n registryDependencies: z.array(z.string()).default([]),\n /** Files to publish, relative to the item's own directory. */\n files: z.array(z.string().min(1)).min(1),\n a11y: z.string().optional(),\n access: registryAccessSchema,\n /**\n * Overrides where the item's directory is, relative to the registry root.\n * Defaults to `<group>/<name>`, which is the layout this repository uses.\n */\n directory: z.string().optional(),\n});\n\nexport type ItemSource = z.input<typeof itemSourceSchema>;\n\nexport const registryConfigSchema = z.object({\n /** Absolute path the item directories are resolved against. */\n root: z.string().min(1),\n items: z.array(itemSourceSchema).min(1),\n /**\n * A registry to layer on top of — a URL, or a directory on disk.\n *\n * The reason a private registry is worth having at all: one URL that serves\n * both the upstream components and yours, so a consumer configures one place\n * and `add` resolves across both.\n */\n extends: z.string().min(1).optional(),\n /** Written into the index, so a consumer can see what produced it. */\n generatedFrom: z.string().min(1).default(\"custom-registry\"),\n});\n\nexport type RegistryConfig = z.input<typeof registryConfigSchema>;\n\n/** Identity helper, for editor autocomplete inside a config file. */\nexport function defineRegistryConfig(config: RegistryConfig): RegistryConfig {\n return config;\n}\n\nexport interface BuildResult {\n items: RegistryItem[];\n /**\n * Names that exist upstream and were replaced by a local item.\n *\n * Reported rather than applied silently. Overriding upstream's Button is a\n * legitimate thing to want and a catastrophic thing to do by accident, and\n * the difference is entirely whether anyone was told.\n */\n overridden: string[];\n /** How many items came from upstream unchanged. */\n inherited: number;\n}\n\n/**\n * Every `@/...` import a source file makes, as `[group, rest]`.\n *\n * Published source is authored against the library's own aliases and rewritten\n * at install time to wherever the consuming project keeps things. Both checks\n * below depend on reading those imports.\n */\nfunction authoredImports(content: string): { group: string; rest: string }[] {\n const found: { group: string; rest: string }[] = [];\n const pattern = /[\"']@\\/(components|lib|hooks|blocks)\\/([^\"']+)[\"']/g;\n\n for (const match of content.matchAll(pattern)) {\n if (match[1] && match[2]) found.push({ group: match[1], rest: match[2] });\n }\n\n return found;\n}\n\n/**\n * Catches source written against the *installed* paths instead of the authored\n * ones.\n *\n * `@/components/ui/badge` looks right — it is where the file ends up — and\n * rewrites to `@/components/ui/ui/badge`, because the rewriter maps\n * `@/components/` to wherever the project keeps its components. The result\n * compiles nowhere and the doubled segment is easy to stare past. The authored\n * form is `@/components/badge`.\n */\nfunction assertAuthoredPaths(name: string, content: string): void {\n const groups = new Set<string>([\"ui\", \"blocks\", \"lib\", \"hooks\"]);\n\n const mistaken = authoredImports(content)\n .filter((entry) => groups.has(entry.rest.split(\"/\")[0] ?? \"\"))\n .map((entry) => `@/${entry.group}/${entry.rest}`);\n\n if (mistaken.length > 0) {\n throw new Error(\n `Item \"${name}\" imports from an installed path rather than an authored one:\\n` +\n ` ${[...new Set(mistaken)].join(\"\\n \")}\\n` +\n \"Write `@/components/badge`, not `@/components/ui/badge` — the leading group is \" +\n \"rewritten to wherever the consuming project keeps its components, so naming it \" +\n \"twice produces a path that resolves nowhere.\",\n );\n }\n}\n\n/**\n * Catches a component importing something it never declared.\n *\n * The undeclared dependency is not installed alongside it, so the install\n * succeeds and the project fails to build — in someone else's repository, where\n * it is hardest to trace back to here.\n */\nfunction assertDeclaredDependencies(\n source: z.infer<typeof itemSourceSchema>,\n content: string,\n): void {\n const declared = new Set([...source.registryDependencies, source.name]);\n\n const undeclared = authoredImports(content)\n .filter((entry) => entry.group === \"components\" || entry.group === \"blocks\")\n // `@/lib/utils` and `@/lib/styles` are written by `init`, so they are\n // present before any component is and are never declared.\n .map((entry) => entry.rest.split(\"/\")[0] ?? \"\")\n .filter((imported) => imported.length > 0 && !declared.has(imported));\n\n if (undeclared.length > 0) {\n throw new Error(\n `Item \"${source.name}\" imports ${[...new Set(undeclared)].join(\", \")} but does not ` +\n \"list them in registryDependencies. They would not be installed alongside it, and \" +\n \"the failure would surface as a build error in the consuming project.\",\n );\n }\n}\n\nfunction toItem(root: string, source: z.infer<typeof itemSourceSchema>): RegistryItem {\n const directory = source.directory ?? join(source.group, source.name);\n const itemDir = join(root, directory);\n\n const files: RegistryFile[] = source.files.map((file) => {\n const path = join(itemDir, file);\n if (!existsSync(path)) {\n throw new Error(\n `Item \"${source.name}\" lists ${file}, but ${path} does not exist. ` +\n \"A registry that names a file it cannot read produces a broken install \" +\n \"in someone else's project, where it is hardest to diagnose.\",\n );\n }\n\n const content = readFileSync(path, \"utf8\");\n assertAuthoredPaths(source.name, content);\n assertDeclaredDependencies(source, content);\n\n return {\n path: `${source.group}/${file}`,\n type: GROUP_FILE_TYPE[source.group],\n content,\n hash: hashContent(content),\n };\n });\n\n return registryItemSchema.parse({\n registryVersion: REGISTRY_VERSION,\n name: source.name,\n type: registryItemTypeSchema.parse(GROUP_FILE_TYPE[source.group]),\n title: source.title,\n description: source.description,\n category: source.category,\n status: source.status,\n dependencies: source.dependencies,\n registryDependencies: source.registryDependencies,\n files,\n a11y: source.a11y,\n access: source.access,\n });\n}\n\nasync function readUpstream(base: string): Promise<RegistryItem[]> {\n const isHttp = base.startsWith(\"http://\") || base.startsWith(\"https://\");\n\n const load = async (file: string): Promise<unknown> => {\n if (!isHttp) {\n const root = base.startsWith(\"file:\") ? fileURLToPath(base) : base;\n const path = join(root, file);\n if (!existsSync(path)) throw new Error(`Upstream registry has no ${file} at ${path}.`);\n return JSON.parse(readFileSync(path, \"utf8\"));\n }\n\n const url = `${base.replace(/\\/$/, \"\")}/${file}`;\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Upstream registry returned ${String(response.status)} for ${url}.`);\n }\n return await response.json();\n };\n\n const index = registryIndexSchema.parse(await load(\"index.json\"));\n\n const items: RegistryItem[] = [];\n for (const entry of index.items) {\n // Licensed upstream items have no public body to inherit. They stay out of\n // the derived registry rather than appearing in it as something that cannot\n // be fetched, which would fail at install time instead of at build time.\n if (entry.access === \"pro\") continue;\n items.push(registryItemSchema.parse(await load(`${entry.name}.json`)));\n }\n\n return items;\n}\n\n/**\n * Every `registryDependencies` name must exist in the finished registry.\n *\n * Checked here, once, rather than discovered by a consumer whose `add` walks\n * into a name nothing serves. This is the single most common way a\n * hand-assembled registry is broken, and it is invisible until someone installs.\n */\nexport function assertResolvable(items: RegistryItem[]): void {\n const known = new Set(items.map((item) => item.name));\n const missing: string[] = [];\n\n for (const item of items) {\n for (const dependency of item.registryDependencies) {\n if (!known.has(dependency)) missing.push(`${item.name} → ${dependency}`);\n }\n }\n\n if (missing.length > 0) {\n throw new Error(\n `These registry dependencies are not in the registry:\\n ${missing.join(\"\\n \")}\\n` +\n \"Add them, or extend a registry that has them.\",\n );\n }\n}\n\nexport async function buildCustomRegistry(config: RegistryConfig): Promise<BuildResult> {\n const parsed = registryConfigSchema.parse(config);\n const local = parsed.items.map((item) => toItem(parsed.root, item));\n\n const duplicates = local\n .map((item) => item.name)\n .filter((name, index, all) => all.indexOf(name) !== index);\n if (duplicates.length > 0) {\n throw new Error(`Declared more than once: ${[...new Set(duplicates)].join(\", \")}.`);\n }\n\n if (!parsed.extends) {\n assertResolvable(local);\n return { items: local, overridden: [], inherited: 0 };\n }\n\n const upstream = await readUpstream(parsed.extends);\n const localNames = new Set(local.map((item) => item.name));\n const overridden = upstream\n .filter((item) => localNames.has(item.name))\n .map((item) => item.name);\n\n // Local wins. That is the point of extending rather than mirroring: an\n // organisation replaces the components it has opinions about and inherits the\n // rest.\n const inherited = upstream.filter((item) => !localNames.has(item.name));\n const items = [...inherited, ...local].sort((a, b) => a.name.localeCompare(b.name));\n\n assertResolvable(items);\n\n return { items, overridden, inherited: inherited.length };\n}\n","import type { RegistryIndex, RegistryIndexEntry, RegistryItem } from \"./schema\";\n\n/**\n * Documentation written for coding agents rather than for people.\n *\n * This lives beside the registry rather than in the CLI or the docs site\n * because all three need to emit the same text: the CLI writes it into a\n * consumer's repository, the site serves it at /llms.txt, and the MCP server\n * answers with it. Three hand-maintained copies would disagree within a\n * release, and an agent acting on a stale catalogue writes code that does not\n * compile.\n *\n * Everything here is derived from the registry index. Nothing is a hardcoded\n * list of component names — that is the failure mode this replaces.\n */\n\nexport interface AgentDocsContext {\n index: RegistryIndex;\n /**\n * Full registry items, when the caller has them.\n *\n * The index carries no accessibility notes, so callers that can afford to\n * fetch every item (the docs build, the MCP server) get richer output than\n * ones that cannot (the CLI, which would otherwise make 81 requests).\n */\n items?: RegistryItem[];\n /** Base URL the CLI installs from. */\n registryUrl: string;\n /** Base URL of the documentation site, no trailing slash. */\n docsUrl: string;\n /** npm package name of the CLI, e.g. `@dowel-ui/cli`. */\n cliPackage: string;\n libraryName: string;\n /** Registry names already present in the project, if known. */\n installed?: string[];\n /**\n * What components are imported from in this project.\n *\n * Source-first installs resolve to the project's own alias; the published\n * package is a separate, supported way to consume the same components. An\n * agent told the wrong one writes imports that do not resolve.\n */\n importFrom: string;\n}\n\nconst CATEGORY_LABELS: Record<string, string> = {\n foundation: \"Foundation\",\n form: \"Forms\",\n overlay: \"Overlays\",\n navigation: \"Navigation\",\n display: \"Display\",\n data: \"Data\",\n feedback: \"Feedback\",\n layout: \"Layout\",\n ai: \"AI\",\n effects: \"Effects\",\n};\n\nconst CATEGORY_ORDER = [\n \"foundation\",\n \"form\",\n \"overlay\",\n \"navigation\",\n \"display\",\n \"data\",\n \"feedback\",\n \"layout\",\n \"ai\",\n \"effects\",\n];\n\nfunction label(category: string): string {\n return CATEGORY_LABELS[category] ?? category;\n}\n\n/** Ordered by curation where curated, alphabetical for anything new. */\nfunction categoriesOf(entries: RegistryIndexEntry[]): string[] {\n const present = new Set(entries.map((entry) => entry.category));\n const known = CATEGORY_ORDER.filter((category) => present.has(category));\n const rest = [...present].filter((category) => !CATEGORY_ORDER.includes(category)).sort();\n return [...known, ...rest];\n}\n\nfunction byType(index: RegistryIndex, type: RegistryIndexEntry[\"type\"]): RegistryIndexEntry[] {\n return index.items\n .filter((entry) => entry.type === type)\n .sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction components(index: RegistryIndex) {\n return byType(index, \"registry:ui\");\n}\n\nfunction blocks(index: RegistryIndex) {\n return byType(index, \"registry:block\");\n}\n\n/**\n * Accessibility rules that differ from what a model has seen elsewhere.\n *\n * An agent trained on every other React library will reach for `disabled` on a\n * loading button and a live region on every alert. Stating only the deltas is\n * deliberate: a general accessibility lecture is ignored, a short list of\n * \"here this is different\" is followed.\n */\nconst ACCESSIBILITY_DELTAS = [\n \"A loading `Button` uses `aria-disabled` + `aria-busy` and guards its own click handler. Never add `disabled` to it — disabling a control mid-action strands keyboard focus.\",\n '`Alert` is not a live region by default. One that exists on first paint announces for no reason. Opt in with `live=\"polite\"` or `live=\"assertive\"` only when the alert appears in response to something.',\n \"`Separator`, `Skeleton` and `Spinner` are decorative and stay out of the accessibility tree unless given a label. Do not add `role` or `aria-label` to them by reflex.\",\n '`PopoverContent` carries `role=\"dialog\"` and warns in development without an accessible name. Always give it `aria-label` or `aria-labelledby`.',\n \"Never use colour as the only signal. The `monochrome` preset exists as a standing check on exactly this — if a state is unreadable under it, the component is wrong.\",\n];\n\nconst TOKEN_RULES = [\n \"Use semantic tokens (`bg-background`, `text-foreground`, `border-border`, `ring-ring`, `bg-primary`, `text-muted-foreground`). Never raw hex, and never Tailwind's own palette (`bg-slate-900`, `text-gray-500`) — those do not follow the theme and break every preset and dark mode.\",\n \"Spacing, radius and type come from the scale. `rounded-md` and `rounded-lg` re-proportion with `--radius-scale`; an arbitrary `rounded-[7px]` does not.\",\n \"Durations derive from `--motion-scale`. Do not hardcode transition timings.\",\n \"Compose class names with `cn()` from the project's utils, so consumer overrides win over defaults.\",\n];\n\nexport function conventionsDoc(context: AgentDocsContext): string {\n const { libraryName, cliPackage, importFrom, docsUrl } = context;\n\n return `# ${libraryName} — conventions\n\nRules for writing code in this project. ${libraryName} is **source-first**: its\ncomponents are files in this repository, not a dependency you can reason about\nfrom its README. They are yours to edit, and edits are preserved across updates.\n\n## The rule that matters most\n\n**Do not hand-write a component that ${libraryName} already has.** Check the\ncatalogue in \\`components.md\\` first. Writing a second Button — with different\nfocus rings, different disabled semantics, different tokens — is the single\nmost common and most damaging thing to do here.\n\n## Adding a component\n\n\\`\\`\\`bash\nnpx ${cliPackage} add <name>\n\\`\\`\\`\n\nThis writes the source into the project and installs whatever it depends on.\n\\`add\\` is safe to re-run: an untouched file is left alone, an edited one is\nnever overwritten without \\`--overwrite\\`.\n\nDo not \\`npm install\\` a component. Do not copy source out of the documentation\nby hand — the CLI resolves the dependency graph and rewrites imports to this\nproject's path alias, and doing it manually gets both wrong.\n\n## Importing\n\n\\`\\`\\`tsx\nimport { Button, Card, CardContent } from \"${importFrom}\";\n\\`\\`\\`\n\n## Styling\n\n${TOKEN_RULES.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Accessibility\n\nTargeted at WCAG 2.2 AA, verified with axe per component. Where ${libraryName}\ndiffers from what you have seen in other libraries:\n\n${ACCESSIBILITY_DELTAS.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Before you build a page\n\nCheck \\`components.md\\` for a **block** that already covers it. A block is a\nwhole section — a login form, a settings page, a chat surface — and installing\none brings every component it is assembled from. Building a dashboard out of\nindividual primitives when \\`add dashboard\\` exists is wasted work.\n\n## Reference\n\n- Documentation: ${docsUrl}\n- Full text for models: ${docsUrl}/llms-full.txt\n`;\n}\n\nexport function componentsDoc(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, installed } = context;\n const have = new Set(installed ?? []);\n const known = installed !== undefined;\n const ui = components(index);\n const blk = blocks(index);\n\n const lines: string[] = [\n `# ${libraryName} — catalogue`,\n \"\",\n `${String(ui.length)} components and ${String(blk.length)} blocks, generated from ` +\n `\\`${index.generatedFrom}\\`. This is the complete list — anything not here does not exist.`,\n \"\",\n ];\n\n if (known) {\n lines.push(\n \"`✓` marks what is already installed in this project. Everything else needs\",\n `\\`npx ${cliPackage} add <name>\\` before it can be imported.`,\n \"\",\n );\n }\n\n const mark = (entry: RegistryIndexEntry) =>\n known ? (have.has(entry.name) ? \"✓ \" : \" \") : \"\";\n\n for (const category of categoriesOf(ui)) {\n lines.push(`## ${label(category)}`, \"\");\n for (const entry of ui.filter((item) => item.category === category)) {\n const status = entry.status === \"stable\" ? \"\" : ` _(${entry.status})_`;\n lines.push(`- ${mark(entry)}**${entry.name}** — ${entry.description}${status}`);\n }\n lines.push(\"\");\n }\n\n lines.push(\n \"## Blocks\",\n \"\",\n \"Whole sections. Installing one installs every component it is built from.\",\n \"\",\n );\n for (const entry of blk) {\n const deps = entry.registryDependencies.length;\n const resolves = deps > 0 ? ` _(resolves ${String(deps)} components)_` : \"\";\n lines.push(`- ${mark(entry)}**${entry.name}** — ${entry.description}${resolves}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\nexport function aiDoc(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage } = context;\n const ai = components(index).filter((entry) => entry.category === \"ai\");\n\n return `# ${libraryName} — AI components\n\n${String(ai.length)} surfaces for AI features. Reach for these before building\nanything custom for a model-facing interface.\n\nMost component sets ship a chat transcript and stop. Real AI features are\nextraction, enrichment, autofill and agents that *change things* — so the parts\nthat matter are the ones around the transcript, not the transcript itself.\n\n${ai.map((entry) => `- **${entry.name}** — ${entry.description}`).join(\"\\n\")}\n\n## Choosing between them\n\n- Rendering a conversation → \\`ai-conversation\\` with \\`ai-message\\` and \\`ai-response\\`.\n- The composer → \\`ai-prompt-input\\`, with \\`ai-model-selector\\` if the model is switchable.\n- A tool the model called → \\`ai-tool\\`. Its arguments and result belong there, not in prose.\n- Asking permission *before* a tool runs → \\`ai-approval-request\\`.\n- Reporting what it did *after* → \\`ai-action-ledger\\`, which is also where reversibility belongs. A deletion can be undone, a refund can only be offset, a sent email cannot be taken back — the ledger is where that distinction is shown.\n- An object streaming in field by field → \\`ai-structured-output\\`, which reserves layout up front so nothing jumps.\n- Ghost text in a real textarea → \\`ai-inline-completion\\`. Escape always returns Tab to focus management, so a keyboard user is never trapped.\n- A value the model proposes for a form field → \\`ai-suggested-value\\`.\n- Reviewing what was pulled out of a document → \\`ai-extraction-review\\`.\n- Long-running work → \\`ai-agent-status\\` and \\`ai-agent-plan\\`.\n- Where an answer came from → \\`ai-sources\\`. Cost → \\`ai-token-usage\\`. Chain of thought → \\`ai-reasoning\\`.\n\n## Whole surface at once\n\n\\`\\`\\`bash\nnpx ${cliPackage} add ai-chat\n\\`\\`\\`\n`;\n}\n\nexport function themesDoc(context: AgentDocsContext): string {\n const { libraryName } = context;\n\n return `# ${libraryName} — theming\n\nTokens are two-tier. **Tier 1** is raw scales: an OKLCH neutral ramp, a radius\nladder, a 15px-base type scale, elevation, motion. **Tier 2** is semantic\naliases — \\`--primary\\`, \\`--background\\`, \\`--border\\`, \\`--ring\\` — and components\nconsume Tier 2 *exclusively*.\n\nRe-skinning the system means reassigning Tier 2. It never means editing a\ncomponent file. If you find yourself changing a colour inside a component, the\nchange belongs in the token layer instead.\n\n## Presets\n\n\\`default\\`, \\`ocean\\`, \\`emerald\\`, \\`violet\\`, \\`rose\\`, \\`amber\\`, \\`monochrome\\`,\n\\`candy\\`, \\`indigo\\`, \\`blue\\`, \\`red\\`, \\`orange\\`, \\`green\\`.\n\n\\`\\`\\`html\n<html data-theme=\"ocean\" class=\"dark\">\n\\`\\`\\`\n\n\\`data-theme\\` selects the preset; the \\`dark\\` class selects the mode. They are\nindependent — every preset works in both.\n\n\\`monochrome\\` is not only a style. It is a standing check that no component uses\ncolour as its only signal, so verify new work under it.\n\n## Two properties that re-proportion everything\n\n- \\`--radius-scale\\` — one multiplier behind every corner in the system. \\`1\\` is the designed default, \\`0\\` is fully square.\n- \\`--motion-scale\\` — one multiplier every duration derives from. Under \\`prefers-reduced-motion\\` it collapses, but indicators that report ongoing state are *slowed* rather than stopped via \\`--motion-scale-indicator\\`, because a frozen spinner reads as a hung application.\n\n## Contrast\n\nAll semantic pairs are verified against WCAG 2.2 AA across both modes and every\npreset, in CI. A new token pair has to pass the same check — do not introduce\none without running \\`audit:contrast\\`.\n`;\n}\n\n/** Frontmatter-carrying skill file for Claude Code. */\nexport function skillDoc(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, importFrom } = context;\n const ui = components(index);\n const blk = blocks(index);\n const names = ui.map((entry) => entry.name).join(\", \");\n\n return `---\nname: ${libraryName.toLowerCase()}-ui\ndescription: >-\n Build React interfaces with ${libraryName}, the source-first component system\n installed in this project. Use whenever writing or editing React UI here —\n any button, form, dialog, table, dashboard or AI surface. Covers the\n ${String(ui.length)}-component catalogue, the ${String(blk.length)} blocks, design tokens, theming\n and the accessibility rules that differ from other libraries.\n---\n\n# ${libraryName}\n\nSource-first React components. They are **files in this repository**, not a\ndependency — installed with a CLI, then owned and edited like any other code.\n\n## Do this first\n\nNever hand-write a component ${libraryName} already has. The catalogue:\n\n${names}\n\nBlocks (whole sections, each resolving its own components):\n${blk.map((entry) => entry.name).join(\", \")}\n\n## Adding one\n\n\\`\\`\\`bash\nnpx ${cliPackage} add button card dialog\n\\`\\`\\`\n\nResolves dependencies, installs npm packages, rewrites imports to this\nproject's alias. Safe to re-run — it will not overwrite a file you have edited\nwithout \\`--overwrite\\`.\n\n## Importing\n\n\\`\\`\\`tsx\nimport { Button, Card, CardContent } from \"${importFrom}\";\n\\`\\`\\`\n\n## Styling rules\n\n${TOKEN_RULES.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Accessibility rules that differ here\n\n${ACCESSIBILITY_DELTAS.map((rule) => `- ${rule}`).join(\"\\n\")}\n\n## Reference files\n\n- \\`.dowel/components.md\\` — the full catalogue with descriptions\n- \\`.dowel/ai.md\\` — the AI components and when to use each\n- \\`.dowel/themes.md\\` — tokens, presets, radius and motion scales\n- \\`.dowel/conventions.md\\` — the rules above, in full\n`;\n}\n\n/** Cursor project rule (`.cursor/rules/*.mdc`). */\nexport function cursorRule(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, importFrom } = context;\n const ui = components(index);\n\n return `---\ndescription: ${libraryName} component system — use for all React UI in this project\nglobs: [\"**/*.tsx\", \"**/*.jsx\"]\nalwaysApply: false\n---\n\n${libraryName} is source-first: its ${String(ui.length)} components are files in this\nrepository. Never hand-write one that already exists.\n\nAdd: \\`npx ${cliPackage} add <name>\\`\nImport: \\`import { Button } from \"${importFrom}\"\\`\n\nAvailable: ${ui.map((entry) => entry.name).join(\", \")}\n\n${TOKEN_RULES.map((rule) => `- ${rule}`).join(\"\\n\")}\n${ACCESSIBILITY_DELTAS.map((rule) => `- ${rule}`).join(\"\\n\")}\n\nFull catalogue and reasoning: \\`.dowel/\\`\n`;\n}\n\nexport const AGENTS_MARKER_START = \"<!-- dowel:start -->\";\nexport const AGENTS_MARKER_END = \"<!-- dowel:end -->\";\n\n/**\n * The block written into a project's AGENTS.md.\n *\n * Marker-wrapped rather than written as a whole file: AGENTS.md belongs to the\n * project and usually already says things about the project. Replacing it would\n * destroy that; appending without markers would duplicate the section on every\n * regeneration.\n */\nexport function agentsSection(context: AgentDocsContext): string {\n const { index, libraryName, cliPackage, importFrom } = context;\n const ui = components(index);\n\n return `${AGENTS_MARKER_START}\n\n## UI components — ${libraryName}\n\nThis project uses ${libraryName}, a **source-first** component system: its\n${String(ui.length)} components live in this repository as editable files.\n\n- **Never hand-write a component that already exists.** The full catalogue is in \\`.dowel/components.md\\`.\n- Add one with \\`npx ${cliPackage} add <name>\\` — never \\`npm install\\`, never copy source by hand.\n- Import from \\`${importFrom}\\`.\n- Style with semantic tokens only (\\`bg-background\\`, \\`text-muted-foreground\\`), never raw hex and never Tailwind's own palette.\n- Building a page? Check \\`.dowel/components.md\\` for a **block** first.\n- Building an AI feature? \\`.dowel/ai.md\\` lists surfaces you will not find elsewhere.\n- Accessibility deltas from other libraries are in \\`.dowel/conventions.md\\`. Read them before adding ARIA by reflex.\n\n${AGENTS_MARKER_END}`;\n}\n\n/** Replaces the marked block, or appends it if there is none. */\nexport function upsertAgentsSection(existing: string, section: string): string {\n const start = existing.indexOf(AGENTS_MARKER_START);\n const end = existing.indexOf(AGENTS_MARKER_END);\n\n if (start !== -1 && end !== -1 && end > start) {\n return existing.slice(0, start) + section + existing.slice(end + AGENTS_MARKER_END.length);\n }\n\n const base = existing.trimEnd();\n return base.length > 0 ? `${base}\\n\\n${section}\\n` : `${section}\\n`;\n}\n\n/**\n * The llms.txt index.\n *\n * Deliberately a map rather than a dump: it names every component and points at\n * the one URL that carries everything, so a model with a small budget can find\n * the right page and one with a large budget can take the lot.\n */\nexport function llmsTxt(context: AgentDocsContext): string {\n const { index, libraryName, docsUrl, cliPackage } = context;\n const ui = components(index);\n const blk = blocks(index);\n\n const lines = [\n `# ${libraryName}`,\n \"\",\n `> Source-first React components for SaaS and AI products. ${String(ui.length)} components ` +\n `and ${String(blk.length)} blocks, installed as code you own rather than imported from a ` +\n `dependency. Built on Tailwind v4 and OKLCH design tokens, targeted at WCAG 2.2 AA.`,\n \"\",\n `Install: \\`npx ${cliPackage} add <name>\\` writes the component's source into your project.`,\n \"Re-running is safe — files you have edited are never overwritten without `--overwrite`.\",\n \"\",\n `Generated from ${index.generatedFrom}.`,\n \"\",\n \"## Start here\",\n \"\",\n `- [Everything, in one file](${docsUrl}/llms-full.txt): the complete catalogue with descriptions, accessibility notes and conventions`,\n `- [Installation](${docsUrl}/docs/installation)`,\n `- [CLI](${docsUrl}/docs/cli)`,\n `- [Theming](${docsUrl}/docs/themes)`,\n `- [Accessibility](${docsUrl}/docs/accessibility)`,\n \"\",\n ];\n\n for (const category of categoriesOf(ui)) {\n lines.push(`## ${label(category)}`, \"\");\n for (const entry of ui.filter((item) => item.category === category)) {\n lines.push(\n `- [${entry.name}](${docsUrl}/docs/components/${entry.name}): ${entry.description}`,\n );\n }\n lines.push(\"\");\n }\n\n lines.push(\"## Blocks\", \"\");\n for (const entry of blk) {\n lines.push(`- [${entry.name}](${docsUrl}/docs/blocks/${entry.name}): ${entry.description}`);\n }\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n}\n\n/** Everything an agent needs, in one request. */\nexport function llmsFullTxt(context: AgentDocsContext): string {\n const { index, items, libraryName, docsUrl } = context;\n const detail = new Map((items ?? []).map((item) => [item.name, item]));\n\n const parts = [\n conventionsDoc(context),\n componentsDoc({ ...context, installed: undefined }),\n aiDoc(context),\n themesDoc(context),\n ];\n\n const lines = [\n `# ${libraryName} — full reference`,\n \"\",\n `Generated from ${index.generatedFrom}. Canonical source: ${docsUrl}`,\n \"\",\n \"---\",\n \"\",\n parts.join(\"\\n---\\n\\n\"),\n ];\n\n if (detail.size > 0) {\n lines.push(\"---\", \"\", \"# Per-component detail\", \"\");\n\n for (const entry of components(index)) {\n const item = detail.get(entry.name);\n lines.push(`## ${entry.title} \\`${entry.name}\\``, \"\", entry.description, \"\");\n lines.push(\n `- Category: ${label(entry.category)} · Status: ${entry.status}`,\n `- Install: \\`add ${entry.name}\\``,\n );\n if (entry.registryDependencies.length > 0) {\n lines.push(`- Also installs: ${entry.registryDependencies.join(\", \")}`);\n }\n if (entry.dependencies.length > 0) {\n lines.push(`- npm: ${entry.dependencies.join(\", \")}`);\n }\n if (item?.a11y) {\n lines.push(`- Accessibility: ${item.a11y}`);\n }\n lines.push(\"\");\n }\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dowel-ui/registry",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "description": "Builds the static component registry that the Dowel CLI installs from. For hosting your own registry or a fork.",
6
6
  "keywords": [
@@ -53,9 +53,9 @@
53
53
  "tsx": "4.23.13",
54
54
  "typescript": "6.0.3",
55
55
  "vitest": "4.1.10",
56
- "@dowel-ui/config": "0.7.0",
57
- "@dowel-ui/themes": "0.7.0",
58
- "@dowel-ui/react": "0.7.0"
56
+ "@dowel-ui/themes": "0.8.0",
57
+ "@dowel-ui/react": "0.8.0",
58
+ "@dowel-ui/config": "0.8.0"
59
59
  },
60
60
  "scripts": {
61
61
  "build": "tsdown && tsx src/build.ts --out r",
package/src/agent-docs.ts CHANGED
@@ -53,6 +53,7 @@ const CATEGORY_LABELS: Record<string, string> = {
53
53
  feedback: "Feedback",
54
54
  layout: "Layout",
55
55
  ai: "AI",
56
+ effects: "Effects",
56
57
  };
57
58
 
58
59
  const CATEGORY_ORDER = [
@@ -65,6 +66,7 @@ const CATEGORY_ORDER = [
65
66
  "feedback",
66
67
  "layout",
67
68
  "ai",
69
+ "effects",
68
70
  ];
69
71
 
70
72
  function label(category: string): string {
@@ -281,7 +283,8 @@ change belongs in the token layer instead.
281
283
 
282
284
  ## Presets
283
285
 
284
- \`default\`, \`ocean\`, \`emerald\`, \`violet\`, \`rose\`, \`amber\`, \`monochrome\`.
286
+ \`default\`, \`ocean\`, \`emerald\`, \`violet\`, \`rose\`, \`amber\`, \`monochrome\`,
287
+ \`candy\`, \`indigo\`, \`blue\`, \`red\`, \`orange\`, \`green\`.
285
288
 
286
289
  \`\`\`html
287
290
  <html data-theme="ocean" class="dark">
package/src/generate.ts CHANGED
@@ -105,24 +105,32 @@ const SYNONYMS: Record<string, string[]> = {
105
105
  invoices: ["billing"],
106
106
  payment: ["billing"],
107
107
  plan: ["pricing", "billing"],
108
- plans: ["pricing"],
108
+ plans: ["pricing", "pricing-three-tier", "pricing-two-tier", "pricing-single-plan"],
109
109
  metrics: ["analytics", "dashboard", "metric-delta"],
110
- chart: ["analytics"],
111
- charts: ["analytics"],
112
- graph: ["analytics"],
113
- stats: ["dashboard", "analytics"],
110
+ chart: ["analytics", "dither-bar", "dither-line", "dither-area", "dither-donut"],
111
+ charts: [
112
+ "analytics",
113
+ "dither-canvas",
114
+ "dither-bar",
115
+ "dither-line",
116
+ "dither-area",
117
+ "dither-donut",
118
+ "dither-heatmap",
119
+ ],
120
+ graph: ["analytics", "dither-line", "dither-area", "contribution-graph"],
121
+ stats: ["dashboard", "analytics", "stats-grid", "stats-trend-cards"],
114
122
  overview: ["dashboard"],
115
123
  grid: ["data-table", "table"],
116
124
  spreadsheet: ["data-table"],
117
125
  list: ["table", "data-table"],
118
- search: ["command", "combobox"],
119
- palette: ["command"],
126
+ search: ["command", "combobox", "expanding-search", "faq-searchable"],
127
+ palette: ["command", "palette-generator"],
120
128
  shortcut: ["command", "shortcut-recorder"],
121
129
  modal: ["dialog"],
122
130
  popup: ["dialog", "popover"],
123
131
  dropdown: ["dropdown-menu", "select"],
124
132
  toast: ["toast"],
125
- notification: ["toast", "activity-feed"],
133
+ notification: ["toast", "activity-feed", "notification-badge", "notify-button"],
126
134
  notifications: ["toast", "settings"],
127
135
  upload: ["file-upload"],
128
136
  file: ["file-upload"],
@@ -130,7 +138,7 @@ const SYNONYMS: Record<string, string[]> = {
130
138
  time: ["time-range-picker"],
131
139
  schedule: ["cron-editor"],
132
140
  cron: ["cron-editor"],
133
- team: ["admin-users", "settings"],
141
+ team: ["admin-users", "settings", "team-grid", "team-carousel"],
134
142
  members: ["admin-users"],
135
143
  users: ["admin-users"],
136
144
  admin: ["admin-users"],
@@ -140,8 +148,8 @@ const SYNONYMS: Record<string, string[]> = {
140
148
  preferences: ["settings"],
141
149
  account: ["settings", "billing"],
142
150
  setup: ["onboarding"],
143
- checklist: ["onboarding"],
144
- wizard: ["onboarding"],
151
+ checklist: ["onboarding", "animated-checklist", "todo-tower"],
152
+ wizard: ["onboarding", "stepper"],
145
153
  logs: ["log-viewer"],
146
154
  log: ["log-viewer"],
147
155
  diff: ["diff-viewer", "record-diff"],
@@ -149,6 +157,107 @@ const SYNONYMS: Record<string, string[]> = {
149
157
  "api key": ["secret-field"],
150
158
  key: ["secret-field"],
151
159
  dns: ["dns-record"],
160
+ loader: [
161
+ "spinner",
162
+ "dots-loader",
163
+ "ring-loader",
164
+ "bar-loader",
165
+ "shape-loader",
166
+ "text-loader",
167
+ "grid-loader",
168
+ "ai-loader",
169
+ ],
170
+ loaders: [
171
+ "dots-loader",
172
+ "ring-loader",
173
+ "bar-loader",
174
+ "shape-loader",
175
+ "text-loader",
176
+ "grid-loader",
177
+ ],
178
+ loading: ["spinner", "dots-loader", "ring-loader", "bar-loader", "skeleton", "text-loader"],
179
+ spinner: ["spinner", "ring-loader"],
180
+ animation: ["text-effect", "text-swap", "shader-transition"],
181
+ animated: ["text-effect", "morph-button", "effect-button", "number-flow"],
182
+ "text animation": [
183
+ "text-effect",
184
+ "text-swap",
185
+ "shimmer-text",
186
+ "scramble-text",
187
+ "typewriter-text",
188
+ ],
189
+ typewriter: ["typewriter-text"],
190
+ shimmer: ["shimmer-text", "skeleton"],
191
+ counter: ["number-flow", "drag-stepper"],
192
+ price: ["number-flow", "pricing"],
193
+ carousel: [
194
+ "carousel-3d",
195
+ "swipe-carousel",
196
+ "reviews-carousel",
197
+ "invite-carousel",
198
+ "time-stack",
199
+ ],
200
+ slider: ["slider", "exposure-slider", "slosh-slider", "scrubber", "range-dial"],
201
+ slideshow: ["carousel-3d", "swipe-carousel", "photo-stack"],
202
+ marquee: ["marquee", "logo-marquee"],
203
+ ticker: ["marquee"],
204
+ cards: ["card", "card-spread", "card-stack", "glow-card", "tilt-card", "expandable-cards"],
205
+ hero: [
206
+ "hero-grid",
207
+ "hero-product",
208
+ "hero-split-image",
209
+ "hero-perspective-grid",
210
+ "hero-spotlight",
211
+ "hero-minimal",
212
+ ],
213
+ landing: ["hero-grid", "features-bento", "cta-centered", "footer-newsletter"],
214
+ cta: ["cta-centered", "cta-split-image", "cta-banner"],
215
+ "call to action": ["cta-centered", "cta-split-image", "cta-banner"],
216
+ features: ["features-icon-grid", "features-bento", "features-alternating"],
217
+ logos: ["logo-cloud-simple", "logo-marquee", "logo-links-marquee", "logo-grid-tooltips"],
218
+ testimonials: [
219
+ "testimonial-rotator",
220
+ "testimonial-spotlight",
221
+ "testimonial-star-grid",
222
+ "reviews-carousel",
223
+ ],
224
+ reviews: ["reviews-carousel", "testimonial-star-grid"],
225
+ faq: ["faq-accordion", "faq-searchable", "faq-categorized", "faq-tabbed-grid"],
226
+ footer: ["footer-simple", "footer-newsletter", "footer-mega", "footer-minimal"],
227
+ newsletter: ["footer-newsletter", "footer-mega"],
228
+ heatmap: ["dither-heatmap", "contribution-graph"],
229
+ donut: ["dither-donut"],
230
+ pie: ["dither-donut"],
231
+ gauge: ["dither-gauge", "meter"],
232
+ funnel: ["dither-funnel"],
233
+ uptime: ["uptime-matrix"],
234
+ "status page": ["uptime-matrix"],
235
+ otp: ["otp-input"],
236
+ "one-time code": ["otp-input"],
237
+ "verification code": ["otp-input"],
238
+ steps: ["stepper"],
239
+ "context menu": ["context-menu"],
240
+ "right click": ["context-menu"],
241
+ reorder: ["reorder-list", "browser-tabs"],
242
+ sortable: ["reorder-list"],
243
+ drag: ["reorder-list", "goo-ball", "swipe-carousel"],
244
+ dock: ["magnify-dock"],
245
+ toolbar: ["canvas-toolbar", "magnify-dock"],
246
+ confirm: ["slide-to-confirm", "inline-confirm", "confirm-typed"],
247
+ delete: ["inline-confirm", "confirm-typed"],
248
+ toggle: ["switch", "liquid-toggle"],
249
+ copy: ["copy-button"],
250
+ clipboard: ["copy-button"],
251
+ refresh: ["pull-to-refresh"],
252
+ music: ["now-playing"],
253
+ player: ["now-playing"],
254
+ orb: ["gradient-orb", "orb-face"],
255
+ transition: ["shader-transition", "text-swap"],
256
+ badge: ["badge", "notification-badge"],
257
+ avatar: ["avatar", "avatar-group", "pixel-avatar"],
258
+ tweet: ["tweet-card"],
259
+ dial: ["dial", "range-dial"],
260
+ knob: ["dial"],
152
261
  };
153
262
 
154
263
  export interface PlanEntry {