@immediately-run/grove 0.1.1
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/README.md +122 -0
- package/docs/ENGINE_BOUNDARY.md +233 -0
- package/llms.txt +115 -0
- package/package.json +82 -0
- package/src/App.tsx +131 -0
- package/src/GroveApp.css +2774 -0
- package/src/GroveWiki.tsx +386 -0
- package/src/components/AssetImage.tsx +58 -0
- package/src/components/Backlinks.tsx +104 -0
- package/src/components/Callout.tsx +26 -0
- package/src/components/ChildPages.tsx +40 -0
- package/src/components/DefaultLayout.tsx +27 -0
- package/src/components/Directory.tsx +65 -0
- package/src/components/DirectoryList.test.tsx +275 -0
- package/src/components/DirectoryList.tsx +189 -0
- package/src/components/DirectoryView.tsx +68 -0
- package/src/components/DocList.tsx +109 -0
- package/src/components/DocsByTag.tsx +13 -0
- package/src/components/Drawer.tsx +45 -0
- package/src/components/EntryHeader.tsx +51 -0
- package/src/components/FamilyTree.tsx +95 -0
- package/src/components/GroveAgent.tsx +264 -0
- package/src/components/GroveFooter.tsx +20 -0
- package/src/components/GroveNav.tsx +102 -0
- package/src/components/Icon.tsx +56 -0
- package/src/components/Infobox.tsx +19 -0
- package/src/components/Kbd.tsx +10 -0
- package/src/components/KeyValue.tsx +32 -0
- package/src/components/Lede.tsx +6 -0
- package/src/components/More.tsx +10 -0
- package/src/components/Outlet.tsx +11 -0
- package/src/components/PageMeta.tsx +24 -0
- package/src/components/PageView.tsx +98 -0
- package/src/components/Quote.tsx +36 -0
- package/src/components/RecentlyUpdated.tsx +6 -0
- package/src/components/SafeEntryBody.tsx +72 -0
- package/src/components/SafeLayout.tsx +35 -0
- package/src/components/ScrollToFragment.tsx +63 -0
- package/src/components/Search.tsx +127 -0
- package/src/components/Sidebar.tsx +118 -0
- package/src/components/TableOfContents.test.tsx +163 -0
- package/src/components/TableOfContents.tsx +101 -0
- package/src/components/TagCloud.tsx +46 -0
- package/src/components/TagList.tsx +31 -0
- package/src/components/Timeline.tsx +55 -0
- package/src/components/Toc.tsx +14 -0
- package/src/components/WikiLink.tsx +112 -0
- package/src/data/themes.ts +14 -0
- package/src/devfs.d.ts +4 -0
- package/src/hooks/useContentComponents.ts +122 -0
- package/src/hooks/useCorpusMetadata.ts +43 -0
- package/src/hooks/useDirectoryListing.ts +56 -0
- package/src/hooks/useHeadings.ts +96 -0
- package/src/hooks/useOpenWikiBoot.ts +95 -0
- package/src/index.css +120 -0
- package/src/lib/compose.test.ts +92 -0
- package/src/lib/compose.ts +99 -0
- package/src/lib/content.test.ts +269 -0
- package/src/lib/content.ts +267 -0
- package/src/lib/contentRoot.ts +61 -0
- package/src/lib/corpusComponents.test.ts +101 -0
- package/src/lib/corpusComponents.ts +117 -0
- package/src/lib/corpusScan.test.ts +157 -0
- package/src/lib/corpusScan.ts +105 -0
- package/src/lib/directory.test.ts +216 -0
- package/src/lib/directory.ts +262 -0
- package/src/lib/fragment.test.ts +88 -0
- package/src/lib/fragment.ts +55 -0
- package/src/lib/frontmatter.ts +26 -0
- package/src/lib/layout.ts +84 -0
- package/src/lib/openWiki.test.ts +216 -0
- package/src/lib/openWiki.ts +84 -0
- package/src/lib/queries.test.ts +74 -0
- package/src/lib/queries.ts +84 -0
- package/src/lib/safeIntrinsics.test.tsx +99 -0
- package/src/lib/safeIntrinsics.tsx +77 -0
- package/src/lib/safeRender.test.ts +359 -0
- package/src/lib/safeSources.ts +25 -0
- package/src/lib/shell.ts +71 -0
- package/src/lib/sourceCache.test.ts +66 -0
- package/src/lib/sourceCache.ts +42 -0
- package/src/lib/tocScroll.test.ts +71 -0
- package/src/lib/tocScroll.ts +93 -0
- package/src/lib/wiki.test.ts +194 -0
- package/src/lib/wiki.ts +175 -0
- package/src/lib.ts +54 -0
- package/src/main.tsx +19 -0
- package/src/mdx.d.ts +9 -0
- package/src/mdxComponents.ts +89 -0
- package/src/test/setup.ts +19 -0
- package/viewer-manifest.schema.json +62 -0
- package/viewer.manifest.json +267 -0
package/src/App.tsx
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
// The entry point immediately.run renders — deliberately a GATE, not the wiki.
|
|
2
|
+
//
|
|
3
|
+
// Grove ships in two packagings and they disagree about two things: where the corpus is,
|
|
4
|
+
// and who knows what is in it.
|
|
5
|
+
//
|
|
6
|
+
// • FORK — `/app/content/`, indexed by the bundler at build time. Both answers
|
|
7
|
+
// arrive before the app boots, so the gate falls straight through.
|
|
8
|
+
// • DISPATCH — a host-minted chroot at someone else's directory (R3-169), which the
|
|
9
|
+
// bundler never scanned, so the frontmatter index has to be BUILT
|
|
10
|
+
// (R3-265). Neither answer exists at first render.
|
|
11
|
+
//
|
|
12
|
+
// Every helper the wiki is made of — which keys are entries, what their hrefs are, which
|
|
13
|
+
// layouts wrap them — is a function of the root; every surface a reader sees — nav,
|
|
14
|
+
// sidebar, search, backlinks, routing, the 404 index — is a function of the index. A
|
|
15
|
+
// component that rendered before either was settled would show the VIEWER's corpus, or an
|
|
16
|
+
// empty one, and then not correct itself. Both are outcomes dispatch may never produce.
|
|
17
|
+
//
|
|
18
|
+
// Hence the split: this file resolves, `GroveWiki` renders.
|
|
19
|
+
|
|
20
|
+
import { use, useEffect, useRef } from 'react';
|
|
21
|
+
import * as sdk from '@immediately-run/sdk';
|
|
22
|
+
import { sendMessage } from '@immediately-run/sdk/sandboxUtils';
|
|
23
|
+
import { MetadataSource } from '@immediately-run/sdk';
|
|
24
|
+
import { TinkerableContext } from '@immediately-run/sdk/TinkerableContext';
|
|
25
|
+
import { MDXProvider } from '@immediately-run/sdk/MDXProvider';
|
|
26
|
+
import { useOpenWikiBoot } from './hooks/useOpenWikiBoot';
|
|
27
|
+
import { useCorpusMetadata } from './hooks/useCorpusMetadata';
|
|
28
|
+
import { useContentComponents } from './hooks/useContentComponents';
|
|
29
|
+
import { getContentRoot } from './lib/contentRoot';
|
|
30
|
+
import { viewedDocumentForTarget } from './lib/content';
|
|
31
|
+
import GroveWiki from './GroveWiki';
|
|
32
|
+
|
|
33
|
+
// R3-268 — the viewed-document rule, registered ONCE at module load: every
|
|
34
|
+
// `navigate()`/`<Link>` navigation declares which file the destination renders,
|
|
35
|
+
// so the host's file explorer can highlight it. The mapping is
|
|
36
|
+
// `viewedDocumentForTarget` (lib/content): repo-relative for a fork,
|
|
37
|
+
// CORPUS-relative under dispatch — the host joins its chroot prefix, since the
|
|
38
|
+
// corpus's repo-side location is host knowledge this app cannot see. Resolved
|
|
39
|
+
// PER NAVIGATION, not captured: the content root is a function of dispatch
|
|
40
|
+
// state (see `contentRoot`). Guarded with `?.` so Grove still runs against an
|
|
41
|
+
// SDK generation without the hook (the host then falls back to the URL
|
|
42
|
+
// convention, which under dispatch simply yields no highlight). Highlight-only
|
|
43
|
+
// by contract — this never scrolls, never moves focus, never opens the editor.
|
|
44
|
+
(sdk as { setViewedDocumentResolver?: (r: (href: string) => string | null | undefined) => void })
|
|
45
|
+
.setViewedDocumentResolver?.(viewedDocumentForTarget);
|
|
46
|
+
|
|
47
|
+
export default function App() {
|
|
48
|
+
const host = use(TinkerableContext);
|
|
49
|
+
const boot = useOpenWikiBoot();
|
|
50
|
+
// R3-268 deep links: declare the INITIALLY rendered document once at boot. A
|
|
51
|
+
// fresh page load performs no navigation, so without this the host records no
|
|
52
|
+
// viewed document for a deep link and the explorer shows no highlight (nor
|
|
53
|
+
// ancestor dot) until the first in-app click. Carries no gesture: the host
|
|
54
|
+
// records it userInitiated=false — highlight-only, never a reveal. Waits for
|
|
55
|
+
// the boot resolution because the content root (and so the mapping) is a
|
|
56
|
+
// function of dispatch state. Fire-and-forget: no transport (plain `vite dev`)
|
|
57
|
+
// must not crash the wiki.
|
|
58
|
+
const declaredBootRef = useRef(false);
|
|
59
|
+
const outerHref = host?.outerHref;
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (declaredBootRef.current) return;
|
|
62
|
+
if (boot.status !== 'ready' && boot.status !== 'fork') return;
|
|
63
|
+
if (!outerHref) return;
|
|
64
|
+
declaredBootRef.current = true;
|
|
65
|
+
try {
|
|
66
|
+
sendMessage('viewed-document-declare', { value: viewedDocumentForTarget(outerHref) });
|
|
67
|
+
} catch {
|
|
68
|
+
/* no host transport — a standalone dev server render */
|
|
69
|
+
}
|
|
70
|
+
}, [boot.status, outerHref]);
|
|
71
|
+
// Only a dispatched viewer scans; a fork's index is already in the context.
|
|
72
|
+
const corpus = useCorpusMetadata(boot.status === 'ready' ? getContentRoot() : null);
|
|
73
|
+
// BOTH packagings, deliberately (R3-174). A corpus's own component vocabulary must not
|
|
74
|
+
// depend on how it was composed — `PLATFORM_LAYERING_SPEC` §1.1's mode-invariance rule —
|
|
75
|
+
// so a fork reads its marker too; that is one cheap open of a file already in `/app`.
|
|
76
|
+
// Gated on the boot status for the same reason the scan is: before the delegation
|
|
77
|
+
// resolves, `getContentRoot()` is still the fork default, and reading THAT marker under
|
|
78
|
+
// dispatch would register the viewer's own sample-corpus components against someone
|
|
79
|
+
// else's content.
|
|
80
|
+
const contentComponents = useContentComponents(
|
|
81
|
+
boot.status === 'ready' || boot.status === 'fork' ? getContentRoot() : null,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
if (boot.status === 'failed') {
|
|
85
|
+
return (
|
|
86
|
+
<div className="grove-boot">
|
|
87
|
+
<p className="grove-boot__msg">{boot.message}</p>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The provider must be COMPLETE before content paints (MDX_FROM_MOUNT_SPEC §2's
|
|
93
|
+
// invariant): rendering into a half-composed map would flash a missing-component error
|
|
94
|
+
// for `<RoadmapBoard>` until registration landed — the very error content components
|
|
95
|
+
// exist to remove — and a nested provider patched in afterwards would do the same.
|
|
96
|
+
// Holding here costs nothing, because the gate already exists for the corpus scan.
|
|
97
|
+
if (boot.status === 'waiting' || corpus.status === 'scanning' || contentComponents.status === 'loading') {
|
|
98
|
+
return (
|
|
99
|
+
<div className="grove-boot">
|
|
100
|
+
<p className="grove-boot__msg">Opening…</p>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Corpus-declared components (R3-174) go on as a nested provider, which the SDK's
|
|
106
|
+
// `useMDXComponents` resolves as `{...stock, ...content}` — so CONTENT WINS a name
|
|
107
|
+
// clash, and a wiki may override even `<DocsByTag>` with its own (value 4, max
|
|
108
|
+
// hackability). §2's "single-map merge, never provider nesting" was written against
|
|
109
|
+
// patching a provider in AFTER a partial render; nesting it INSIDE the gate above is
|
|
110
|
+
// that same merge, composed before anything paints.
|
|
111
|
+
const wiki = <GroveWiki readOnly={boot.readOnly} rejectedComponents={contentComponents.rejected} />;
|
|
112
|
+
const withComponents =
|
|
113
|
+
contentComponents.status === 'ready' && Object.keys(contentComponents.components).length > 0 ? (
|
|
114
|
+
<MDXProvider components={contentComponents.components}>{wiki}</MDXProvider>
|
|
115
|
+
) : (
|
|
116
|
+
wiki
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
if (corpus.status === 'ready' && corpus.metadata) {
|
|
120
|
+
// Provide the scanned corpus as the metadata SOURCE through the supported
|
|
121
|
+
// surface (R3-276), not a wholesale TinkerableContext re-provision: the
|
|
122
|
+
// platform stays free to grow its own state, and the hooks read the nearest
|
|
123
|
+
// MetadataSource — so every consumer works unchanged, and nothing re-states
|
|
124
|
+
// host fields it does not own.
|
|
125
|
+
return (
|
|
126
|
+
<MetadataSource value={corpus.metadata}>{withComponents}</MetadataSource>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return withComponents;
|
|
131
|
+
}
|