Skip to content

Commit 91d36ad

Browse files
feat(library)!: consolidate @tumaet/apollon to a single entry with required peers (#785)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e4a44f2 commit 91d36ad

92 files changed

Lines changed: 990 additions & 547 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/library-theming-api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
Adds a public theming API for embedding hosts. You can now theme the editor with a typed helper instead of hand-writing CSS variables: `createApollonTheme()` maps a structured `ApollonTheme` (primary, background, grid, etc.) to the underlying `--apollon-*` custom properties, and `<Apollon>` accepts optional `theme` and `dataTheme` props (also available as `ApollonOptions` fields) that are applied to the editor mount node.
66

77
```ts
8-
import { Apollon, createApollonTheme } from "@tumaet/apollon/react"
8+
import { Apollon, createApollonTheme } from "@tumaet/apollon"
99

1010
<Apollon theme={createApollonTheme({ primary: "#6d28d9", background: "#0b0b0c" })} dataTheme="dark" />
1111
```
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
"@tumaet/apollon": major
3+
---
4+
5+
Everything ships from one entry now: `@tumaet/apollon` exports the `<Apollon>` React component, the hooks, the provider, and the imperative `ApollonEditor` API together, with every dependency external. `react`, `react-dom`, and `@xyflow/react` are required peers alongside `yjs` / `y-protocols`, so your app and the editor share a single copy of each — no duplicate React, and your bundle analyzer / SBOM sees the real packages instead of a copy inlined into one chunk.
6+
7+
If you imported from the `/react` or `/external` subpaths, switch to `@tumaet/apollon`:
8+
9+
- `@tumaet/apollon/external``@tumaet/apollon` — same `ApollonEditor` API, just drop the subpath.
10+
- `@tumaet/apollon/react``@tumaet/apollon` — the component, hooks, and provider are on the main entry.
11+
- Install the peers if you haven't: `react react-dom @xyflow/react` (npm 7+ auto-installs them; pnpm/yarn users add them explicitly).
12+
- The main entry is a client module (`"use client"`) — import it from client components, not React Server Components.
13+
- `@tumaet/apollon/internals` and `@tumaet/apollon/export` are unchanged.
14+
15+
See the [Upgrading guide](https://ls1intum.github.io/Apollon/library/upgrading) for the full walkthrough.

.github/pull_request_template.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ Write "n/a — no Changesets-tracked package changed" if this PR doesn't touch @
2929
- [ ] Added a changeset whose summary is written in the user's voice (`pnpm changeset`, [how](https://ls1intum.github.io/Apollon/contributor/development/release-notes/)) — or this PR doesn't touch a Changesets-tracked package (`@tumaet/apollon`, `@tumaet/webapp`, `@tumaet/server`)
3030
- [ ] PR title's Conventional Commit type (`feat`/`fix`/…) matches the kind of change — it groups the release note
3131
- [ ] Tests added or updated
32+
- [ ] Ran `pnpm lint && pnpm format:check && pnpm build && pnpm test` locally — green
3233
- [ ] Documentation updated (if applicable)
3334
- [ ] Screenshots or screencasts attached (if a UI change)

.github/workflows/pr-health-checks.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ jobs:
3838
- 'library/**'
3939
- 'standalone/**'
4040
- 'vscode-extension/**'
41+
- 'docs/**'
42+
- 'scripts/**'
4143
- 'package.json'
4244
- 'pnpm-lock.yaml'
4345
- 'pnpm-workspace.yaml'
@@ -138,9 +140,22 @@ jobs:
138140
# needs `library/dist/` to exist — keep this step after build.
139141
run: pnpm --filter @tumaet/apollon-docs run typecheck
140142

143+
- name: Typecheck doc code examples
144+
# Compiles the ```ts / ```tsx examples in library/README.md,
145+
# library/THEMING.md and docs/library/** against the real
146+
# @tumaet/apollon types — fails if the public API drifts from the
147+
# docs. Resolves through docs/node_modules → library/dist, so it must
148+
# run after the build above.
149+
run: pnpm run check:doc-snippets
150+
141151
- name: Run unit tests
142152
run: pnpm run test
143153

154+
- name: Typecheck @tumaet/ui (incl. stories)
155+
# The declaration build excludes stories/tests (they are not public API),
156+
# so type-check the full source here to keep stories type-safe.
157+
run: pnpm --filter @tumaet/ui run typecheck
158+
144159
- name: Run shared-ui unit tests
145160
# The @tumaet/ui component suite (Base UI primitives + a11y behaviour).
146161
run: pnpm --filter @tumaet/ui run test
@@ -339,10 +354,10 @@ jobs:
339354
run: |
340355
node --input-type=module -e '
341356
const root = import.meta.resolve("@tumaet/apollon");
342-
const react = import.meta.resolve("@tumaet/apollon/react");
343357
const internals = import.meta.resolve("@tumaet/apollon/internals");
358+
const exportEntry = import.meta.resolve("@tumaet/apollon/export");
344359
const css = import.meta.resolve("@tumaet/apollon/style.css");
345-
console.log({ root, react, internals, css });
360+
console.log({ root, internals, exportEntry, css });
346361
'
347362
348363
- name: Lint published package shape (publint)
@@ -355,10 +370,8 @@ jobs:
355370
# decompressed buffer on each chunk callback instead of accumulating.
356371
# Any tarball that decompresses across multiple fflate chunks (ours
357372
# is ~750 KB → 3 chunks) crashes with `Cannot read properties of
358-
# undefined (reading 'filename')`. The standalone subpath
359-
# deliberately bundles peers (~2.4 MB) so the tarball is over
360-
# threshold by design. `publint` above plus the `import.meta.resolve`
361-
# exports-map check below cover the same ground.
373+
# undefined (reading 'filename')`. `publint` above plus the
374+
# `import.meta.resolve` exports-map check below cover the same ground.
362375
- name: Enforce bundle-size budget
363376
working-directory: library
364377
# Budgets in library/package.json#size-limit. Fails on regression

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,6 @@ docs/build/
7676

7777
# Stray pnpm store if pnpm is run outside the workspace root
7878
.pnpm-store/
79+
80+
# Temp dir used by scripts/check-doc-snippets.mjs (removed on each run)
81+
docs/.snippet-typecheck/

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Conventions for AI coding agents in this repo, the TUM UML diagram editor. Follo
1313

1414
A pnpm + Vite monorepo (the server compiles with `tsc`, not Vite).
1515

16-
- **`library/`**`@tumaet/apollon`, the embeddable React editor, published to npm. Native HTML + Base UI primitives (`@base-ui-components/react`) styled via `--apollon-*` CSS variables; `lucide-react` icons; Yjs collaboration — the live-cursor/presence layer lives here ([`collaboration.md`](docs/library/api/collaboration.md)).
16+
- **`library/`**`@tumaet/apollon`, the embeddable React editor, published to npm. Native HTML + Base UI primitives (`@base-ui/react`) styled via `--apollon-*` CSS variables; `lucide-react` icons; Yjs collaboration — the live-cursor/presence layer lives here ([`collaboration.md`](docs/library/api/collaboration.md)).
1717
- **`standalone/webapp/`**`@tumaet/webapp` (private). React + Vite + Tailwind; Capacitor for iOS/Android.
1818
- **`standalone/server/`**`@tumaet/server` (private). Express + Redis Stack (RedisJSON diagram storage + version history).
1919
- **`vscode-extension/`**`apollon-vscode`, with nested `menu/` and `editor/` webview sub-packages.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ This monorepo contains every piece of the Apollon platform:
1515
## Use the library
1616

1717
```sh
18-
npm install @tumaet/apollon yjs y-protocols
18+
npm install @tumaet/apollon react react-dom @xyflow/react yjs y-protocols
1919
```
2020

21-
`yjs` and `y-protocols` are required peer dependencies — they power Apollon's
22-
document model and undo/redo (and live collaboration when enabled), kept
23-
external so the host owns a single Yjs instance. See the
24-
[library README](./library/README.md) for the API and the other build entries.
21+
`react`, `react-dom`, `@xyflow/react`, `yjs`, and `y-protocols` are required
22+
peer dependencies — the editor renders on the host's single React and Yjs
23+
instance instead of bundling its own. See the
24+
[library README](./library/README.md) for the full API and per-framework guides.
2525

2626
## Run the stack locally
2727

docs/contributor/development/scripts.md

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@ Run a production build locally — assumes `pnpm build` already ran.
7070
Per-workspace variants (`lint:ui`, `lint:lib`, `lint:server`, `lint:webapp`,
7171
`lint:vscode`, `lint:docs`, and their `lint:fix:*` counterparts) exist for
7272
narrower runs.
73-
`lint:docs` runs `markdownlint-cli2` over the docs Markdown **and** `tsc
74-
--noEmit` on the Docusaurus config + theme.
73+
`lint:docs` runs `markdownlint-cli2` over the docs Markdown. Type-checking — the
74+
Docusaurus config/theme (`typecheck`) and the doc code examples
75+
(`check:doc-snippets`) — runs separately in CI, not as part of `lint`.
7576

7677
## Test
7778

@@ -93,15 +94,41 @@ Playwright visual regression lives in the webapp workspace — see
9394

9495
## Docs
9596

96-
| Script | Does |
97-
| ----------------- | ---------------------------------------------- |
98-
| `pnpm dev:docs` | Library build, then the Docusaurus dev server |
99-
| `pnpm build:docs` | Library build, then the static Docusaurus site |
97+
| Script | Does |
98+
| ------------------------- | ------------------------------------------------------ |
99+
| `pnpm dev:docs` | Library build, then the Docusaurus dev server |
100+
| `pnpm build:docs` | Library build, then the static Docusaurus site |
101+
| `pnpm check:doc-snippets` | Library build, then type-check the docs' code examples |
100102

101103
The docs site is published at <https://ls1intum.github.io/Apollon/>. The
102104
Docusaurus build uses `onBrokenLinks: "throw"`, so a bad internal link fails
103105
`build:docs`.
104106

107+
### Doc code examples are type-checked
108+
109+
`check:doc-snippets` (`scripts/check-doc-snippets.mjs`) compiles every fenced
110+
`ts`/`tsx` block in `library/README.md`, `library/THEMING.md`, and
111+
`docs/library/**` against the **real** built `@tumaet/apollon` types, so a public
112+
API change that breaks a documented example fails CI (`pr-health-checks`) instead
113+
of shipping rotten docs. Each block is checked as a standalone module, so it must
114+
carry its own imports.
115+
116+
Mark a block `no-check` in the fence info string to skip it — for bare fragments
117+
that reference an undeclared `editor`, type-signature illustrations, or
118+
framework-specific examples (`@angular/core`, `next/dynamic`, the resvg `?url`
119+
wasm import) that can't compile in isolation:
120+
121+
````md
122+
```ts no-check
123+
editor.fitView() // `editor` is illustrative, not declared here
124+
```
125+
````
126+
127+
The `no-check` token lives after the language in the info string, which
128+
Docusaurus, GitHub, and npm all ignore when rendering — readers never see it.
129+
Prefer making a block self-contained (add the imports) over `no-check` when it's
130+
a real copy-paste example.
131+
105132
## Capacitor
106133

107134
Mobile shell scaffolding for the webapp. Run these once per platform; see

docs/contributor/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pnpm dev
3636
## Pull-request checklist
3737

3838
```sh
39-
pnpm run lint # eslint per workspace + markdownlint + docs typecheck
39+
pnpm run lint # eslint per workspace + markdownlint
4040
pnpm run format:check
4141
pnpm run build # library first, then server + webapp concurrently
4242
pnpm test # library unit tests

docs/library/api.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ description: The complete ApollonEditor reference — constructor options, lifec
1010
into the DOM node you hand it and exposes an imperative API — your host code
1111
never touches React.
1212

13-
```ts
13+
```ts no-check
1414
import { ApollonEditor, UMLDiagramType } from "@tumaet/apollon"
1515
import "@tumaet/apollon/style.css"
1616

@@ -29,11 +29,11 @@ documented below remains the API for non-React hosts and for advanced control.
2929

3030
For React hosts, `<Apollon>` wraps `ApollonEditor` and owns its lifecycle: it
3131
constructs the editor on mount and destroys it on unmount. Import it from the
32-
`@tumaet/apollon/react` subpath — see [React](/library/embedding/react) for
32+
package's main entry, `@tumaet/apollon` — see [React](/library/embedding/react) for
3333
the full integration story (hooks, provider, ref, controlled-model overlay).
3434

3535
```tsx
36-
import { Apollon } from "@tumaet/apollon/react"
36+
import { Apollon } from "@tumaet/apollon"
3737
import "@tumaet/apollon/style.css"
3838
;<Apollon style={{ height: 600 }} />
3939
```
@@ -97,7 +97,7 @@ live value untouched (no reset). Re-key the component to fully reset.
9797

9898
## Constructor
9999

100-
```ts
100+
```ts no-check
101101
new ApollonEditor(element: HTMLElement, options?: ApollonOptions)
102102
```
103103

@@ -212,7 +212,7 @@ prev/next equality check.
212212
| `subscribeToCollaboratorChanges(cb)` | `(collaborators: CollaboratorInfo[]) => void` |
213213
| `unsubscribe(subscriptionId)` | `(number) => void` |
214214

215-
```ts
215+
```ts no-check
216216
const id = editor.subscribeToModelChange((model) => persist(model))
217217
// later
218218
editor.unsubscribe(id)

0 commit comments

Comments
 (0)