@octanejs/docusaurus 0.0.2 → 0.0.4

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.
@@ -0,0 +1,462 @@
1
+ import { createContext, useContext, type ComponentBody, type OctaneNode } from 'octane';
2
+ import { Link as RouterLink, type Location } from '@octanejs/remix-router';
3
+ import { Head, Seo } from '@octanejs/seo';
4
+ import { useDocusaurusManifest } from './client-components.tsrx';
5
+
6
+ type NavigationItem = {
7
+ label: string;
8
+ href?: string;
9
+ to?: string;
10
+ position?: 'left' | 'right';
11
+ };
12
+
13
+ type NavbarConfig = {
14
+ title?: string;
15
+ logo?: {
16
+ alt?: string;
17
+ href?: string;
18
+ src: string;
19
+ };
20
+ items?: NavigationItem[];
21
+ };
22
+
23
+ type FooterItem = {
24
+ label: string;
25
+ href?: string;
26
+ to?: string;
27
+ };
28
+
29
+ type FooterConfig = {
30
+ copyright?: string;
31
+ links?: Array<{
32
+ title: string;
33
+ items: FooterItem[];
34
+ }>;
35
+ };
36
+
37
+ type ClassicThemeConfig = {
38
+ navbar?: NavbarConfig;
39
+ footer?: FooterConfig;
40
+ };
41
+
42
+ type SidebarItem = {
43
+ type: string;
44
+ label: string;
45
+ href?: string;
46
+ key?: string;
47
+ items?: SidebarItem[];
48
+ };
49
+
50
+ type DocLink = {
51
+ title: string;
52
+ permalink: string;
53
+ description?: string;
54
+ };
55
+
56
+ type DocsVersion = {
57
+ label: string;
58
+ noIndex?: boolean;
59
+ docsSidebars: Record<string, SidebarItem[]>;
60
+ };
61
+
62
+ type DocMetadata = {
63
+ title?: string;
64
+ description?: string;
65
+ permalink?: string;
66
+ previous?: DocLink;
67
+ next?: DocLink;
68
+ };
69
+
70
+ type DocContent =
71
+ ComponentBody<Record<string, unknown>> & {
72
+ contentTitle?: string;
73
+ frontMatter?: {
74
+ title?: string;
75
+ description?: string;
76
+ noIndex?: boolean;
77
+ };
78
+ metadata?: DocMetadata;
79
+ };
80
+
81
+ type RouteProps = {
82
+ attributes?: Record<string, unknown>;
83
+ routes?: RouteProps[];
84
+ path?: string;
85
+ };
86
+
87
+ const VersionContext = createContext<DocsVersion | null>(null);
88
+
89
+ function isExternal(href: string): boolean {
90
+ return /^(?:[a-z][a-z\d+.-]*:|\/\/)/i.test(href);
91
+ }
92
+
93
+ function resolvedHref(item: { href?: string; to?: string }): string | null {
94
+ return item.to ?? item.href ?? null;
95
+ }
96
+
97
+ function withBaseUrl(baseUrl: string, href: string): string {
98
+ if (href === '' || isExternal(href) || href.startsWith('#')) return href;
99
+ if (href === baseUrl.replace(/\/$/, '')) return baseUrl;
100
+ if (href.startsWith(baseUrl)) return href;
101
+ return `${baseUrl}${href.replace(/^(?:\.\/|\/)/, '')}`;
102
+ }
103
+
104
+ function absoluteUrl(siteUrl: string, href: string): string {
105
+ try {
106
+ return new URL(href, siteUrl).href;
107
+ } catch {
108
+ return href;
109
+ }
110
+ }
111
+
112
+ function sidebarKey(item: SidebarItem): string {
113
+ return item.key ?? item.href ?? `${item.type}:${item.label}`;
114
+ }
115
+
116
+ function navigationKey(item: NavigationItem | FooterItem): string {
117
+ return resolvedHref(item) ?? item.label;
118
+ }
119
+
120
+ function findSidebarCategory(items: SidebarItem[], href: string): SidebarItem | null {
121
+ for (const item of items) {
122
+ if (item.type !== 'category') continue;
123
+ if (item.href === href) return item;
124
+ const nested = findSidebarCategory(item.items ?? [], href);
125
+ if (nested !== null) return nested;
126
+ }
127
+ return null;
128
+ }
129
+
130
+ function categoryItems(version: DocsVersion, href: string): DocLink[] {
131
+ for (const sidebar of Object.values(version.docsSidebars)) {
132
+ const category = findSidebarCategory(sidebar, href);
133
+ if (category === null) continue;
134
+ return (category.items ?? []).flatMap(
135
+ (item) => item.href === undefined
136
+ ? []
137
+ : [
138
+ {
139
+ title: item.label,
140
+ permalink: item.href,
141
+ },
142
+ ],
143
+ );
144
+ }
145
+ return [];
146
+ }
147
+
148
+ function useDocsVersion(): DocsVersion {
149
+ const version = useContext(VersionContext);
150
+ if (version === null) {
151
+ throw new Error('[@octanejs/docusaurus] The classic DocRoot requires DocVersionRoot.');
152
+ }
153
+ return version;
154
+ }
155
+
156
+ function ThemeLink(props: {
157
+ href: string;
158
+ class?: string;
159
+ 'aria-current'?: 'page';
160
+ children?: OctaneNode;
161
+ }) @{
162
+ @if (isExternal(props.href)) {
163
+ <a
164
+ href={props.href}
165
+ class={props.class}
166
+ aria-current={props['aria-current']}
167
+ >{props.children}</a>
168
+ } @else {
169
+ <RouterLink
170
+ to={props.href}
171
+ class={props.class}
172
+ aria-current={props['aria-current']}
173
+ >{props.children}</RouterLink>
174
+ }
175
+ }
176
+
177
+ function Navbar(props: { config?: NavbarConfig }) @{
178
+ const manifest = useDocusaurusManifest();
179
+ const title = props.config?.title ?? manifest.site.title;
180
+ const brandHref = withBaseUrl(manifest.baseUrl, props.config?.logo?.href ?? manifest.baseUrl);
181
+ const items = props.config?.items ?? [];
182
+
183
+ <header class="octane-docs-navbar">
184
+ <ThemeLink href={brandHref} class="octane-docs-navbar__brand">
185
+ @if (props.config?.logo !== undefined) {
186
+ <img
187
+ src={withBaseUrl(manifest.baseUrl, props.config.logo.src)}
188
+ alt={props.config.logo.alt ?? title}
189
+ />
190
+ }
191
+ <span>{title}</span>
192
+ </ThemeLink>
193
+ @if (items.length > 0) {
194
+ <nav aria-label="Primary">
195
+ <ul class="octane-docs-navbar__items">
196
+ @for (const item of items; key navigationKey(item)) {
197
+ @if (resolvedHref(item) !== null) {
198
+ <li>
199
+ <ThemeLink
200
+ href={withBaseUrl(manifest.baseUrl, resolvedHref(item)!)}
201
+ >{item.label}</ThemeLink>
202
+ </li>
203
+ }
204
+ }
205
+ </ul>
206
+ </nav>
207
+ }
208
+ </header>
209
+ }
210
+
211
+ function Footer(props: { baseUrl: string; config?: FooterConfig }) @{
212
+ const groups = props.config?.links ?? [];
213
+ // Docusaurus treats the developer-provided copyright as trusted site HTML.
214
+ const copyright = props.config?.copyright;
215
+
216
+ @if (groups.length > 0 || copyright !== undefined) {
217
+ <footer class="octane-docs-footer">
218
+ @if (groups.length > 0) {
219
+ <ul class="octane-docs-footer__links">
220
+ @for (const group of groups; key group.title) {
221
+ <li>
222
+ <strong>{group.title}</strong>
223
+ <ul class="octane-docs-footer__items">
224
+ @for (const item of group.items; key navigationKey(item)) {
225
+ @if (resolvedHref(item) !== null) {
226
+ <li>
227
+ <ThemeLink
228
+ href={withBaseUrl(props.baseUrl, resolvedHref(item)!)}
229
+ >{item.label}</ThemeLink>
230
+ </li>
231
+ }
232
+ }
233
+ </ul>
234
+ </li>
235
+ }
236
+ </ul>
237
+ }
238
+ @if (copyright !== undefined) {
239
+ <div
240
+ class="octane-docs-footer__copyright"
241
+ dangerouslySetInnerHTML={{ __html: copyright }}
242
+ />
243
+ }
244
+ </footer>
245
+ }
246
+ }
247
+
248
+ function SidebarItems(props: { items: SidebarItem[]; pathname: string }) @{
249
+ <ul>
250
+ @for (const item of props.items; key sidebarKey(item)) {
251
+ <li>
252
+ @if (item.type === 'category' && item.items !== undefined) {
253
+ <>
254
+ @if (item.href !== undefined) {
255
+ <ThemeLink
256
+ href={item.href}
257
+ class="octane-docs-sidebar__category"
258
+ aria-current={item.href === props.pathname ? 'page' : undefined}
259
+ >{item.label}</ThemeLink>
260
+ } @else {
261
+ <span class="octane-docs-sidebar__category">{item.label}</span>
262
+ }
263
+ <SidebarItems items={item.items} pathname={props.pathname} />
264
+ </>
265
+ } @else if (item.href !== undefined) {
266
+ <ThemeLink
267
+ href={item.href}
268
+ aria-current={item.href === props.pathname ? 'page' : undefined}
269
+ >{item.label}</ThemeLink>
270
+ } @else {
271
+ <span>{item.label}</span>
272
+ }
273
+ </li>
274
+ }
275
+ </ul>
276
+ }
277
+
278
+ function PageMetadata(props: {
279
+ title?: string;
280
+ description?: string;
281
+ permalink?: string;
282
+ noIndex?: boolean;
283
+ }) @{
284
+ const manifest = useDocusaurusManifest();
285
+ const title =
286
+ props.title === undefined || props.title === manifest.site.title
287
+ ? manifest.site.title
288
+ : `${props.title} | ${manifest.site.title}`;
289
+
290
+ <Head>
291
+ <Seo
292
+ title={title}
293
+ description={props.description}
294
+ canonical={props.permalink === undefined
295
+ ? undefined
296
+ : absoluteUrl(manifest.site.url, props.permalink)}
297
+ openGraph={{ title, description: props.description }}
298
+ robots={props.noIndex === true ? { index: false, follow: false } : undefined}
299
+ />
300
+ </Head>
301
+ }
302
+
303
+ function Paginator(props: { previous?: DocLink; next?: DocLink }) @{
304
+ @if (props.previous !== undefined || props.next !== undefined) {
305
+ <nav class="octane-docs-paginator" aria-label="Documentation pages">
306
+ <div>
307
+ @if (props.previous !== undefined) {
308
+ <ThemeLink href={props.previous.permalink}>← {props.previous.title}</ThemeLink>
309
+ }
310
+ </div>
311
+ <div class="octane-docs-paginator__next">
312
+ @if (props.next !== undefined) {
313
+ <ThemeLink href={props.next.permalink}>{props.next.title} →</ThemeLink>
314
+ }
315
+ </div>
316
+ </nav>
317
+ }
318
+ }
319
+
320
+ function CardList(props: { items: DocLink[] }) @{
321
+ <ul class="octane-docs-card-list">
322
+ @for (const item of props.items; key item.permalink) {
323
+ <li class="octane-docs-card">
324
+ <ThemeLink href={item.permalink}>{item.title}</ThemeLink>
325
+ @if (item.description !== undefined) {
326
+ <p>{item.description}</p>
327
+ }
328
+ </li>
329
+ }
330
+ </ul>
331
+ }
332
+
333
+ export function Root(props: { children?: OctaneNode }) @{
334
+ <>
335
+ {props.children}
336
+ </>
337
+ }
338
+
339
+ export function DocsRoot(props: { children?: OctaneNode }) @{
340
+ const manifest = useDocusaurusManifest();
341
+ const themeConfig = manifest.site.themeConfig as ClassicThemeConfig;
342
+
343
+ <div class="octane-docusaurus">
344
+ <Navbar config={themeConfig.navbar} />
345
+ {props.children}
346
+ <Footer baseUrl={manifest.baseUrl} config={themeConfig.footer} />
347
+ </div>
348
+ }
349
+
350
+ export function DocVersionRoot(props: { children?: OctaneNode; version: DocsVersion }) @{
351
+ <VersionContext.Provider value={props.version}>{props.children}</VersionContext.Provider>
352
+ }
353
+
354
+ export function DocRoot(props: {
355
+ children?: OctaneNode;
356
+ location: Location;
357
+ route: RouteProps;
358
+ }) @{
359
+ const version = useDocsVersion();
360
+ const activeRoute = props.route.routes?.find((route) => route.path === props.location.pathname);
361
+ const sidebarId = activeRoute?.attributes?.sidebar;
362
+ const sidebar =
363
+ typeof sidebarId === 'string' ? version.docsSidebars[sidebarId] ?? [] : [];
364
+
365
+ <div class="octane-docs-layout">
366
+ @if (sidebar.length > 0) {
367
+ <aside class="octane-docs-sidebar" aria-label="Documentation sidebar">
368
+ <SidebarItems items={sidebar} pathname={props.location.pathname} />
369
+ </aside>
370
+ }
371
+ <main class="octane-docs-main">{props.children}</main>
372
+ </div>
373
+ }
374
+
375
+ export function DocItem(props: { content: DocContent }) @{
376
+ const manifest = useDocusaurusManifest();
377
+ const version = useDocsVersion();
378
+ const Content = props.content;
379
+ const metadata = Content.metadata ?? {};
380
+ const frontMatter = Content.frontMatter ?? {};
381
+ const title = frontMatter.title ?? metadata.title ?? Content.contentTitle;
382
+ const description = frontMatter.description ?? metadata.description;
383
+
384
+ <>
385
+ <PageMetadata
386
+ title={title}
387
+ description={description}
388
+ permalink={metadata.permalink}
389
+ noIndex={frontMatter.noIndex === true || version.noIndex === true || manifest.site.noIndex}
390
+ />
391
+ <article class="octane-docs-article">
392
+ <Content />
393
+ <Paginator previous={metadata.previous} next={metadata.next} />
394
+ </article>
395
+ </>
396
+ }
397
+
398
+ export function DocCategoryGeneratedIndexPage(props: {
399
+ categoryGeneratedIndex: {
400
+ title: string;
401
+ description?: string;
402
+ permalink: string;
403
+ navigation?: {
404
+ previous?: DocLink;
405
+ next?: DocLink;
406
+ };
407
+ };
408
+ }) @{
409
+ const version = useDocsVersion();
410
+ const page = props.categoryGeneratedIndex;
411
+ const items = categoryItems(version, page.permalink);
412
+ <div class="octane-docs-list-page">
413
+ <PageMetadata
414
+ title={page.title}
415
+ description={page.description}
416
+ permalink={page.permalink}
417
+ noIndex={version.noIndex}
418
+ />
419
+ <h1>{page.title}</h1>
420
+ @if (page.description !== undefined) {
421
+ <p>{page.description}</p>
422
+ }
423
+ <CardList items={items} />
424
+ <Paginator previous={page.navigation?.previous} next={page.navigation?.next} />
425
+ </div>
426
+ }
427
+
428
+ export function DocTagsListPage(props: {
429
+ tags: Array<{ label: string; permalink: string; description?: string }>;
430
+ location: Location;
431
+ }) @{
432
+ const version = useDocsVersion();
433
+ <div class="octane-docs-list-page">
434
+ <PageMetadata title="Tags" permalink={props.location.pathname} noIndex={version.noIndex} />
435
+ <h1>Tags</h1>
436
+ <CardList items={props.tags.map((tag) => ({ ...tag, title: tag.label }))} />
437
+ </div>
438
+ }
439
+
440
+ export function DocTagDocListPage(props: {
441
+ tag: {
442
+ label: string;
443
+ description?: string;
444
+ permalink: string;
445
+ items: DocLink[];
446
+ };
447
+ }) @{
448
+ const version = useDocsVersion();
449
+ <div class="octane-docs-list-page">
450
+ <PageMetadata
451
+ title={props.tag.label}
452
+ description={props.tag.description}
453
+ permalink={props.tag.permalink}
454
+ noIndex={version.noIndex}
455
+ />
456
+ <h1>{props.tag.label}</h1>
457
+ @if (props.tag.description !== undefined) {
458
+ <p>{props.tag.description}</p>
459
+ }
460
+ <CardList items={props.tag.items} />
461
+ </div>
462
+ }
package/src/theme.js ADDED
@@ -0,0 +1,25 @@
1
+ import { fileURLToPath } from 'node:url';
2
+
3
+ const THEME_PATH = fileURLToPath(new URL('./theme', import.meta.url));
4
+ const STYLES_PATH = fileURLToPath(new URL('./theme/styles.css', import.meta.url));
5
+
6
+ /**
7
+ * Docusaurus theme plugin exposing Octane-authored docs route components.
8
+ *
9
+ * Add this function to `themes` in `docusaurus.config.*`. Docusaurus remains
10
+ * responsible for content/plugin loading; the Octane Vite bridge resolves the
11
+ * returned theme modules and imports the client stylesheet.
12
+ */
13
+ export default function octaneClassicTheme() {
14
+ return {
15
+ name: '@octanejs/docusaurus-theme-classic',
16
+ getThemePath() {
17
+ return THEME_PATH;
18
+ },
19
+ getClientModules() {
20
+ return [STYLES_PATH];
21
+ },
22
+ };
23
+ }
24
+
25
+ export { octaneClassicTheme };
package/src/vite.js CHANGED
@@ -3,9 +3,12 @@ import { createOctaneCompiler } from 'octane/compiler/bundler';
3
3
  import { compileDocusaurusMdx } from './mdx.js';
