Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .changeset/v1-public-surface-and-docs-polish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
"leadtype": minor
---

Ship the v1 headless integration surface plus docs polish.

**New public API**

- `createDocsSource({ contentDir })` at the root — framework-neutral docs source primitive returning navigation, page loading, search index, and standalone include resolution. Works with Next App Router, Astro, Vite + Vue/Solid/Svelte, Nuxt, SvelteKit, and any MDX-aware bundler.
- `leadtype/mdx` subpath — typed prop contracts for every custom MDX tag (`CalloutProps`, `TabsProps`, `StepProps`, `TypeTableProps`, …) plus `mdxSourcePlugins` (a remark preset that expands `<include>` and resolves `<ExtractedTypeTable>` at build time while leaving custom tags as JSX). Framework-neutral — `children` is typed as `unknown` so consumers intersect with React/Vue/Svelte/Solid/Astro child types.
- `leadtype/fumadocs` subpath — thin adapter mapping `createDocsSource()` to fumadocs-core's `Source` interface, including `meta.json` walking. `fumadocs-core >= 15` is an optional peer dependency.

**New helpers**

- `convertMdxFile(path, plugins)` from `leadtype/convert` — returns `{ ast, frontmatter, data, markdown }` in memory for a single MDX file.
- `resolveInclude(specifier, options)` from `leadtype/mdx` — standalone include resolver, no remark transform required. Plus `parseIncludeSpecifier`, `extractMdxSection`, `resolveIncludePath`.
- `remarkResolveTypeTableJsx` — source-preset variant of the type-table plugin that emits `<TypeTable properties={…} />` JSX (vs. the existing markdown-flattening variant).

**Frontmatter contract**

- New optional `order:` field. Pages with explicit order sort first within their group (ascending); pages without `order` fall back to alphabetical urlPath ordering. Conventionally numbered in tens for insertion room.

**Navigation**

- `resolveDocsNavigation` accepts an optional `docsDirName` config field (defaults to `"docs"`) for projects whose docs folder isn't named `docs/`.

**Bug fixes**

- Mermaid blocks in agent-flattened markdown no longer destroy `<br/>` line-break syntax (was being replaced with ` / ` and ` - ` in two passes). Mermaid renderers now receive valid syntax with multi-line node labels intact.
- The mermaid plugin's outer-backtick stripper now handles the common `` chart={`flowchart LR\n...`} `` inline form, not just backticks-on-their-own-lines.
3 changes: 2 additions & 1 deletion apps/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"pipeline:convert": "bun run scripts/mdx-convert.ts",
"pipeline:llm": "bun run scripts/llm-generate.ts",
"pipeline:search": "bun run scripts/search-generate.ts",
"pipeline:build": "bun run pipeline:convert && bun run pipeline:llm && bun run pipeline:search",
"pipeline:source-manifest": "bun run scripts/docs-source-manifest.ts",
"pipeline:build": "bun run pipeline:convert && bun run pipeline:llm && bun run pipeline:search && bun run pipeline:source-manifest",
"pipeline:test": "bun run scripts/test-pipeline.ts",
"pipeline:setup-real": "bun run scripts/setup-real-content.ts",
"pipeline:test-real": "bun run pipeline:setup-real && bun run scripts/test-real.ts",
Expand Down
64 changes: 64 additions & 0 deletions apps/example/scripts/docs-source-manifest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env bun
/**
* Build-time dogfood of `createDocsSource()` — the v1 source primitive.
*
* Writes `src/generated/docs-pages.json` with `{ slug, urlPath, title,
* description, relativePath, extension }` for every page in `/docs`. The
* catch-all docs route uses this manifest to wire slugs → MDX modules
* without hand-rolling one route file per page.
*
* The companion `llm-generate.ts` script still emits the on-disk
* `llms.txt` / `agent-readability.json` artifacts via the older composed
* APIs. The two paths coexist deliberately — they demonstrate both
* integration shapes from `/docs/build/build-a-docs-site`.
*/

import { mkdir, writeFile } from "node:fs/promises";
import { dirname, join, sep as platformSep, relative } from "node:path";
import { fileURLToPath } from "node:url";
import { createDocsSource } from "leadtype";
import docsConfig from "../../../docs/docs.config";

/** `import.meta.glob` keys are always POSIX even on Windows. */
function toPosix(input: string): string {
return platformSep === "/" ? input : input.replaceAll(platformSep, "/");
}

const scriptsRoot = dirname(fileURLToPath(import.meta.url));
const appRoot = join(scriptsRoot, "..");
const repoRoot = join(appRoot, "..", "..");
const contentDir = join(repoRoot, "docs");
const generatedDir = join(appRoot, "src", "generated");
const manifestPath = join(generatedDir, "docs-pages.json");

const source = await createDocsSource({
contentDir,
baseUrl: process.env.BASE_URL?.trim() || "https://leadtype.dev",
groups: docsConfig.groups,
});

const pages = await source.listPages();

const manifest = pages.map((page) => ({
slug: page.slug,
urlPath: page.urlPath,
title: page.title,
description: page.description,
relativePath: page.relativePath,
extension: page.extension,
groups: page.groups,
// Path the runtime catch-all can use to look up the MDX module against
// `import.meta.glob('../../../../docs/**/*.mdx')`. Always relative to
// src/routes/docs/$.tsx with POSIX separators so the key matches the
// glob output on every platform (Windows otherwise emits backslashes).
globKey: toPosix(
`${relative(join(appRoot, "src", "routes", "docs"), join(contentDir, page.relativePath))}${page.extension}`
),
}));

await mkdir(generatedDir, { recursive: true });
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);

process.stdout.write(
`Wrote ${manifest.length} pages to ${relative(repoRoot, manifestPath)}\n`
);
33 changes: 10 additions & 23 deletions apps/example/src/components/docs-mdx/callout.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,16 @@
import type {
CalloutTypeAlias,
CalloutVariant,
CalloutProps as LeadtypeCalloutProps,
} from "leadtype/mdx";
import type { HTMLAttributes, ReactNode } from "react";

export type CalloutVariant =
| "info"
| "note"
| "tip"
| "warning"
| "success"
| "error"
| "canary"
| "deprecated"
| "experimental";
export type { CalloutTypeAlias, CalloutVariant } from "leadtype/mdx";

/**
* Aliases accepted by the deprecated `type` prop. Mirrors `CalloutVariant`
* but also accepts `"warn"` (Fumadocs-style) which maps to `"warning"`.
*/
export type CalloutTypeAlias = CalloutVariant | "warn";

export type CalloutProps = HTMLAttributes<HTMLElement> & {
variant?: CalloutVariant;
/** @deprecated Use `variant` instead. Kept for Fumadocs-authored MDX compatibility. */
type?: CalloutTypeAlias;
title?: string;
children?: ReactNode;
};
export type CalloutProps = Omit<LeadtypeCalloutProps, "children"> &
HTMLAttributes<HTMLElement> & {
children?: ReactNode;
};

function normalizeVariant(
variant: CalloutVariant | undefined,
Expand Down
Loading
Loading