@tangle-network/ui 11.5.0 → 11.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @tangle-network/ui
2
2
 
3
+ ## 11.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - b52965b: Load the `./editor` entry's optional peers through a dynamic `import()`.
8
+
9
+ The entry declares `@tiptap/*`, `@hocuspocus/provider` and `yjs` as optional peers, but reached them through static imports. A bundler resolves an uninstalled optional peer to a stub module that carries a default export only, so `import { EditorContent } from "@tiptap/react"` and `import { HocuspocusProvider } from "@hocuspocus/provider"` failed the build of every consumer that did not install them, with `MISSING_EXPORT`. The failure was not limited to `./editor`: `./files` reaches `DocumentEditorPane` through a lazy import, so `@tangle-network/ui/files` failed the same way.
10
+
11
+ `EditorProvider`, `TiptapEditor` and the local markdown editor are now built from namespaces that `loadCollaborationPeers`/`loadDocumentEditorPeers` resolve at first render. A consumer without the peers builds clean and sees an error that names the packages to install, and only when it renders an editor. Preview-only use of `DocumentEditorPane` needs no peer at all. The two loaders stay separate so the local markdown editor still runs on `@tiptap/react` and `@tiptap/starter-kit` alone, without yjs or Hocuspocus.
12
+
13
+ A bundler reads the literal specifier in a dynamic `import()`, so the clean build is not automatic in every bundler. Vite and Rollup leave the unresolved peer to run time on their own. esbuild does so only when the call carries a `.catch()`, which every peer import now has, and `pnpm test:package` builds the packed consumer under esbuild as well as Vite to hold that. webpack has no such rule: a webpack consumer that installs none of the peers must give `resolve.fallback` the value `false` for each one, which `packages/ui/README.md` documents.
14
+
15
+ `EditorProvider` loads `yjs` and `@hocuspocus/provider` on its own, through `loadEditorProviderPeers`. It reads no tiptap namespace, so a consumer that installs those two peers and drives its own editor from the provider's context keeps working — the same set the provider imported statically before.
16
+
17
+ Rendering an editor now goes through a `Suspense` boundary: `TiptapEditor` and the local editor show a "Loading editor…" placeholder for the first frame, and `EditorProvider` renders its children only after the peers land, because every child hook reads a context that only the loaded provider supplies.
18
+
3
19
  ## 11.5.0
4
20
 
5
21
  ### Minor Changes
package/README.md CHANGED
@@ -28,8 +28,33 @@ export function App() {
28
28
 
29
29
  ## Subpaths
30
30
 
31
- Fourteen named exports: `primitives`, `chat`, `run`, `openui`, `files`, `editor`, `markdown`, `auth`, `hooks`, `sdk-hooks`, `stores`, `types`, `utils`, `tool-previews`.
31
+ Sixteen named exports: `primitives`, `chat`, `run`, `openui`, `files`, `editor`, `markdown`, `auth`, `hooks`, `sdk-hooks`, `stores`, `types`, `utils`, `tool-previews`, `nav`, `redaction`.
32
32
 
33
33
  ## Optional peers
34
34
 
35
- `@nanostores/react`, `nanostores`, `@tanstack/react-query`, `@hocuspocus/provider`, `@tiptap/*`, `yjs` — install only the peers you actually use. The package will type-check and tree-shake without them.
35
+ `@tiptap/core`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-collaboration`, `@tiptap/extension-collaboration-caret`, `@hocuspocus/provider` and `yjs` back the `./editor` entry. The entry reaches every one of them through a dynamic `import()`, and gets a loud error that names the missing packages only when it renders an editor. `./editor` splits the cost three ways, so each surface costs only the peers it uses:
36
+
37
+ | Surface | Peers it needs |
38
+ | --- | --- |
39
+ | `DocumentEditorPane` in preview mode | none |
40
+ | `MarkdownDocumentEditor` (local) | `@tiptap/react`, `@tiptap/starter-kit` |
41
+ | `EditorProvider` (collaboration transport) | `@hocuspocus/provider`, `yjs` |
42
+ | `TiptapEditor` (collaborative) | all of the above, plus both collaboration extensions |
43
+
44
+ `EditorProvider` builds the document and the socket from `yjs` and `@hocuspocus/provider` alone, so a consumer that drives its own editor from its context — through `useEditorConnection`, `useCollaborators` and the other `./editor` hooks — installs those two and no tiptap package.
45
+
46
+ A bundler still reads the literal specifier in a dynamic `import()`, so what a consumer without the peers must do depends on the bundler:
47
+
48
+ | Bundler | A consumer that installs none of the peers |
49
+ | --- | --- |
50
+ | Vite, Rollup | Builds. The unresolved peer becomes a chunk that throws when it loads. |
51
+ | esbuild | Builds. Each import carries a `.catch()`, which moves the unresolved path from build time to run time. |
52
+ | webpack | Needs configuration. Give `resolve.fallback` the value `false` for each peer you do not install, for example `resolve: { fallback: { "@tiptap/react": false } }`. |
53
+
54
+ A TypeScript consumer resolves these entries through the emitted declarations, and those declarations name the optional peers in their own import statements. Keep `skipLibCheck: true` — the common default — and a consumer without the peers type-checks: its own imports resolve, and TypeScript skips the declaration files that name the packages it does not have. With `skipLibCheck: false`, TypeScript reads those files and reports `TS2307` for each absent peer; install the peers, or add a module declaration for each one you omit.
55
+
56
+ `pnpm test:package` builds a packed consumer that installs none of the peers, under both Vite and esbuild, and type-checks it. `scripts/validate-dist.mjs` rejects a static import of any of them, and rejects a dynamic import that lost its `.catch()`.
57
+
58
+ Because the peers now resolve at first render rather than at build time, a missing one surfaces as a thrown error while React renders. Wrap the editors in an error boundary, so the install list reaches a surface you control instead of unmounting the tree.
59
+
60
+ `nanostores` and `@nanostores/react` back `./stores`, and `react-router` backs `./nav`. Those two entries create their values at module scope, so they hold a static import and a consumer that imports them must install the peer. Every other entry stays free of all of these.
@@ -560,7 +560,7 @@ import { lazy, Suspense } from "react";
560
560
  import { Download as Download2, X as X3 } from "lucide-react";
561
561
  import { Fragment, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
562
562
  var LazyDocumentEditorPane = lazy(async () => {
563
- const module = await import("./document-editor-pane-MX3FIZSE.js");
563
+ const module = await import("./document-editor-pane-A3JURPW5.js");
564
564
  return { default: module.DocumentEditorPane };
565
565
  });
566
566
  function FileArtifactPane({