4
4
  import { loadDocusaurusSite } from './load-site.js';
5
5
  import { createDocusaurusManifest, resolveDocusaurusId } from './manifest.js';
6
+ import { collectDocusaurusRouteModuleReferences } from './route-modules.js';
6
7
 
7
8
  export const DOCUSAURUS_MANIFEST_ID = 'virtual:octane-docusaurus-manifest';
9
+ export const DOCUSAURUS_ROUTES_ID = 'virtual:octane-docusaurus-routes';
8
10
  const RESOLVED_DOCUSAURUS_MANIFEST_ID = `\0${DOCUSAURUS_MANIFEST_ID}`;
11
+ const RESOLVED_DOCUSAURUS_ROUTES_ID = `\0${DOCUSAURUS_ROUTES_ID}`;
9
12
 
10
13
  function cleanId(id) {
11
14
  return id.split(/[?#]/, 1)[0];
@@ -27,6 +30,27 @@ function serializableManifest(manifest) {
27
30
  .replace(/</g, '\\u003c');
28
31
  }
29
32
 
33
+ function clientRoutesModule(manifest) {
34
+ const clientModules = manifest.assets.clientModules
35
+ .map((specifier) => `import ${JSON.stringify(specifier)};\n`)
36
+ .join('');
37
+ const importers = [...collectDocusaurusRouteModuleReferences(manifest.routes)]
38
+ .sort(([left], [right]) => left.localeCompare(right))
39
+ .map(
40
+ ([key, specifier]) => `\t${JSON.stringify(key)}: () => import(${JSON.stringify(specifier)}),`,
41
+ )
42
+ .join('\n');
43
+ return `${clientModules}import { createDocusaurusRoutes } from "@octanejs/docusaurus/client";
44
+ import manifest from ${JSON.stringify(DOCUSAURUS_MANIFEST_ID)};
45
+
46
+ export { manifest };
47
+ export const routeModules = {
48
+ ${importers}
49
+ };
50
+ export const routes = createDocusaurusRoutes(manifest, routeModules);
51
+ `;
52
+ }
53
+
30
54
  function createSharedState(options) {
31
55
  let loaded;
32
56
  let manifest;
@@ -76,6 +100,17 @@ function createSharedState(options) {
76
100
  }
77
101
 
78
102
  export function docusaurusBridge(options = {}, shared = createSharedState(options)) {
103
+ let server;
104
+
105
+ function invalidateVirtualModules() {
106
+ if (server === undefined) return;
107
+ for (const id of [RESOLVED_DOCUSAURUS_MANIFEST_ID, RESOLVED_DOCUSAURUS_ROUTES_ID]) {
108
+ const module = server.moduleGraph.getModuleById(id);
109
+ if (module !== undefined) server.moduleGraph.invalidateModule(module);
110
+ }
111
+ server.ws.send({ type: 'full-reload' });
112
+ }
113
+
79
114
  return {
80
115
  name: 'octane-docusaurus-bridge',
81
116
  enforce: 'pre',
@@ -83,6 +118,9 @@ export function docusaurusBridge(options = {}, shared = createSharedState(option
83
118
  getManifest: () => shared.getManifest(),
84
119
  reload: () => shared.refresh(),
85
120
  },
121
+ configureServer(value) {
122
+ server = value;
123
+ },
86
124
  async configResolved(config) {
87
125
  shared.setRoot(config.root ?? process.cwd());
88
126
  await shared.refresh();
@@ -102,18 +140,28 @@ export function docusaurusBridge(options = {}, shared = createSharedState(option
102
140
  const resolved = path.isAbsolute(source) ? source : resolveDocusaurusId(source, manifest);
103
141
  if (resolved !== null) this.addWatchFile?.(cleanId(resolved));
104
142
  }
143
+ for (const clientModule of manifest.assets.clientModules) {
144
+ this.addWatchFile?.(cleanId(clientModule));
145
+ }
105
146
  },
106
147
  async watchChange() {
107
148
  await shared.refresh();
149
+ invalidateVirtualModules();
108
150
  },
109
151
  async resolveId(id) {
110
152
  if (id === DOCUSAURUS_MANIFEST_ID) return RESOLVED_DOCUSAURUS_MANIFEST_ID;
153
+ if (id === DOCUSAURUS_ROUTES_ID) return RESOLVED_DOCUSAURUS_ROUTES_ID;
111
154
  const manifest = await shared.getManifest();
112
155
  return resolveDocusaurusId(id, manifest);
113
156
  },
114
157
  async load(id) {
115
- if (id !== RESOLVED_DOCUSAURUS_MANIFEST_ID) return null;
116
- return `export default ${serializableManifest(await shared.getManifest())};\n`;
158
+ if (id === RESOLVED_DOCUSAURUS_MANIFEST_ID) {
159
+ return `export default ${serializableManifest(await shared.getManifest())};\n`;
160
+ }
161
+ if (id === RESOLVED_DOCUSAURUS_ROUTES_ID) {
162
+ return clientRoutesModule(await shared.getManifest());
163
+ }
164
+ return null;
117
165
  },
118
166
  };
119
167
  }
@@ -0,0 +1,58 @@
1
+ /// <reference path="./virtual.d.ts" />
2
+
3
+ import type { ComponentBody, OctaneNode } from 'octane';
4
+ import type {
5
+ DOMRouterOpts,
6
+ DataRouter,
7
+ Location,
8
+ MemoryRouterOpts,
9
+ NavigateFunction,
10
+ RouteObject,
11
+ } from '@octanejs/remix-router';
12
+ import type {
13
+ DocusaurusManifest,
14
+ DocusaurusManifestRoute,
15
+ DocusaurusPluginIdentifier,
16
+ } from './index.js';
17
+
18
+ export type DocusaurusRouteModuleNamespace = Record<string, unknown>;
19
+ export type DocusaurusRouteModuleImporter = () => Promise<DocusaurusRouteModuleNamespace>;
20
+ export type DocusaurusRouteModuleRegistry = Record<string, DocusaurusRouteModuleImporter>;
21
+
22
+ export interface DocusaurusRouteContext {
23
+ plugin: DocusaurusPluginIdentifier;
24
+ data: Record<string, unknown>;
25
+ }
26
+
27
+ export interface DocusaurusRouteComponentProps extends Record<string, unknown> {
28
+ route: DocusaurusManifestRoute & { routes: DocusaurusManifestRoute[] };
29
+ location: Location;
30
+ params: Readonly<Record<string, string | undefined>>;
31
+ navigate: NavigateFunction;
32
+ children?: OctaneNode;
33
+ }
34
+
35
+ export declare function createDocusaurusRoutes(
36
+ manifest: DocusaurusManifest,
37
+ registry: DocusaurusRouteModuleRegistry,
38
+ ): RouteObject[];
39
+
40
+ export declare function createDocusaurusBrowserRouter(
41
+ manifest: DocusaurusManifest,
42
+ registry: DocusaurusRouteModuleRegistry,
43
+ options?: DOMRouterOpts,
44
+ ): DataRouter;
45
+
46
+ export declare function createDocusaurusMemoryRouter(
47
+ manifest: DocusaurusManifest,
48
+ registry: DocusaurusRouteModuleRegistry,
49
+ options?: MemoryRouterOpts,
50
+ ): DataRouter;
51
+
52
+ export declare const DocusaurusRouterProvider: ComponentBody<{
53
+ manifest: DocusaurusManifest;
54
+ router: DataRouter;
55
+ }>;
56
+
57
+ export declare function useDocusaurusManifest(): DocusaurusManifest;
58
+ export declare function useDocusaurusRouteContext(): DocusaurusRouteContext;
@@ -0,0 +1,21 @@
1
+ import type { Root } from 'octane';
2
+ import type { DataRouter, DOMRouterOpts } from '@octanejs/remix-router';
3
+ import type { DocusaurusManifest } from './index.js';
4
+ import type { DocusaurusRouteModuleRegistry } from './client.js';
5
+
6
+ export interface DocusaurusHydrateOptions extends DOMRouterOpts {
7
+ identifierPrefix?: string;
8
+ signal?: AbortSignal;
9
+ }
10
+
11
+ export interface DocusaurusHydrationRoot {
12
+ root: Root;
13
+ router: DataRouter;
14
+ }
15
+
16
+ export declare function hydrateDocusaurusRoot(
17
+ container: Element,
18
+ manifest: DocusaurusManifest,
19
+ registry: DocusaurusRouteModuleRegistry,
20
+ options?: DocusaurusHydrateOptions,
21
+ ): Promise<DocusaurusHydrationRoot>;