@lexibase/rdx-next 3.0.0 → 3.2.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/bin/cli.mjs +2 -0
- package/bin/project-styles.mjs +27 -0
- package/config.d.mts +7 -2
- package/config.mjs +19 -5
- package/dist/runtime/index.js +81 -49
- package/package.json +6 -6
- package/src/runtime/styles.css +1 -13
package/bin/cli.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { createJiti } from 'jiti'
|
|
|
10
10
|
|
|
11
11
|
import postcssConfig from '../postcss.config.mjs'
|
|
12
12
|
import { preparePublicAssets } from './public-assets.mjs'
|
|
13
|
+
import { prepareProjectStyles } from './project-styles.mjs'
|
|
13
14
|
|
|
14
15
|
export async function runRdxCli({ templateDir } = {}) {
|
|
15
16
|
const supportedCommands = new Set(['dev', 'build', 'start'])
|
|
@@ -31,6 +32,7 @@ export async function runRdxCli({ templateDir } = {}) {
|
|
|
31
32
|
force: true,
|
|
32
33
|
recursive: true,
|
|
33
34
|
})
|
|
35
|
+
await prepareProjectStyles(projectRoot, runtimeDirectory)
|
|
34
36
|
// Resolve in Node before Next processes this file: UI may be transitive,
|
|
35
37
|
// and native Tailwind plugins must stay outside the Turbopack module graph.
|
|
36
38
|
const resolvePlugin = createRequire(import.meta.url)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readFile, stat, writeFile } from 'node:fs/promises'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
|
|
4
|
+
/** Import project-owned CSS after the theme without copying or editing it. */
|
|
5
|
+
export async function prepareProjectStyles(projectRoot, runtimeDirectory) {
|
|
6
|
+
const source = path.join(projectRoot, 'rdx.css')
|
|
7
|
+
const destination = path.join(runtimeDirectory, 'app', 'globals.css')
|
|
8
|
+
const current = await readFile(destination, 'utf8')
|
|
9
|
+
const original = current.replace(
|
|
10
|
+
/^@import "\.\.\/\.\.\/rdx\.css";\r?\n/gm,
|
|
11
|
+
''
|
|
12
|
+
)
|
|
13
|
+
let exists = false
|
|
14
|
+
try {
|
|
15
|
+
const info = await stat(source)
|
|
16
|
+
if (!info.isFile()) throw new Error('rdx.css must be a CSS file.')
|
|
17
|
+
exists = true
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error.code !== 'ENOENT') throw error
|
|
20
|
+
}
|
|
21
|
+
const next = exists
|
|
22
|
+
? original.replace(/(@import[^;]+;)/, '$1\n@import "../../rdx.css";')
|
|
23
|
+
: original
|
|
24
|
+
if (next !== current) {
|
|
25
|
+
await writeFile(destination, next)
|
|
26
|
+
}
|
|
27
|
+
}
|
package/config.d.mts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/** Common build root for the documentation project and its installed Next.js. */
|
|
2
2
|
export function getRdxBuildRoot(rootDir: string): Promise<string>
|
|
3
3
|
|
|
4
|
-
/** Explicit deployment files for a native Next.js application
|
|
4
|
+
/** Explicit deployment files and historical route redirects for a native Next.js application. */
|
|
5
5
|
export function getRdxTracingConfig(options: {
|
|
6
6
|
rootDir: string
|
|
7
7
|
appDir?: string
|
|
8
|
-
}): Promise<{
|
|
8
|
+
}): Promise<{
|
|
9
|
+
outputFileTracingIncludes: Record<string, string[]>
|
|
10
|
+
redirects?: () => Promise<
|
|
11
|
+
{ source: string; destination: string; permanent: boolean }[]
|
|
12
|
+
>
|
|
13
|
+
}>
|
package/config.mjs
CHANGED
|
@@ -62,7 +62,7 @@ function literalPattern(filename) {
|
|
|
62
62
|
.replace(/([*?[\]{}()!+@])/g, '\\$1')
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
/** Next.js tracing
|
|
65
|
+
/** Next.js tracing and historical route redirects, independent of plugin names. */
|
|
66
66
|
export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
|
|
67
67
|
rootDir = path.resolve(rootDir)
|
|
68
68
|
appDir = path.resolve(appDir)
|
|
@@ -77,11 +77,17 @@ export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
|
|
|
77
77
|
const project = await createRdxProject(input, { rootDir })
|
|
78
78
|
const files = (
|
|
79
79
|
await Promise.all(
|
|
80
|
-
project.sources
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
project.sources
|
|
81
|
+
.filter((source) => source.redirectTo === undefined)
|
|
82
|
+
.map((source) =>
|
|
83
|
+
contentFiles(
|
|
84
|
+
resolveProjectPath(
|
|
85
|
+
rootDir,
|
|
86
|
+
source.docsDir,
|
|
87
|
+
'content source docsDir'
|
|
88
|
+
)
|
|
89
|
+
)
|
|
83
90
|
)
|
|
84
|
-
)
|
|
85
91
|
)
|
|
86
92
|
).flat()
|
|
87
93
|
for (const filename of project.runtimeFiles) {
|
|
@@ -94,7 +100,15 @@ export async function getRdxTracingConfig({ rootDir, appDir = rootDir }) {
|
|
|
94
100
|
throw new Error(`Plugin runtimeFiles must name a file: ${filename}`)
|
|
95
101
|
files.push(resolved)
|
|
96
102
|
}
|
|
103
|
+
const redirects = project.sources
|
|
104
|
+
.filter((source) => source.redirectTo !== undefined)
|
|
105
|
+
.map((source) => ({
|
|
106
|
+
source: `/docs/${source.routePrefix}/:path*`,
|
|
107
|
+
destination: `/docs/${source.redirectTo}/:path*`,
|
|
108
|
+
permanent: true,
|
|
109
|
+
}))
|
|
97
110
|
return {
|
|
111
|
+
...(redirects.length ? { redirects: async () => redirects } : {}),
|
|
98
112
|
outputFileTracingIncludes: {
|
|
99
113
|
'/*': [
|
|
100
114
|
...new Set(
|
package/dist/runtime/index.js
CHANGED
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
import { Button } from "@lexibase/rdx-ui/components/button";
|
|
9
9
|
import { DocsSidebar } from "@lexibase/rdx-ui/components/docs-sidebar";
|
|
10
10
|
import { DocsToc } from "@lexibase/rdx-ui/components/docs-toc";
|
|
11
|
+
import { DocsPageTransition } from "@lexibase/rdx-ui/components/docs-page-transition";
|
|
11
12
|
import { DocsSearch } from "@lexibase/rdx-ui/components/docs-search";
|
|
12
13
|
import { Home } from "@lexibase/rdx-ui/components/home";
|
|
14
|
+
import { SkipLink } from "@lexibase/rdx-ui/components/skip-link";
|
|
13
15
|
import { FooterCredit } from "@lexibase/rdx-ui/components/footer-credit";
|
|
14
16
|
import { Logo } from "@lexibase/rdx-ui/components/logo";
|
|
15
17
|
import { getMdxComponents } from "@lexibase/rdx-ui/components/mdx-components";
|
|
@@ -21,13 +23,14 @@ import {
|
|
|
21
23
|
VersionDropdown
|
|
22
24
|
} from "@lexibase/rdx-ui/components/version-dropdown";
|
|
23
25
|
import { ThemeProvider } from "@lexibase/rdx-ui/providers/theme-provider";
|
|
24
|
-
import { notFound as notFound2, redirect } from "next/navigation";
|
|
26
|
+
import { notFound as notFound2, redirect, permanentRedirect } from "next/navigation";
|
|
25
27
|
|
|
26
28
|
// src/runtime/mdx.ts
|
|
27
29
|
import { compileMDX } from "next-mdx-remote/rsc";
|
|
28
30
|
import remarkGfm from "remark-gfm";
|
|
29
31
|
import {
|
|
30
32
|
remarkDocumentLinks,
|
|
33
|
+
remarkDocumentationComponents,
|
|
31
34
|
rehypeDocumentationHeadings,
|
|
32
35
|
rehypeDocumentationCode
|
|
33
36
|
} from "@lexibase/rdx-core/mdx";
|
|
@@ -39,7 +42,11 @@ function compileDocumentation(source, components, links) {
|
|
|
39
42
|
blockJS: true,
|
|
40
43
|
blockDangerousJS: true,
|
|
41
44
|
mdxOptions: {
|
|
42
|
-
remarkPlugins: [
|
|
45
|
+
remarkPlugins: [
|
|
46
|
+
remarkGfm,
|
|
47
|
+
remarkDocumentationComponents,
|
|
48
|
+
[remarkDocumentLinks, links]
|
|
49
|
+
],
|
|
43
50
|
rehypePlugins: [rehypeDocumentationHeadings, rehypeDocumentationCode]
|
|
44
51
|
}
|
|
45
52
|
}
|
|
@@ -53,12 +60,12 @@ import { createRdxProject, getProjectDocsPaths } from "@lexibase/rdx-core";
|
|
|
53
60
|
import { getDocsIndex, getDocument, getSourceOptions } from "@lexibase/rdx-core";
|
|
54
61
|
import { buildSearchIndex } from "@lexibase/rdx-core/search";
|
|
55
62
|
function getSearchSources(project) {
|
|
56
|
-
return project.config.search ? project.sources.map((source) => ({ source: source.routePrefix || "_" })) : [];
|
|
63
|
+
return project.config.search ? project.sources.filter((source) => source.redirectTo === void 0).map((source) => ({ source: source.routePrefix || "_" })) : [];
|
|
57
64
|
}
|
|
58
65
|
function getSearchResponse(project, key) {
|
|
59
66
|
if (!project.config.search) return new Response(null, { status: 404 });
|
|
60
67
|
const source = project.sources.find(
|
|
61
|
-
(entry) => (entry.routePrefix || "_") === key
|
|
68
|
+
(entry) => entry.redirectTo === void 0 && (entry.routePrefix || "_") === key
|
|
62
69
|
);
|
|
63
70
|
if (!source) return new Response(null, { status: 404 });
|
|
64
71
|
const options = getSourceOptions(project, source);
|
|
@@ -86,6 +93,7 @@ function getDocumentMetadata({
|
|
|
86
93
|
slug
|
|
87
94
|
}) {
|
|
88
95
|
const route = resolveDocsRoute(project, slug);
|
|
96
|
+
if (route.source.redirectTo !== void 0) return {};
|
|
89
97
|
if (!route.slug) return {};
|
|
90
98
|
if (!route.document) notFound();
|
|
91
99
|
const page = route.categories.flatMap((category) => category.pages).find((page2) => page2.slug === route.slug);
|
|
@@ -134,7 +142,6 @@ function RdxLayout({
|
|
|
134
142
|
config,
|
|
135
143
|
bodyClassName
|
|
136
144
|
}) {
|
|
137
|
-
const messages = getMessages(config.lang);
|
|
138
145
|
return /* @__PURE__ */ jsx("html", { suppressHydrationWarning: true, lang: config.lang ?? "en", children: /* @__PURE__ */ jsx("body", { className: bodyClassName, children: /* @__PURE__ */ jsx(
|
|
139
146
|
ThemeProvider,
|
|
140
147
|
{
|
|
@@ -143,7 +150,7 @@ function RdxLayout({
|
|
|
143
150
|
attribute: "class",
|
|
144
151
|
defaultTheme: config.theme?.defaultTheme ?? "system",
|
|
145
152
|
children: /* @__PURE__ */ jsxs(LocaleProvider, { lang: config.lang, children: [
|
|
146
|
-
/* @__PURE__ */ jsx(
|
|
153
|
+
/* @__PURE__ */ jsx(SkipLink, { lang: config.lang }),
|
|
147
154
|
/* @__PURE__ */ jsx("div", { className: "flex flex-col h-dvh", children })
|
|
148
155
|
] })
|
|
149
156
|
}
|
|
@@ -156,7 +163,7 @@ function RdxHeader({
|
|
|
156
163
|
const { config } = project;
|
|
157
164
|
const messages = getMessages(config.lang);
|
|
158
165
|
const { source, slug: currentSlug } = resolveDocsRoute2(project, slug);
|
|
159
|
-
const options = project.sources.map((edition) => {
|
|
166
|
+
const options = project.sources.filter((edition) => edition.redirectTo === void 0).map((edition) => {
|
|
160
167
|
const docs = getSourceOptions2(project, edition);
|
|
161
168
|
const destination = currentSlug && getDocument2(currentSlug, docs) ? currentSlug : getDocsPaths(docs)[0];
|
|
162
169
|
return {
|
|
@@ -233,6 +240,14 @@ async function DocsPage({
|
|
|
233
240
|
document,
|
|
234
241
|
categories
|
|
235
242
|
} = resolveDocsRoute2(project, slug);
|
|
243
|
+
if (source.redirectTo !== void 0)
|
|
244
|
+
permanentRedirect(
|
|
245
|
+
[
|
|
246
|
+
"/docs",
|
|
247
|
+
source.redirectTo,
|
|
248
|
+
...slug?.slice(1).map(encodeURIComponent) ?? []
|
|
249
|
+
].join("/")
|
|
250
|
+
);
|
|
236
251
|
if (!currentSlug)
|
|
237
252
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
238
253
|
/* @__PURE__ */ jsx(RdxHeader, { project, slug }),
|
|
@@ -286,51 +301,68 @@ async function DocsPage({
|
|
|
286
301
|
className: "relative flex-1 min-w-0 h-full overflow-y-auto pt-12 md:pt-0 outline-none",
|
|
287
302
|
children: [
|
|
288
303
|
project.config.TOC && /* @__PURE__ */ jsx(DocsToc, {}, hrefFor(currentSlug)),
|
|
289
|
-
/* @__PURE__ */
|
|
290
|
-
|
|
304
|
+
/* @__PURE__ */ jsx(
|
|
305
|
+
DocsPageTransition,
|
|
291
306
|
{
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
/* @__PURE__ */ jsx(
|
|
302
|
-
"main",
|
|
303
|
-
{
|
|
304
|
-
id: "rdx-main",
|
|
305
|
-
tabIndex: -1,
|
|
306
|
-
className: "h-full w-full flex-1 max-w-[960px]",
|
|
307
|
-
children: content
|
|
308
|
-
}
|
|
309
|
-
)
|
|
310
|
-
] }),
|
|
311
|
-
/* @__PURE__ */ jsxs("footer", { className: "flex flex-col", children: [
|
|
312
|
-
/* @__PURE__ */ jsxs("section", { className: "flex items-center justify-between", children: [
|
|
313
|
-
previous ? /* @__PURE__ */ jsx(
|
|
314
|
-
Button,
|
|
307
|
+
previousHref: previous ? hrefFor(previous.slug) : void 0,
|
|
308
|
+
nextHref: next ? hrefFor(next.slug) : void 0,
|
|
309
|
+
children: /* @__PURE__ */ jsxs(
|
|
310
|
+
"section",
|
|
311
|
+
{
|
|
312
|
+
className: `w-full min-h-full bg-background px-7 flex flex-col gap-5 pb-8 md:py-8 ${project.config.TOC ? "xl:pr-20" : ""}`,
|
|
313
|
+
children: [
|
|
314
|
+
/* @__PURE__ */ jsxs(
|
|
315
|
+
"main",
|
|
315
316
|
{
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
children:
|
|
317
|
+
id: "rdx-main",
|
|
318
|
+
tabIndex: -1,
|
|
319
|
+
className: "w-full flex flex-col gap-5 md:mx-auto md:max-w-[860px] pt-14 md:pt-0 flex-1 outline-none",
|
|
320
|
+
children: [
|
|
321
|
+
/* @__PURE__ */ jsxs("header", { className: "mb-6", children: [
|
|
322
|
+
source.badge && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mb-4", children: source.badge === "Archived" ? messages.archivedVersion : source.badge }),
|
|
323
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-zinc-600 font-semibold uppercase block -mb-0.5", children: category?.title }),
|
|
324
|
+
/* @__PURE__ */ jsx("h1", { className: "text-4xl uppercase font-bold mb-2", children: title }),
|
|
325
|
+
description && /* @__PURE__ */ jsx("p", { className: "text-sm text-ring max-w-[726px]", children: description })
|
|
326
|
+
] }),
|
|
327
|
+
/* @__PURE__ */ jsx("div", { className: "h-full w-full flex-1 max-w-[960px]", children: content })
|
|
328
|
+
]
|
|
320
329
|
}
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
330
|
+
),
|
|
331
|
+
/* @__PURE__ */ jsxs("footer", { className: "flex flex-col", children: [
|
|
332
|
+
/* @__PURE__ */ jsxs("section", { className: "flex items-center justify-between", children: [
|
|
333
|
+
previous ? /* @__PURE__ */ jsx(
|
|
334
|
+
Button,
|
|
335
|
+
{
|
|
336
|
+
variant: "outline",
|
|
337
|
+
size: "sm",
|
|
338
|
+
href: hrefFor(previous.slug),
|
|
339
|
+
transitionTypes: ["rdx-doc-back"],
|
|
340
|
+
children: previous.title
|
|
341
|
+
}
|
|
342
|
+
) : /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", disabled: true, children: messages.previous }),
|
|
343
|
+
next ? /* @__PURE__ */ jsx(
|
|
344
|
+
Button,
|
|
345
|
+
{
|
|
346
|
+
variant: "outline",
|
|
347
|
+
size: "sm",
|
|
348
|
+
href: hrefFor(next.slug),
|
|
349
|
+
transitionTypes: ["rdx-doc-forward"],
|
|
350
|
+
children: next.title
|
|
351
|
+
}
|
|
352
|
+
) : /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", disabled: true, children: messages.next })
|
|
353
|
+
] }),
|
|
354
|
+
/* @__PURE__ */ jsx(
|
|
355
|
+
FooterCredit,
|
|
356
|
+
{
|
|
357
|
+
lang: project.config.lang,
|
|
358
|
+
name: project.config.metadata.applicationName,
|
|
359
|
+
since: project.config.metadata.since
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
] })
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
)
|
|
334
366
|
}
|
|
335
367
|
)
|
|
336
368
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lexibase/rdx-next",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "The Next.js runtime for RDX documentation projects.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -51,11 +51,11 @@
|
|
|
51
51
|
"next-mdx-remote": "^6.0.0",
|
|
52
52
|
"remark-gfm": "^4",
|
|
53
53
|
"typescript": "6.0.3",
|
|
54
|
-
"@lexibase/rdx-core": "1.
|
|
55
|
-
"@lexibase/rdx-types": "1.
|
|
54
|
+
"@lexibase/rdx-core": "1.4.0",
|
|
55
|
+
"@lexibase/rdx-types": "1.2.0"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@lexibase/rdx-ui": "^3.
|
|
58
|
+
"@lexibase/rdx-ui": "^3.2.0",
|
|
59
59
|
"next": "^16.4.2",
|
|
60
60
|
"react": "^19.3.1",
|
|
61
61
|
"react-dom": "^19.3.1"
|
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
"next": "^16.4.2",
|
|
81
81
|
"react": "19.3.1",
|
|
82
82
|
"react-dom": "19.3.1",
|
|
83
|
-
"@rdx
|
|
83
|
+
"@lexibase/rdx-ui": "3.2.0",
|
|
84
84
|
"@rdx/typescript-config": "1.0.0",
|
|
85
|
-
"@
|
|
85
|
+
"@rdx/eslint-config": "1.0.0"
|
|
86
86
|
},
|
|
87
87
|
"scripts": {
|
|
88
88
|
"dev": "tsup src/index.ts src/runtime/index.tsx --format esm --dts --watch --external @lexibase/rdx-core --external @lexibase/rdx-types --external @lexibase/rdx-ui --external next --external react --external react-dom --external next-mdx-remote",
|
package/src/runtime/styles.css
CHANGED
|
@@ -2,16 +2,4 @@
|
|
|
2
2
|
/* Register the entry file directly: consumer ignore rules can hide nested dist folders. */
|
|
3
3
|
@source '../../dist/runtime/index.js';
|
|
4
4
|
|
|
5
|
-
/* Colors,
|
|
6
|
-
.rdx-skip-link {
|
|
7
|
-
position: fixed;
|
|
8
|
-
top: -100px;
|
|
9
|
-
left: 16px;
|
|
10
|
-
z-index: 100;
|
|
11
|
-
padding: 12px;
|
|
12
|
-
background: var(--background);
|
|
13
|
-
color: var(--foreground);
|
|
14
|
-
}
|
|
15
|
-
.rdx-skip-link:focus {
|
|
16
|
-
top: 12px;
|
|
17
|
-
}
|
|
5
|
+
/* Colors, focus navigation and typography come from the shared UI theme. */
|