react-docs-ui 0.7.5 → 0.7.6

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.
Files changed (47) hide show
  1. package/dist/{DocsApp-B-VaP4ms.js → DocsApp-CCFHuucK.js} +138 -124
  2. package/dist/{MdxContent-CZLqZlNp.js → MdxContent-CJydH4kW.js} +1 -1
  3. package/dist/{MdxContent.lazy-i9phqEH3.js → MdxContent.lazy-ChT4eAlU.js} +1 -1
  4. package/dist/{SearchDialog-DWVre6R9.js → SearchDialog-Dh1RvEgs.js} +87 -85
  5. package/dist/{SearchRuntime-D0rSMKV3.js → SearchRuntime-wdAGDBv4.js} +5 -4
  6. package/dist/{architectureDiagram-2XIMDMQ5-DmhcSwl7.js → architectureDiagram-2XIMDMQ5-D5B3Bc8w.js} +1 -1
  7. package/dist/{chunk-GLR3WWYH-ShSppUzV.js → chunk-GLR3WWYH-C7t8eN-i.js} +1 -1
  8. package/dist/{chunk-NQ4KR5QH-BWRGvKed.js → chunk-NQ4KR5QH-ygKrPhgw.js} +1 -1
  9. package/dist/{chunk-WL4C6EOR-DLbU3P3W.js → chunk-WL4C6EOR-BX4P121X.js} +1 -1
  10. package/dist/{classDiagram-VBA2DB6C-D4y64v83.js → classDiagram-VBA2DB6C-CWWKW2ZN.js} +2 -2
  11. package/dist/{classDiagram-v2-RAHNMMFH-DXkt0Wd4.js → classDiagram-v2-RAHNMMFH-9SKKaVzh.js} +2 -2
  12. package/dist/{cose-bilkent-S5V4N54A-BX63fiTJ.js → cose-bilkent-S5V4N54A-DCXUWrka.js} +1 -1
  13. package/dist/docs-app.es.js +1 -1
  14. package/dist/{erDiagram-INFDFZHY-DjNq2UqZ.js → erDiagram-INFDFZHY-DdivnAXH.js} +1 -1
  15. package/dist/{flowDiagram-PKNHOUZH-AUeVhXRc.js → flowDiagram-PKNHOUZH-CgCGjn11.js} +1 -1
  16. package/dist/{mdx-components-m1cGPhc8.js → mdx-components-BLq-Umts.js} +1 -1
  17. package/dist/{mermaid.core-CtkJeRVj.js → mermaid.core-Dg_svxvF.js} +12 -12
  18. package/dist/{mindmap-definition-YRQLILUH-Cnl-qPDR.js → mindmap-definition-YRQLILUH-3st_5tCe.js} +1 -1
  19. package/dist/react-docs-ui.es.js +4 -4
  20. package/dist/{requirementDiagram-Z7DCOOCP-Bx6NAgqy.js → requirementDiagram-Z7DCOOCP-ClKKAQ0C.js} +1 -1
  21. package/dist/{stateDiagram-RAJIS63D-DFmbSHPX.js → stateDiagram-RAJIS63D-C8Ab__vp.js} +2 -2
  22. package/dist/{stateDiagram-v2-FVOUBMTO-TjYtTjLB.js → stateDiagram-v2-FVOUBMTO-BhQBkYI5.js} +2 -2
  23. package/dist/types/components/DocsLayout.d.ts.map +1 -1
  24. package/dist/types/components/ExportToolbar.d.ts +8 -1
  25. package/dist/types/components/ExportToolbar.d.ts.map +1 -1
  26. package/dist/types/components/HeaderNav.d.ts.map +1 -1
  27. package/dist/types/components/MobileSidebar.d.ts +2 -7
  28. package/dist/types/components/MobileSidebar.d.ts.map +1 -1
  29. package/dist/types/components/SearchLauncher.d.ts +2 -1
  30. package/dist/types/components/SearchLauncher.d.ts.map +1 -1
  31. package/dist/types/components/search/SearchProvider.d.ts +2 -1
  32. package/dist/types/components/search/SearchProvider.d.ts.map +1 -1
  33. package/dist/types/components/search/SearchRuntime.d.ts +2 -1
  34. package/dist/types/components/search/SearchRuntime.d.ts.map +1 -1
  35. package/dist/types/hooks/useScrollPosition.d.ts.map +1 -1
  36. package/dist/types/lib/config.d.ts +1 -0
  37. package/dist/types/lib/config.d.ts.map +1 -1
  38. package/dist/types/lib/search/runtime/search-engine.d.ts.map +1 -1
  39. package/dist/types/lib/search/runtime/types.d.ts +1 -0
  40. package/dist/types/lib/search/runtime/types.d.ts.map +1 -1
  41. package/package.json +143 -136
  42. package/scripts/cli.mjs +18 -0
  43. package/scripts/generate-changelog-index.mjs +89 -0
  44. package/scripts/generate-doc-git-meta.mjs +63 -0
  45. package/scripts/generate-llms-files.mjs +34 -0
  46. package/scripts/generate-search-index.mjs +236 -0
  47. package/scripts/generate-shiki-bundle.mjs +80 -0
@@ -0,0 +1,63 @@
1
+ import { promisify } from "node:util"
2
+ import { execFile } from "node:child_process"
3
+ import { glob } from "glob"
4
+ import path from "node:path"
5
+ import fs from "node:fs/promises"
6
+
7
+ const execFileAsync = promisify(execFile)
8
+ const rootDir = process.cwd()
9
+ const publicDir = path.join(rootDir, "public")
10
+ const outputPath = path.join(publicDir, "doc-git-meta.json")
11
+
12
+ async function getGitValue(args) {
13
+ try {
14
+ const { stdout } = await execFileAsync("git", args, { cwd: rootDir })
15
+ return stdout.trim()
16
+ } catch {
17
+ return ""
18
+ }
19
+ }
20
+
21
+ async function main() {
22
+ const repoRoot = (await getGitValue(["rev-parse", "--show-toplevel"])) || rootDir
23
+ const files = await glob("public/docs/**/*.{md,mdx}", {
24
+ cwd: rootDir,
25
+ absolute: true,
26
+ nodir: true,
27
+ })
28
+
29
+ const entries = []
30
+ for (const file of files) {
31
+ const relativePath = path.relative(repoRoot, file).replace(/\\/g, "/")
32
+ const [lastUpdated, author] = await Promise.all([
33
+ getGitValue(["log", "-1", "--format=%cI", "--", relativePath]),
34
+ getGitValue(["log", "-1", "--format=%an", "--", relativePath]),
35
+ ])
36
+ entries.push({
37
+ relativePath: path.relative(rootDir, file).replace(/\\/g, "/"),
38
+ meta: {
39
+ lastUpdated: lastUpdated || undefined,
40
+ author: author || undefined,
41
+ },
42
+ })
43
+ }
44
+ const docMeta = Object.fromEntries(
45
+ entries
46
+ .filter(({ meta }) => meta.lastUpdated || meta.author)
47
+ .map(({ relativePath, meta }) => [relativePath, meta])
48
+ )
49
+
50
+ const payload = {
51
+ generatedAt: new Date().toISOString(),
52
+ files: docMeta,
53
+ }
54
+
55
+ await fs.mkdir(publicDir, { recursive: true })
56
+ await fs.writeFile(outputPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8")
57
+ console.log(`[doc-git-meta] Wrote ${Object.keys(docMeta).length} entries to public/doc-git-meta.json`)
58
+ }
59
+
60
+ main().catch((error) => {
61
+ console.error("[doc-git-meta] Failed:", error)
62
+ process.exitCode = 1
63
+ })
@@ -0,0 +1,34 @@
1
+ import fs from "node:fs/promises"
2
+ import path from "node:path"
3
+ import { glob } from "glob"
4
+
5
+ const rootDir = process.cwd()
6
+ const publicDir = path.join(rootDir, "public")
7
+
8
+ function stripFrontmatter(source) {
9
+ if (!source.startsWith("---\n")) return source
10
+ const endIndex = source.indexOf("\n---\n", 4)
11
+ return endIndex === -1 ? source : source.slice(endIndex + 5)
12
+ }
13
+
14
+ async function main() {
15
+ const files = await glob("public/docs/**/*.{md,mdx}", { cwd: rootDir, absolute: true, nodir: true })
16
+ const docs = await Promise.all(files.map(async (file) => {
17
+ const relative = path.relative(rootDir, file).replace(/\\/g, "/")
18
+ const urlPath = relative.replace(/^public\/docs\//, "").replace(/\.(md|mdx)$/i, "")
19
+ const content = stripFrontmatter(await fs.readFile(file, "utf8")).trim()
20
+ return { relative, urlPath, content }
21
+ }))
22
+
23
+ const llms = docs.map((doc) => `- /${doc.urlPath} | ${doc.relative}`).join("\n")
24
+ const llmsFull = docs.map((doc) => `# /${doc.urlPath}\n\n${doc.content}`).join("\n\n")
25
+
26
+ await fs.writeFile(path.join(publicDir, "llms.txt"), `${llms}\n`, "utf8")
27
+ await fs.writeFile(path.join(publicDir, "llms-full.txt"), `${llmsFull}\n`, "utf8")
28
+ console.log(`[llms] Wrote ${docs.length} docs to llms.txt and llms-full.txt`)
29
+ }
30
+
31
+ main().catch((error) => {
32
+ console.error("[llms] Failed:", error)
33
+ process.exitCode = 1
34
+ })
@@ -0,0 +1,236 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ const ROOT_DIR = process.cwd()
5
+ const PUBLIC_DIR = path.join(ROOT_DIR, 'public')
6
+ const DOCS_DIR = path.join(PUBLIC_DIR, 'docs')
7
+
8
+ const SEARCH_INDEX_VERSION = '2.0.0'
9
+ const MAX_CONTENT_LENGTH = 300
10
+
11
+ function isChinese(text) {
12
+ return /[\u4e00-\u9fa5]/.test(text)
13
+ }
14
+
15
+ function tokenize(text) {
16
+ if (!text) return []
17
+ const tokens = []
18
+ const parts = text.split(/(\s+|[,。!?、;:""''()【】《》\n\r]+)/)
19
+ for (const part of parts) {
20
+ if (!part.trim()) continue
21
+ if (isChinese(part)) {
22
+ const chars = part.split('')
23
+ for (let i = 0; i < chars.length - 1; i++) {
24
+ tokens.push(chars[i] + chars[i + 1])
25
+ }
26
+ tokens.push(...chars.filter(c => c.trim()))
27
+ } else {
28
+ const words = part.toLowerCase().split(/[^a-zA-Z0-9]+/).filter(w => w.length > 0)
29
+ tokens.push(...words)
30
+ }
31
+ }
32
+ return [...new Set(tokens)]
33
+ }
34
+
35
+ function parseFrontmatter(content) {
36
+ const normalized = content.replace(/^\uFEFF/, '')
37
+ const lines = normalized.split(/\r?\n/)
38
+ const data = {}
39
+ let contentStart = 0
40
+ if (lines[0]?.startsWith('---')) {
41
+ let i = 1
42
+ while (i < lines.length && !lines[i]?.startsWith('---')) {
43
+ const line = lines[i]
44
+ const colonIndex = line?.indexOf(':') ?? -1
45
+ if (colonIndex > 0 && line) {
46
+ const key = line.substring(0, colonIndex).trim()
47
+ const value = line.substring(colonIndex + 1).trim()
48
+ data[key] = value
49
+ }
50
+ i++
51
+ }
52
+ if (i < lines.length && lines[i]?.startsWith('---')) {
53
+ contentStart = i + 1
54
+ }
55
+ }
56
+ return { data, content: lines.slice(contentStart).join('\n') }
57
+ }
58
+
59
+ function cleanContent(text) {
60
+ return text
61
+ .replace(/\s+/g, ' ')
62
+ .replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
63
+ .replace(/[#*`_~>|]/g, '')
64
+ .replace(/\$\$?[^$]+\$\$?/g, '')
65
+ .trim()
66
+ }
67
+
68
+ function extractTextContent(node) {
69
+ if (!node || typeof node !== 'object') return ''
70
+ if (node.type === 'text') return node.value || ''
71
+ if (node.type === 'inlineCode') return `\`${node.value || ''}\``
72
+ if (node.type === 'code') return node.value || ''
73
+ if ('children' in node && Array.isArray(node.children)) {
74
+ return node.children.map(extractTextContent).join(' ')
75
+ }
76
+ return ''
77
+ }
78
+
79
+ async function parseMarkdown(content) {
80
+ const { unified } = await import('unified')
81
+ const remarkParse = (await import('remark-parse')).default
82
+ const remarkGfm = (await import('remark-gfm')).default
83
+ const remarkMath = (await import('remark-math')).default
84
+
85
+ const { data: frontmatter, content: markdownContent } = parseFrontmatter(content)
86
+ const processor = unified().use(remarkParse).use(remarkGfm).use(remarkMath)
87
+ const tree = processor.parse(markdownContent)
88
+
89
+ const title = frontmatter.title || ''
90
+ const sections = []
91
+ let currentSection = null
92
+ let contentParts = []
93
+
94
+ const saveCurrentSection = () => {
95
+ if (currentSection && contentParts.length > 0) {
96
+ currentSection.content = cleanContent(contentParts.join(' '))
97
+ sections.push(currentSection)
98
+ }
99
+ contentParts = []
100
+ }
101
+
102
+ for (const node of tree.children) {
103
+ if (node.type === 'heading') {
104
+ saveCurrentSection()
105
+ currentSection = {
106
+ title: extractTextContent(node),
107
+ content: '',
108
+ level: node.depth,
109
+ }
110
+ } else if (currentSection) {
111
+ const text = extractTextContent(node)
112
+ if (text) contentParts.push(text)
113
+ }
114
+ }
115
+
116
+ saveCurrentSection()
117
+
118
+ if (sections.length === 0 && title) {
119
+ const allContent = []
120
+ for (const node of tree.children) {
121
+ const text = extractTextContent(node)
122
+ if (text) allContent.push(text)
123
+ }
124
+ if (allContent.length > 0) {
125
+ sections.push({
126
+ title,
127
+ content: cleanContent(allContent.join(' ')),
128
+ level: 1,
129
+ })
130
+ }
131
+ }
132
+
133
+ return { title, sections }
134
+ }
135
+
136
+ function scanDocsDirectory(docsDir, baseDir, lang, results = []) {
137
+ if (!fs.existsSync(docsDir)) return results
138
+ const entries = fs.readdirSync(docsDir, { withFileTypes: true })
139
+ for (const entry of entries) {
140
+ const fullPath = path.join(docsDir, entry.name)
141
+ if (entry.isDirectory()) {
142
+ scanDocsDirectory(fullPath, baseDir, lang, results)
143
+ } else if (entry.isFile() && ['.md', '.mdx'].includes(path.extname(entry.name))) {
144
+ results.push({ filePath: fullPath, relativePath: path.relative(baseDir, fullPath), lang })
145
+ }
146
+ }
147
+ return results
148
+ }
149
+
150
+ function generateId(docPath, sectionTitle) {
151
+ const base = docPath.replace(/[\/\\]/g, '-')
152
+ const anchor = sectionTitle.toLowerCase().replace(/[^\w\u4e00-\u9fa5]+/g, '-').replace(/^-+|-+$/g, '')
153
+ return anchor ? `${base}--${anchor}` : base
154
+ }
155
+
156
+ function buildUrl(lang, docPath, sectionTitle) {
157
+ const anchor = sectionTitle.toLowerCase().replace(/[^\w\u4e00-\u9fa5]+/g, '-').replace(/^-+|-+$/g, '')
158
+ let url = `/${lang}/${docPath}`
159
+ if (anchor) url += `#${anchor}`
160
+ return url
161
+ }
162
+
163
+ function truncateContent(content, maxLength) {
164
+ if (content.length <= maxLength) return content
165
+ return content.slice(0, maxLength)
166
+ }
167
+
168
+ async function generateSearchIndex(lang) {
169
+ console.log(`Generating search index for language: ${lang}`)
170
+ const docsLangDir = path.join(DOCS_DIR, lang)
171
+ const files = scanDocsDirectory(docsLangDir, path.join(PUBLIC_DIR, 'docs'), lang)
172
+ const sections = []
173
+
174
+ for (const file of files) {
175
+ try {
176
+ const content = fs.readFileSync(file.filePath, 'utf-8')
177
+ const docPath = file.relativePath
178
+ .replace(new RegExp(`^${lang}[/\\\\]`), '')
179
+ .replace(/\.(md|mdx)$/, '')
180
+ .replace(/[/\\]index$/, '')
181
+
182
+ const parsed = await parseMarkdown(content)
183
+
184
+ for (const section of parsed.sections) {
185
+ const id = generateId(docPath, section.title)
186
+ const url = buildUrl(lang, docPath, section.title)
187
+ const fullText = section.title + ' ' + section.content
188
+ const tokens = await tokenize(fullText)
189
+
190
+ sections.push({
191
+ id,
192
+ pageTitle: parsed.title,
193
+ sectionTitle: section.title,
194
+ content: truncateContent(section.content, MAX_CONTENT_LENGTH),
195
+ url,
196
+ lang,
197
+ tokens,
198
+ })
199
+ }
200
+ } catch (error) {
201
+ console.warn(`Failed to process ${file.filePath}:`, error.message)
202
+ }
203
+ }
204
+
205
+ return {
206
+ version: SEARCH_INDEX_VERSION,
207
+ generatedAt: Date.now(),
208
+ lang,
209
+ sections,
210
+ }
211
+ }
212
+
213
+ async function main() {
214
+ console.log('Starting search index generation...')
215
+ if (!fs.existsSync(DOCS_DIR)) {
216
+ console.error('Docs directory not found:', DOCS_DIR)
217
+ process.exit(1)
218
+ }
219
+
220
+ const entries = fs.readdirSync(DOCS_DIR, { withFileTypes: true })
221
+ const langs = entries.filter(e => e.isDirectory()).map(e => e.name)
222
+ console.log('Found languages:', langs.join(', '))
223
+
224
+ for (const lang of langs) {
225
+ const index = await generateSearchIndex(lang)
226
+ const outputPath = path.join(PUBLIC_DIR, `search-index-${lang}.json`)
227
+ fs.writeFileSync(outputPath, JSON.stringify(index))
228
+ console.log(`Generated: ${outputPath} (${index.sections.length} sections)`)
229
+ }
230
+ console.log('Search index generation complete!')
231
+ }
232
+
233
+ main().catch(error => {
234
+ console.error('Error generating search index:', error)
235
+ process.exit(1)
236
+ })
@@ -0,0 +1,80 @@
1
+ import fs from "node:fs"
2
+ import path from "node:path"
3
+ import yaml from "js-yaml"
4
+
5
+ const rootDir = process.cwd()
6
+ const configDir = path.join(rootDir, "public", "config")
7
+ const outputFile = path.join(rootDir, "src", "generated", "shiki-bundle.ts")
8
+ const defaultLangs = [
9
+ "javascript", "typescript", "jsx", "tsx", "bash", "shell",
10
+ "python", "java", "c", "cpp", "csharp", "go", "rust", "ruby",
11
+ "php", "swift", "kotlin", "sql", "json", "yaml", "toml",
12
+ "markdown", "html", "css", "scss", "less", "vue", "svelte",
13
+ "docker", "nginx", "xml", "diff", "regex",
14
+ ]
15
+ const langAliasMap = {
16
+ js: "javascript",
17
+ ts: "typescript",
18
+ sh: "shell",
19
+ shell: "bash",
20
+ yml: "yaml",
21
+ md: "markdown",
22
+ rb: "ruby",
23
+ py: "python",
24
+ dockerfile: "docker",
25
+ conf: "nginx",
26
+ }
27
+
28
+ function resolveLang(lang) {
29
+ const normalized = String(lang || "").trim().toLowerCase()
30
+ return normalized ? langAliasMap[normalized] || normalized : null
31
+ }
32
+
33
+ function readYamlConfig(fileName) {
34
+ const filePath = path.join(configDir, fileName)
35
+ return fs.existsSync(filePath) ? yaml.load(fs.readFileSync(filePath, "utf8")) : null
36
+ }
37
+
38
+ function collectBundleConfig() {
39
+ const configs = ["site.yaml", "site.en.yaml"].map(readYamlConfig).filter(Boolean)
40
+ const langs = new Set()
41
+ const themes = new Set()
42
+ for (const config of configs) {
43
+ const configuredLangs = config?.codeHighlight?.langs
44
+ const sourceLangs = Array.isArray(configuredLangs) && configuredLangs.length > 0 ? configuredLangs : defaultLangs
45
+ sourceLangs.forEach(lang => {
46
+ const resolved = resolveLang(lang)
47
+ if (resolved) langs.add(resolved)
48
+ })
49
+ themes.add(String(config?.codeHighlight?.lightTheme || "github-light").trim())
50
+ themes.add(String(config?.codeHighlight?.darkTheme || "github-dark").trim())
51
+ }
52
+ if (langs.size === 0) defaultLangs.forEach(lang => langs.add(resolveLang(lang)))
53
+ if (themes.size === 0) {
54
+ themes.add("github-light")
55
+ themes.add("github-dark")
56
+ }
57
+ return { langs: Array.from(langs).sort(), themes: Array.from(themes).sort() }
58
+ }
59
+
60
+ function toObjectEntries(values, basePath) {
61
+ return values.map(value => ` ${JSON.stringify(value)}: () => import(${JSON.stringify(`${basePath}/${value}`)}),`).join("\n")
62
+ }
63
+
64
+ function main() {
65
+ const bundleConfig = collectBundleConfig()
66
+ const fileContent = `export const siteShikiBundle = {
67
+ langs: {
68
+ ${toObjectEntries(bundleConfig.langs, "shiki/langs")}
69
+ },
70
+ themes: {
71
+ ${toObjectEntries(bundleConfig.themes, "shiki/themes")}
72
+ },
73
+ }
74
+ `
75
+ fs.mkdirSync(path.dirname(outputFile), { recursive: true })
76
+ fs.writeFileSync(outputFile, fileContent, "utf8")
77
+ console.log(`[shiki-bundle] generated ${path.relative(rootDir, outputFile)} with ${bundleConfig.langs.length} languages and ${bundleConfig.themes.length} themes`)
78
+ }
79
+
80
+ main()