@haklex/rich-compose 0.1.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/README.md +185 -0
- package/dist/core/compose.d.ts +4 -0
- package/dist/core/compose.d.ts.map +1 -0
- package/dist/core/dedup.d.ts +16 -0
- package/dist/core/dedup.d.ts.map +1 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/lazy.d.ts +11 -0
- package/dist/core/lazy.d.ts.map +1 -0
- package/dist/core/types.d.ts +62 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +146 -0
- package/dist/modules/chat/index.d.ts +5 -0
- package/dist/modules/chat/index.d.ts.map +1 -0
- package/dist/modules/chat/index.mjs +11 -0
- package/dist/modules/chat/module.d.ts +3 -0
- package/dist/modules/chat/module.d.ts.map +1 -0
- package/dist/modules/chat/node.d.ts +3 -0
- package/dist/modules/chat/node.d.ts.map +1 -0
- package/dist/modules/chat/node.mjs +2 -0
- package/dist/modules/chat/renderer.d.ts +4 -0
- package/dist/modules/chat/renderer.d.ts.map +1 -0
- package/dist/modules/chat/renderer.mjs +5 -0
- package/dist/modules/code-block/index.d.ts +3 -0
- package/dist/modules/code-block/index.d.ts.map +1 -0
- package/dist/modules/code-block/index.mjs +39 -0
- package/dist/modules/code-block/module.d.ts +12 -0
- package/dist/modules/code-block/module.d.ts.map +1 -0
- package/dist/modules/code-block/renderer.d.ts +4 -0
- package/dist/modules/code-block/renderer.d.ts.map +1 -0
- package/dist/modules/code-block/renderer.mjs +5 -0
- package/dist/modules/code-block/ssr-fallback.d.ts +13 -0
- package/dist/modules/code-block/ssr-fallback.d.ts.map +1 -0
- package/dist/modules/code-snippet/index.d.ts +5 -0
- package/dist/modules/code-snippet/index.d.ts.map +1 -0
- package/dist/modules/code-snippet/index.mjs +11 -0
- package/dist/modules/code-snippet/module.d.ts +3 -0
- package/dist/modules/code-snippet/module.d.ts.map +1 -0
- package/dist/modules/code-snippet/node.d.ts +3 -0
- package/dist/modules/code-snippet/node.d.ts.map +1 -0
- package/dist/modules/code-snippet/node.mjs +2 -0
- package/dist/modules/code-snippet/renderer.d.ts +4 -0
- package/dist/modules/code-snippet/renderer.d.ts.map +1 -0
- package/dist/modules/code-snippet/renderer.mjs +5 -0
- package/dist/modules/embed/index.d.ts +4 -0
- package/dist/modules/embed/index.d.ts.map +1 -0
- package/dist/modules/embed/index.mjs +17 -0
- package/dist/modules/embed/module.d.ts +11 -0
- package/dist/modules/embed/module.d.ts.map +1 -0
- package/dist/modules/embed/node.d.ts +3 -0
- package/dist/modules/embed/node.d.ts.map +1 -0
- package/dist/modules/embed/node.mjs +2 -0
- package/dist/modules/gallery/index.d.ts +5 -0
- package/dist/modules/gallery/index.d.ts.map +1 -0
- package/dist/modules/gallery/index.mjs +11 -0
- package/dist/modules/gallery/module.d.ts +3 -0
- package/dist/modules/gallery/module.d.ts.map +1 -0
- package/dist/modules/gallery/node.d.ts +3 -0
- package/dist/modules/gallery/node.d.ts.map +1 -0
- package/dist/modules/gallery/node.mjs +2 -0
- package/dist/modules/gallery/renderer.d.ts +4 -0
- package/dist/modules/gallery/renderer.d.ts.map +1 -0
- package/dist/modules/gallery/renderer.mjs +5 -0
- package/dist/modules/link-card/index.d.ts +3 -0
- package/dist/modules/link-card/index.d.ts.map +1 -0
- package/dist/modules/link-card/index.mjs +15 -0
- package/dist/modules/link-card/module.d.ts +9 -0
- package/dist/modules/link-card/module.d.ts.map +1 -0
- package/dist/modules/link-card/renderer.d.ts +4 -0
- package/dist/modules/link-card/renderer.d.ts.map +1 -0
- package/dist/modules/link-card/renderer.mjs +5 -0
- package/package.json +149 -0
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# @haklex/rich-compose
|
|
2
|
+
|
|
3
|
+
Compose primitives for haklex rich content renderers — Gundam-style assembly of Lexical nodes, sync/lazy renderers, and Provider stacks.
|
|
4
|
+
|
|
5
|
+
Status: experimental (`0.1.0`). The renderer side is being migrated from `@haklex/rich-kit-shiro/renderer`. The editor side is out of scope.
|
|
6
|
+
|
|
7
|
+
## Why
|
|
8
|
+
|
|
9
|
+
`@haklex/rich-kit-shiro/renderer` ships every default renderer eagerly: even when a consumer overrides `CodeBlock` or `LinkCard`, the upstream `shiki` and `LinkCardRenderer` chains stay in the production bundle. `rich-compose` solves three problems at once:
|
|
10
|
+
|
|
11
|
+
1. **Subtractable** — drop a module by not importing it.
|
|
12
|
+
2. **Replaceable** — swap a default renderer with no leftover bytes from the original.
|
|
13
|
+
3. **Extensible** — add new renderer slots (sync or lazy) without touching the package.
|
|
14
|
+
|
|
15
|
+
Tree-shake is enforced by physical subpath isolation (`./modules/<name>/node` separates Klasses from heavy renderer code) plus ESM-only emit.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm add @haklex/rich-compose
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Peer Dependencies
|
|
24
|
+
|
|
25
|
+
| Package | Version |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `react` / `react-dom` | `>=19` |
|
|
28
|
+
| `lexical` / `@lexical/react` | `^0.44.0` |
|
|
29
|
+
| `@haklex/rich-editor` | workspace |
|
|
30
|
+
| `@haklex/rich-static-renderer` | workspace |
|
|
31
|
+
|
|
32
|
+
Per-module upstream packages (`@haklex/rich-ext-*`, `@haklex/rich-renderer-*`) are optional peers — install only those you compose into your renderer.
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { composeRenderer } from '@haklex/rich-compose'
|
|
38
|
+
import { embedModule } from '@haklex/rich-compose/modules/embed'
|
|
39
|
+
import { codeBlockModule } from '@haklex/rich-compose/modules/code-block'
|
|
40
|
+
import { linkCardModule } from '@haklex/rich-compose/modules/link-card'
|
|
41
|
+
// import any modules you need...
|
|
42
|
+
|
|
43
|
+
const RichContent = composeRenderer({
|
|
44
|
+
modules: [embedModule, codeBlockModule, linkCardModule],
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// Render
|
|
48
|
+
<RichContent value={editorState} theme="light" variant="article" />
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`composeRenderer` returns a memoized React component compatible with `<RichRenderer>`'s prop surface (theme, variant, value, className, style, …).
|
|
52
|
+
|
|
53
|
+
## Three consumer modes
|
|
54
|
+
|
|
55
|
+
### Mode A — defaults
|
|
56
|
+
|
|
57
|
+
Import the module sugar. Klass + renderer + (optional) lazy/SSR fallback are wired automatically.
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { embedModule } from '@haklex/rich-compose/modules/embed'
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Mode B — custom renderer (tree-shake the default)
|
|
64
|
+
|
|
65
|
+
Import the Klass from the `/node` subpath; supply your own renderer. The default renderer's chunk never enters the bundle.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { GalleryNode } from '@haklex/rich-compose/modules/gallery/node'
|
|
69
|
+
|
|
70
|
+
const myGalleryModule: RichRendererModule = {
|
|
71
|
+
name: 'gallery',
|
|
72
|
+
nodes: [GalleryNode],
|
|
73
|
+
renderers: { Gallery: MyGalleryRenderer },
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
For modules with no custom Klass (most of the renderer-only modules), simply construct a module with the same `name` and your renderer:
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
const myLinkCardModule: RichRendererModule = {
|
|
81
|
+
name: 'link-card',
|
|
82
|
+
renderers: { LinkCard: MyLinkCardRenderer },
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Mode C — wrap the default
|
|
87
|
+
|
|
88
|
+
Pull the default renderer from `/renderer` and wrap it.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { LinkCardNode } from '@haklex/rich-compose/modules/link-card/node' // when applicable
|
|
92
|
+
import { LinkCardRenderer } from '@haklex/rich-compose/modules/link-card/renderer'
|
|
93
|
+
|
|
94
|
+
const wrappedModule: RichRendererModule = {
|
|
95
|
+
name: 'link-card',
|
|
96
|
+
renderers: {
|
|
97
|
+
LinkCard: (props) => (
|
|
98
|
+
<div className="extra-wrap">
|
|
99
|
+
<LinkCardRenderer {...props} />
|
|
100
|
+
</div>
|
|
101
|
+
),
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## `RichRendererModule` shape
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
interface RichRendererModule {
|
|
110
|
+
name: string // dedup key
|
|
111
|
+
nodes?: Klass<LexicalNode>[] // optional — omit for builtin types
|
|
112
|
+
renderers?: Partial<RendererConfig> // sync renderer map
|
|
113
|
+
Provider?: ComponentType<{ children: ReactNode }> // optional internal provider
|
|
114
|
+
lazyRenderers?: Partial<{ // code-split renderers
|
|
115
|
+
[K in RendererKey]: () => Promise<{ default: NonNullable<RendererConfig[K]> }>
|
|
116
|
+
}>
|
|
117
|
+
ssrFallback?: Partial<Record<RendererKey, ReactNode>> // deterministic fallback
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`composeRenderer` merges modules, dedups Klasses, wraps lazy loaders in `React.lazy` (factory built once per compose), stacks Providers, and always sets `NestedContentRendererProvider` to a recursive closure for nested editor states.
|
|
122
|
+
|
|
123
|
+
## Lazy modules
|
|
124
|
+
|
|
125
|
+
`code-block`, `excalidraw`, `katex`, and `mermaid` ship lazy by default. Each provides an `ssrFallback` that renders deterministically server-side and during hydration to avoid mismatches.
|
|
126
|
+
|
|
127
|
+
To override a lazy renderer (e.g., for a sync, pre-tokenized code block on SSR), pass an entry in `overrides`:
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
composeRenderer({
|
|
131
|
+
modules: [/* ... */],
|
|
132
|
+
overrides: { CodeBlock: PreTokenizedCodeBlock },
|
|
133
|
+
})
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The lazy chunk is still emitted but never fetched at runtime.
|
|
137
|
+
|
|
138
|
+
## Dedup rules
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
modules:
|
|
142
|
+
reference seen → skip silently
|
|
143
|
+
same name → warn (dev), replace previous module entirely
|
|
144
|
+
else → append
|
|
145
|
+
|
|
146
|
+
nodes:
|
|
147
|
+
reference seen → skip
|
|
148
|
+
same getType collision → throw at compose time
|
|
149
|
+
(multiple Klass instances break instanceof)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Module catalog
|
|
153
|
+
|
|
154
|
+
Implemented:
|
|
155
|
+
|
|
156
|
+
| Module | Klass | Renderer mode | Source |
|
|
157
|
+
| --- | --- | --- | --- |
|
|
158
|
+
| `embed` | `EmbedNode` | sync (via node decorate) | `rich-ext-embed` |
|
|
159
|
+
| `link-card` | builtin | sync | `rich-renderer-linkcard` |
|
|
160
|
+
| `gallery` | `GalleryNode` | sync | `rich-ext-gallery` |
|
|
161
|
+
| `code-snippet` | `CodeSnippetNode` | sync | `rich-ext-code-snippet` |
|
|
162
|
+
| `chat` | `ChatNode` | sync | `rich-ext-chat` |
|
|
163
|
+
| `code-block` | builtin | lazy + ssr fallback | `rich-renderer-codeblock` |
|
|
164
|
+
|
|
165
|
+
Planned (not yet shipped): `excalidraw`, `nested-doc`, `katex`, `mermaid`, `mention`, `poll`, `video`, `ruby`, `alert`, `banner`, `image`. See `docs/superpowers/specs/2026-05-08-rich-compose-design.md` for the full catalog and migration plan.
|
|
166
|
+
|
|
167
|
+
> **Note**: `@haklex/rich-editor` registers a wide set of custom Klasses in `customNodes` (LinkCard, Mention, Image, Video, KaTeX, Mermaid, Alert, Banner, Ruby, Tag, Poll, CodeBlock, Footnote, etc.). Modules for these contribute only renderer mappings — there is no Klass to register, hence no `node.ts` and no `/node` subpath.
|
|
168
|
+
|
|
169
|
+
## Sub-path exports
|
|
170
|
+
|
|
171
|
+
| Path | Description |
|
|
172
|
+
| --- | --- |
|
|
173
|
+
| `@haklex/rich-compose` | core: `composeRenderer`, types, helpers |
|
|
174
|
+
| `@haklex/rich-compose/modules/<name>` | full module barrel |
|
|
175
|
+
| `@haklex/rich-compose/modules/<name>/node` | Klass(es) only (when applicable) |
|
|
176
|
+
| `@haklex/rich-compose/modules/<name>/renderer` | default renderer only |
|
|
177
|
+
| `@haklex/rich-compose/style.css` | core styles (skeletons, layout shell) |
|
|
178
|
+
|
|
179
|
+
## Part of Haklex
|
|
180
|
+
|
|
181
|
+
This package is part of the [Haklex](../../README.md) rich editor ecosystem.
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/core/compose.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,OAAO,CAAA;AAIvF,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EAEtB,MAAM,SAAS,CAAA;AAoChB,wBAAgB,eAAe,CAC7B,IAAI,EAAE,sBAAsB,GAC3B,aAAa,CAAC,qBAAqB,CAAC,CAiDtC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Klass, LexicalNode } from 'lexical';
|
|
2
|
+
import { RichRendererModule } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Merge preset and modules, deduplicating by:
|
|
5
|
+
* 1. Same module reference → skip silently (idempotent)
|
|
6
|
+
* 2. Same module.name → replace previous module entirely; warn in dev
|
|
7
|
+
* 3. Else → append
|
|
8
|
+
*/
|
|
9
|
+
export declare function mergeModules(preset: RichRendererModule[] | undefined, modules: RichRendererModule[] | undefined): RichRendererModule[];
|
|
10
|
+
/**
|
|
11
|
+
* Dedup by class reference. Throws if two distinct Klasses share the same
|
|
12
|
+
* `getType()` — multiple Klass instances will break `instanceof` checks
|
|
13
|
+
* across module boundaries.
|
|
14
|
+
*/
|
|
15
|
+
export declare function dedupNodes(nodes: Klass<LexicalNode>[]): Klass<LexicalNode>[];
|
|
16
|
+
//# sourceMappingURL=dedup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../src/core/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAEjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,kBAAkB,EAAE,GAAG,SAAS,EACxC,OAAO,EAAE,kBAAkB,EAAE,GAAG,SAAS,GACxC,kBAAkB,EAAE,CA0BtB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC,EAAE,CAyB5E"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { composeRenderer } from './compose';
|
|
2
|
+
export { dedupNodes, mergeModules } from './dedup';
|
|
3
|
+
export { wrapLazy } from './lazy';
|
|
4
|
+
export type { ComposeRendererOptions, RendererKey, RichRendererBaseProps, RichRendererModule, } from './types';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACjC,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RendererConfig } from '@haklex/rich-editor';
|
|
2
|
+
import { RichRendererModule } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Build sync wrappers around `React.lazy(loader)` factories.
|
|
5
|
+
*
|
|
6
|
+
* Each factory is created exactly **once** at compose time, not per render.
|
|
7
|
+
* Recreating the factory on every render would force React to refetch the
|
|
8
|
+
* chunk and replay the Suspense fallback, causing flicker.
|
|
9
|
+
*/
|
|
10
|
+
export declare function wrapLazy(modules: RichRendererModule[]): Partial<RendererConfig>;
|
|
11
|
+
//# sourceMappingURL=lazy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../../src/core/lazy.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAIzD,OAAO,KAAK,EAAe,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAE9D;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAsB/E"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { RendererConfig, RichEditorVariant } from '@haklex/rich-editor';
|
|
2
|
+
import { BuiltinNodeRenderer } from '@haklex/rich-static-renderer';
|
|
3
|
+
import { Klass, LexicalNode, SerializedEditorState } from 'lexical';
|
|
4
|
+
import { ComponentType, CSSProperties, ReactNode } from 'react';
|
|
5
|
+
export type RendererKey = keyof RendererConfig;
|
|
6
|
+
export interface RichRendererModule {
|
|
7
|
+
/** Stable identifier; used for dedup, debug logs, and Provider DevTools naming. */
|
|
8
|
+
name: string;
|
|
9
|
+
/**
|
|
10
|
+
* Lexical node classes. Always synchronous. Optional — modules that only
|
|
11
|
+
* override renderers for Lexical builtin types omit this field.
|
|
12
|
+
* composeRenderer treats missing `nodes` as `[]`.
|
|
13
|
+
*/
|
|
14
|
+
nodes?: Klass<LexicalNode>[];
|
|
15
|
+
/** type → Component map. Sync renderers. */
|
|
16
|
+
renderers?: Partial<RendererConfig>;
|
|
17
|
+
/**
|
|
18
|
+
* Optional context provider. composeRenderer stacks Providers in module
|
|
19
|
+
* order outside `<RichRenderer>`. Module Providers are for internal
|
|
20
|
+
* plumbing only — do not redeclare `NestedContentRendererProvider`,
|
|
21
|
+
* composeRenderer manages it.
|
|
22
|
+
*/
|
|
23
|
+
Provider?: ComponentType<{
|
|
24
|
+
children: ReactNode;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Lazy renderers. Each loader returns the renderer component as default
|
|
28
|
+
* export. composeRenderer wraps each in `React.lazy` (factory created
|
|
29
|
+
* once at compose time) + `<Suspense fallback={ssrFallback?.[type]}>`.
|
|
30
|
+
*/
|
|
31
|
+
lazyRenderers?: Partial<{
|
|
32
|
+
[K in RendererKey]: () => Promise<{
|
|
33
|
+
default: NonNullable<RendererConfig[K]>;
|
|
34
|
+
}>;
|
|
35
|
+
}>;
|
|
36
|
+
/**
|
|
37
|
+
* SSR / Suspense fallback. Must be deterministic — no Date.now, no random,
|
|
38
|
+
* no client-only API access. Renders identically server-side and during
|
|
39
|
+
* client hydration.
|
|
40
|
+
*/
|
|
41
|
+
ssrFallback?: Partial<Record<RendererKey, ReactNode>>;
|
|
42
|
+
}
|
|
43
|
+
export interface ComposeRendererOptions {
|
|
44
|
+
/** Starting set; can be `shiroPreset`, custom array, or omitted. */
|
|
45
|
+
preset?: RichRendererModule[];
|
|
46
|
+
/** Appended to preset; later modules override earlier on `name` collision. */
|
|
47
|
+
modules?: RichRendererModule[];
|
|
48
|
+
/** Final renderer overrides; takes precedence over module-supplied renderers. */
|
|
49
|
+
overrides?: Partial<RendererConfig>;
|
|
50
|
+
/** Pass-through to `<RichRenderer>` for `paragraph` / `link` / `autolink` etc. */
|
|
51
|
+
builtinNodeOverrides?: Record<string, BuiltinNodeRenderer>;
|
|
52
|
+
}
|
|
53
|
+
export interface RichRendererBaseProps {
|
|
54
|
+
value: SerializedEditorState;
|
|
55
|
+
variant?: RichEditorVariant;
|
|
56
|
+
theme?: 'light' | 'dark';
|
|
57
|
+
className?: string;
|
|
58
|
+
style?: CSSProperties;
|
|
59
|
+
nested?: boolean;
|
|
60
|
+
as?: keyof React.JSX.IntrinsicElements;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AACvE,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEpE,MAAM,MAAM,WAAW,GAAG,MAAM,cAAc,CAAA;AAE9C,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAA;IAEZ;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAA;IAE5B,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IAEnC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAA;IAEjD;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;SACrB,CAAC,IAAI,WAAW,GAAG,MAAM,OAAO,CAAC;YAAE,OAAO,EAAE,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAA;SAAE,CAAC;KAC/E,CAAC,CAAA;IAEF;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAA;CACtD;AAED,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC7B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC9B,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAA;IACnC,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;CAC3D;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,qBAAqB,CAAA;IAC5B,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAA;CACvC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,QAAQ,GACT,MAAM,QAAQ,CAAA;AACf,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,QAAQ,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { NestedContentRendererProvider } from "@haklex/rich-editor";
|
|
2
|
+
import { RichRenderer } from "@haklex/rich-static-renderer";
|
|
3
|
+
import { Fragment, Suspense, lazy, memo, useCallback } from "react";
|
|
4
|
+
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
5
|
+
//#region src/core/dedup.ts
|
|
6
|
+
/**
|
|
7
|
+
* Merge preset and modules, deduplicating by:
|
|
8
|
+
* 1. Same module reference → skip silently (idempotent)
|
|
9
|
+
* 2. Same module.name → replace previous module entirely; warn in dev
|
|
10
|
+
* 3. Else → append
|
|
11
|
+
*/
|
|
12
|
+
function mergeModules(preset, modules) {
|
|
13
|
+
const all = [...preset ?? [], ...modules ?? []];
|
|
14
|
+
const refSeen = /* @__PURE__ */ new Set();
|
|
15
|
+
const byName = /* @__PURE__ */ new Map();
|
|
16
|
+
const result = [];
|
|
17
|
+
for (const m of all) {
|
|
18
|
+
if (refSeen.has(m)) continue;
|
|
19
|
+
refSeen.add(m);
|
|
20
|
+
const existingIdx = byName.get(m.name);
|
|
21
|
+
if (existingIdx !== void 0) {
|
|
22
|
+
console.warn(`[rich-compose] module name collision: "${m.name}" — replacing previous registration. Pass the same module reference to silence this warning.`);
|
|
23
|
+
result[existingIdx] = m;
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
byName.set(m.name, result.length);
|
|
27
|
+
result.push(m);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Dedup by class reference. Throws if two distinct Klasses share the same
|
|
33
|
+
* `getType()` — multiple Klass instances will break `instanceof` checks
|
|
34
|
+
* across module boundaries.
|
|
35
|
+
*/
|
|
36
|
+
function dedupNodes(nodes) {
|
|
37
|
+
const seen = /* @__PURE__ */ new Set();
|
|
38
|
+
const byType = /* @__PURE__ */ new Map();
|
|
39
|
+
const result = [];
|
|
40
|
+
for (const Node of nodes) {
|
|
41
|
+
if (seen.has(Node)) continue;
|
|
42
|
+
seen.add(Node);
|
|
43
|
+
const type = typeof Node.getType === "function" ? Node.getType() : void 0;
|
|
44
|
+
if (type !== void 0) {
|
|
45
|
+
const prev = byType.get(type);
|
|
46
|
+
if (prev !== void 0 && prev !== Node) throw new Error(`[rich-compose] node type collision on "${type}": two distinct Klass references registered. This breaks \`instanceof\` checks. Ensure peerDeps/lexical version are pinned and a single module exports each type.`);
|
|
47
|
+
byType.set(type, Node);
|
|
48
|
+
}
|
|
49
|
+
result.push(Node);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region src/core/lazy.tsx
|
|
55
|
+
/**
|
|
56
|
+
* Build sync wrappers around `React.lazy(loader)` factories.
|
|
57
|
+
*
|
|
58
|
+
* Each factory is created exactly **once** at compose time, not per render.
|
|
59
|
+
* Recreating the factory on every render would force React to refetch the
|
|
60
|
+
* chunk and replay the Suspense fallback, causing flicker.
|
|
61
|
+
*/
|
|
62
|
+
function wrapLazy(modules) {
|
|
63
|
+
const result = {};
|
|
64
|
+
for (const m of modules) {
|
|
65
|
+
if (!m.lazyRenderers) continue;
|
|
66
|
+
for (const key of Object.keys(m.lazyRenderers)) {
|
|
67
|
+
const loader = m.lazyRenderers[key];
|
|
68
|
+
if (!loader) continue;
|
|
69
|
+
const fallback = m.ssrFallback?.[key] ?? null;
|
|
70
|
+
const LazyInner = lazy(loader);
|
|
71
|
+
const Wrapped = (props) => /* @__PURE__ */ jsx(Suspense, {
|
|
72
|
+
fallback,
|
|
73
|
+
children: /* @__PURE__ */ jsx(LazyInner, { ...props })
|
|
74
|
+
});
|
|
75
|
+
Wrapped.displayName = `Lazy(${m.name}.${String(key)})`;
|
|
76
|
+
result[key] = Wrapped;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/core/compose.tsx
|
|
83
|
+
function flattenNodes(modules) {
|
|
84
|
+
return dedupNodes(modules.flatMap((m) => m.nodes ?? []));
|
|
85
|
+
}
|
|
86
|
+
function mergeSyncRenderers(modules) {
|
|
87
|
+
const out = {};
|
|
88
|
+
for (const m of modules) {
|
|
89
|
+
if (!m.renderers) continue;
|
|
90
|
+
Object.assign(out, m.renderers);
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
function composeProviders(modules) {
|
|
95
|
+
const providers = modules.map((m) => m.Provider).filter((P) => Boolean(P));
|
|
96
|
+
if (providers.length === 0) return Fragment;
|
|
97
|
+
const ComposedProviders = ({ children }) => {
|
|
98
|
+
let acc = children;
|
|
99
|
+
for (let i = providers.length - 1; i >= 0; i--) {
|
|
100
|
+
const P = providers[i];
|
|
101
|
+
acc = /* @__PURE__ */ jsx(P, { children: acc });
|
|
102
|
+
}
|
|
103
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: acc });
|
|
104
|
+
};
|
|
105
|
+
ComposedProviders.displayName = "ComposedProviders";
|
|
106
|
+
return ComposedProviders;
|
|
107
|
+
}
|
|
108
|
+
function composeRenderer(opts) {
|
|
109
|
+
const merged = mergeModules(opts.preset, opts.modules);
|
|
110
|
+
const allNodes = flattenNodes(merged);
|
|
111
|
+
const syncMap = mergeSyncRenderers(merged);
|
|
112
|
+
const lazyMap = wrapLazy(merged);
|
|
113
|
+
const finalConfig = {
|
|
114
|
+
...syncMap,
|
|
115
|
+
...lazyMap,
|
|
116
|
+
...opts.overrides ?? {}
|
|
117
|
+
};
|
|
118
|
+
const ComposedProviders = composeProviders(merged);
|
|
119
|
+
const builtinNodeOverrides = opts.builtinNodeOverrides;
|
|
120
|
+
function ComposedRenderer(props) {
|
|
121
|
+
const { theme, variant } = props;
|
|
122
|
+
return /* @__PURE__ */ jsx(NestedContentRendererProvider, {
|
|
123
|
+
value: useCallback((value, overrideVariant) => /* @__PURE__ */ jsx(ComposedRenderer, {
|
|
124
|
+
nested: true,
|
|
125
|
+
theme,
|
|
126
|
+
value,
|
|
127
|
+
variant: overrideVariant ?? variant
|
|
128
|
+
}), [theme, variant]),
|
|
129
|
+
children: /* @__PURE__ */ jsx(ComposedProviders, { children: /* @__PURE__ */ jsx(RichRenderer, {
|
|
130
|
+
as: props.as,
|
|
131
|
+
builtinNodeOverrides,
|
|
132
|
+
className: props.className,
|
|
133
|
+
extraNodes: allNodes,
|
|
134
|
+
nested: props.nested,
|
|
135
|
+
rendererConfig: finalConfig,
|
|
136
|
+
style: props.style,
|
|
137
|
+
theme,
|
|
138
|
+
value: props.value,
|
|
139
|
+
variant
|
|
140
|
+
}) })
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return memo(ComposedRenderer);
|
|
144
|
+
}
|
|
145
|
+
//#endregion
|
|
146
|
+
export { composeRenderer, dedupNodes, mergeModules, wrapLazy };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { ChatMessage, ChatParticipant, ChatParticipantKind, ChatRendererProps, ChatVariant, SerializedChatNode, } from '@haklex/rich-ext-chat/static';
|
|
2
|
+
export { $createChatNode, $isChatNode, ChatNode, chatNodes, } from './node';
|
|
3
|
+
export { ChatRenderer } from './renderer';
|
|
4
|
+
export { chatModule } from './module';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/chat/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,iBAAiB,EACjB,WAAW,EACX,kBAAkB,GACnB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EACL,eAAe,EACf,WAAW,EACX,QAAQ,EACR,SAAS,GACV,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { $createChatNode, $isChatNode, ChatNode, chatNodes } from "./node.mjs";
|
|
2
|
+
import { ChatRenderer } from "./renderer.mjs";
|
|
3
|
+
import { ChatRenderer as ChatRenderer$1, chatNodes as chatNodes$1 } from "@haklex/rich-ext-chat/static";
|
|
4
|
+
//#region src/modules/chat/module.ts
|
|
5
|
+
var chatModule = {
|
|
6
|
+
name: "chat",
|
|
7
|
+
nodes: chatNodes$1,
|
|
8
|
+
renderers: { Chat: ChatRenderer$1 }
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { $createChatNode, $isChatNode, ChatNode, ChatRenderer, chatModule, chatNodes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/chat/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,eAAO,MAAM,UAAU,EAAE,kBAIxB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/modules/chat/node.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AACtE,OAAO,EACL,eAAe,EACf,WAAW,EACX,QAAQ,EACR,SAAS,GACV,MAAM,8BAA8B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/modules/chat/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAE3D,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,eAAe,YAAY,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/code-block/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CodeBlockRenderer } from "./renderer.mjs";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/modules/code-block/ssr-fallback.tsx
|
|
4
|
+
/**
|
|
5
|
+
* SSR / Suspense fallback for the lazy CodeBlock renderer.
|
|
6
|
+
*
|
|
7
|
+
* Determinism requirement: identical output server-side and client-side
|
|
8
|
+
* to avoid hydration mismatches. No Date, no random, no client-only API.
|
|
9
|
+
*
|
|
10
|
+
* Renders a placeholder `<pre>` shell. The lazy renderer replaces it with
|
|
11
|
+
* shiki-tokenized output once the chunk resolves. Even without code text
|
|
12
|
+
* (the fallback runs before props are routed through the lazy boundary),
|
|
13
|
+
* the empty pre keeps layout stable.
|
|
14
|
+
*/
|
|
15
|
+
function CodeBlockSsrFallback() {
|
|
16
|
+
return /* @__PURE__ */ jsx("pre", {
|
|
17
|
+
className: "rich-codeblock-skeleton",
|
|
18
|
+
"data-rich-skeleton": "codeblock",
|
|
19
|
+
children: /* @__PURE__ */ jsx("code", {})
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/modules/code-block/module.tsx
|
|
24
|
+
/**
|
|
25
|
+
* Code-block module — uses Lexical's builtin `code` node, so no `nodes`
|
|
26
|
+
* field. The default renderer (`@haklex/rich-renderer-codeblock`) is heavy
|
|
27
|
+
* (shiki) and ships in a separate lazy chunk.
|
|
28
|
+
*
|
|
29
|
+
* The SSR fallback emits a `<pre>` shell so server-rendered HTML keeps
|
|
30
|
+
* layout stable before the lazy chunk resolves. The lazy renderer replaces
|
|
31
|
+
* it with shiki-tokenized output after hydration.
|
|
32
|
+
*/
|
|
33
|
+
var codeBlockModule = {
|
|
34
|
+
name: "code-block",
|
|
35
|
+
lazyRenderers: { CodeBlock: () => import("./renderer.mjs") },
|
|
36
|
+
ssrFallback: { CodeBlock: /* @__PURE__ */ jsx(CodeBlockSsrFallback, {}) }
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { CodeBlockRenderer, codeBlockModule };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RichRendererModule } from '../../core/types';
|
|
2
|
+
/**
|
|
3
|
+
* Code-block module — uses Lexical's builtin `code` node, so no `nodes`
|
|
4
|
+
* field. The default renderer (`@haklex/rich-renderer-codeblock`) is heavy
|
|
5
|
+
* (shiki) and ships in a separate lazy chunk.
|
|
6
|
+
*
|
|
7
|
+
* The SSR fallback emits a `<pre>` shell so server-rendered HTML keeps
|
|
8
|
+
* layout stable before the lazy chunk resolves. The lazy renderer replaces
|
|
9
|
+
* it with shiki-tokenized output after hydration.
|
|
10
|
+
*/
|
|
11
|
+
export declare const codeBlockModule: RichRendererModule;
|
|
12
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/code-block/module.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAG1D;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,kBAQ7B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/modules/code-block/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAE1E,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSR / Suspense fallback for the lazy CodeBlock renderer.
|
|
3
|
+
*
|
|
4
|
+
* Determinism requirement: identical output server-side and client-side
|
|
5
|
+
* to avoid hydration mismatches. No Date, no random, no client-only API.
|
|
6
|
+
*
|
|
7
|
+
* Renders a placeholder `<pre>` shell. The lazy renderer replaces it with
|
|
8
|
+
* shiki-tokenized output once the chunk resolves. Even without code text
|
|
9
|
+
* (the fallback runs before props are routed through the lazy boundary),
|
|
10
|
+
* the empty pre keeps layout stable.
|
|
11
|
+
*/
|
|
12
|
+
export declare function CodeBlockSsrFallback(): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=ssr-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssr-fallback.d.ts","sourceRoot":"","sources":["../../../src/modules/code-block/ssr-fallback.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,4CAMnC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { SerializedCodeSnippetNode } from './node';
|
|
2
|
+
export { $createCodeSnippetNode, $isCodeSnippetNode, CodeSnippetNode, codeSnippetNodes, } from './node';
|
|
3
|
+
export { CodeSnippetRenderer } from './renderer';
|
|
4
|
+
export { codeSnippetModule } from './module';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/code-snippet/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAA;AACvD,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { $createCodeSnippetNode, $isCodeSnippetNode, CodeSnippetNode, codeSnippetNodes } from "./node.mjs";
|
|
2
|
+
import { CodeSnippetRenderer } from "./renderer.mjs";
|
|
3
|
+
import { CodeSnippetRenderer as CodeSnippetRenderer$1, codeSnippetNodes as codeSnippetNodes$1 } from "@haklex/rich-ext-code-snippet/static";
|
|
4
|
+
//#region src/modules/code-snippet/module.ts
|
|
5
|
+
var codeSnippetModule = {
|
|
6
|
+
name: "code-snippet",
|
|
7
|
+
nodes: codeSnippetNodes$1,
|
|
8
|
+
renderers: { CodeSnippet: CodeSnippetRenderer$1 }
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { $createCodeSnippetNode, $isCodeSnippetNode, CodeSnippetNode, CodeSnippetRenderer, codeSnippetModule, codeSnippetNodes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/code-snippet/module.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,eAAO,MAAM,iBAAiB,EAAE,kBAI/B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/modules/code-snippet/node.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAA;AACrF,OAAO,EACL,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,sCAAsC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/modules/code-snippet/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAA;AAE1E,OAAO,EAAE,mBAAmB,EAAE,CAAA;AAC9B,eAAe,mBAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/embed/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { $createEmbedNode, $isEmbedNode, EmbedNode, embedNodes } from "./node.mjs";
|
|
2
|
+
import { embedNodes as embedNodes$1 } from "@haklex/rich-ext-embed/static";
|
|
3
|
+
//#region src/modules/embed/module.ts
|
|
4
|
+
/**
|
|
5
|
+
* Embed module — registers the EmbedNode Klass.
|
|
6
|
+
*
|
|
7
|
+
* The embed node's `decorate()` calls `EmbedStaticRenderer` internally; per-
|
|
8
|
+
* platform component injection happens via `EmbedRendererProvider` at the
|
|
9
|
+
* consumer level (it's data, not a renderer slot in `RendererConfig`).
|
|
10
|
+
* Hence this module declares only `nodes`.
|
|
11
|
+
*/
|
|
12
|
+
var embedModule = {
|
|
13
|
+
name: "embed",
|
|
14
|
+
nodes: embedNodes$1
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { $createEmbedNode, $isEmbedNode, EmbedNode, embedModule, embedNodes };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RichRendererModule } from '../../core/types';
|
|
2
|
+
/**
|
|
3
|
+
* Embed module — registers the EmbedNode Klass.
|
|
4
|
+
*
|
|
5
|
+
* The embed node's `decorate()` calls `EmbedStaticRenderer` internally; per-
|
|
6
|
+
* platform component injection happens via `EmbedRendererProvider` at the
|
|
7
|
+
* consumer level (it's data, not a renderer slot in `RendererConfig`).
|
|
8
|
+
* Hence this module declares only `nodes`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const embedModule: RichRendererModule;
|
|
11
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/embed/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,EAAE,kBAGzB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/modules/embed/node.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,UAAU,GACX,MAAM,+BAA+B,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { GalleryNodePayload, SerializedGalleryNode } from './node';
|
|
2
|
+
export { $createGalleryNode, $isGalleryNode, GalleryNode, galleryNodes, } from './node';
|
|
3
|
+
export { GalleryRenderer } from './renderer';
|
|
4
|
+
export { galleryModule } from './module';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/gallery/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,QAAQ,CAAA;AACvE,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,YAAY,GACb,MAAM,QAAQ,CAAA;AACf,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { $createGalleryNode, $isGalleryNode, GalleryNode, galleryNodes } from "./node.mjs";
|
|
2
|
+
import { GalleryRenderer } from "./renderer.mjs";
|
|
3
|
+
import { GalleryRenderer as GalleryRenderer$1, galleryNodes as galleryNodes$1 } from "@haklex/rich-ext-gallery/static";
|
|
4
|
+
//#region src/modules/gallery/module.ts
|
|
5
|
+
var galleryModule = {
|
|
6
|
+
name: "gallery",
|
|
7
|
+
nodes: galleryNodes$1,
|
|
8
|
+
renderers: { Gallery: GalleryRenderer$1 }
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { $createGalleryNode, $isGalleryNode, GalleryNode, GalleryRenderer, galleryModule, galleryNodes };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/gallery/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D,eAAO,MAAM,aAAa,EAAE,kBAI3B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/modules/gallery/node.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AAChG,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,YAAY,GACb,MAAM,iCAAiC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/modules/gallery/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAA;AAEjE,OAAO,EAAE,eAAe,EAAE,CAAA;AAC1B,eAAe,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/link-card/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LinkCardRenderer } from "./renderer.mjs";
|
|
2
|
+
import { LinkCardRenderer as LinkCardRenderer$1 } from "@haklex/rich-renderer-linkcard/static";
|
|
3
|
+
//#region src/modules/link-card/module.ts
|
|
4
|
+
/**
|
|
5
|
+
* Link-card module — `LinkCardNode` is registered by `@haklex/rich-editor`
|
|
6
|
+
* (it lives in `customNodes`/`allNodes`). This module only contributes the
|
|
7
|
+
* default renderer; consumers wanting a custom renderer construct their own
|
|
8
|
+
* module with the same `name` and avoid importing `linkCardModule`.
|
|
9
|
+
*/
|
|
10
|
+
var linkCardModule = {
|
|
11
|
+
name: "link-card",
|
|
12
|
+
renderers: { LinkCard: LinkCardRenderer$1 }
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { LinkCardRenderer, linkCardModule };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RichRendererModule } from '../../core/types';
|
|
2
|
+
/**
|
|
3
|
+
* Link-card module — `LinkCardNode` is registered by `@haklex/rich-editor`
|
|
4
|
+
* (it lives in `customNodes`/`allNodes`). This module only contributes the
|
|
5
|
+
* default renderer; consumers wanting a custom renderer construct their own
|
|
6
|
+
* module with the same `name` and avoid importing `linkCardModule`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const linkCardModule: RichRendererModule;
|
|
9
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/modules/link-card/module.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAE1D;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,kBAG5B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/modules/link-card/renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uCAAuC,CAAA;AAExE,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,eAAe,gBAAgB,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@haklex/rich-compose",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Compose primitives for haklex rich content renderers — Gundam-style assembly of Lexical nodes, sync/lazy renderers, and Provider stacks.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/Innei/haklex.git",
|
|
8
|
+
"directory": "packages/rich-compose"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"sideEffects": [
|
|
13
|
+
"**/*.css"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
|
+
"types": "./dist/index.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./modules/embed": {
|
|
21
|
+
"import": "./dist/modules/embed/index.mjs",
|
|
22
|
+
"types": "./dist/modules/embed/index.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./modules/embed/node": {
|
|
25
|
+
"import": "./dist/modules/embed/node.mjs",
|
|
26
|
+
"types": "./dist/modules/embed/node.d.ts"
|
|
27
|
+
},
|
|
28
|
+
"./modules/code-block": {
|
|
29
|
+
"import": "./dist/modules/code-block/index.mjs",
|
|
30
|
+
"types": "./dist/modules/code-block/index.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./modules/code-block/renderer": {
|
|
33
|
+
"import": "./dist/modules/code-block/renderer.mjs",
|
|
34
|
+
"types": "./dist/modules/code-block/renderer.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"./modules/link-card": {
|
|
37
|
+
"import": "./dist/modules/link-card/index.mjs",
|
|
38
|
+
"types": "./dist/modules/link-card/index.d.ts"
|
|
39
|
+
},
|
|
40
|
+
"./modules/link-card/renderer": {
|
|
41
|
+
"import": "./dist/modules/link-card/renderer.mjs",
|
|
42
|
+
"types": "./dist/modules/link-card/renderer.d.ts"
|
|
43
|
+
},
|
|
44
|
+
"./modules/gallery": {
|
|
45
|
+
"import": "./dist/modules/gallery/index.mjs",
|
|
46
|
+
"types": "./dist/modules/gallery/index.d.ts"
|
|
47
|
+
},
|
|
48
|
+
"./modules/gallery/node": {
|
|
49
|
+
"import": "./dist/modules/gallery/node.mjs",
|
|
50
|
+
"types": "./dist/modules/gallery/node.d.ts"
|
|
51
|
+
},
|
|
52
|
+
"./modules/gallery/renderer": {
|
|
53
|
+
"import": "./dist/modules/gallery/renderer.mjs",
|
|
54
|
+
"types": "./dist/modules/gallery/renderer.d.ts"
|
|
55
|
+
},
|
|
56
|
+
"./modules/code-snippet": {
|
|
57
|
+
"import": "./dist/modules/code-snippet/index.mjs",
|
|
58
|
+
"types": "./dist/modules/code-snippet/index.d.ts"
|
|
59
|
+
},
|
|
60
|
+
"./modules/code-snippet/node": {
|
|
61
|
+
"import": "./dist/modules/code-snippet/node.mjs",
|
|
62
|
+
"types": "./dist/modules/code-snippet/node.d.ts"
|
|
63
|
+
},
|
|
64
|
+
"./modules/code-snippet/renderer": {
|
|
65
|
+
"import": "./dist/modules/code-snippet/renderer.mjs",
|
|
66
|
+
"types": "./dist/modules/code-snippet/renderer.d.ts"
|
|
67
|
+
},
|
|
68
|
+
"./modules/chat": {
|
|
69
|
+
"import": "./dist/modules/chat/index.mjs",
|
|
70
|
+
"types": "./dist/modules/chat/index.d.ts"
|
|
71
|
+
},
|
|
72
|
+
"./modules/chat/node": {
|
|
73
|
+
"import": "./dist/modules/chat/node.mjs",
|
|
74
|
+
"types": "./dist/modules/chat/node.d.ts"
|
|
75
|
+
},
|
|
76
|
+
"./modules/chat/renderer": {
|
|
77
|
+
"import": "./dist/modules/chat/renderer.mjs",
|
|
78
|
+
"types": "./dist/modules/chat/renderer.d.ts"
|
|
79
|
+
},
|
|
80
|
+
"./style.css": "./dist/rich-compose.css"
|
|
81
|
+
},
|
|
82
|
+
"main": "./dist/index.mjs",
|
|
83
|
+
"files": [
|
|
84
|
+
"dist"
|
|
85
|
+
],
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@lexical/react": "^0.44.0",
|
|
88
|
+
"@types/react": "^19.2.14",
|
|
89
|
+
"@types/react-dom": "^19.2.3",
|
|
90
|
+
"lexical": "^0.44.0",
|
|
91
|
+
"react": "19.2.5",
|
|
92
|
+
"react-dom": "19.2.5",
|
|
93
|
+
"typescript": "^5.9.3",
|
|
94
|
+
"vite": "^8.0.10",
|
|
95
|
+
"vite-plugin-dts": "^4.5.4",
|
|
96
|
+
"vitest": "^4.1.5",
|
|
97
|
+
"@haklex/rich-editor": "0.4.1",
|
|
98
|
+
"@haklex/rich-ext-chat": "0.4.1",
|
|
99
|
+
"@haklex/rich-ext-code-snippet": "0.4.1",
|
|
100
|
+
"@haklex/rich-ext-gallery": "0.4.1",
|
|
101
|
+
"@haklex/rich-ext-embed": "0.4.1",
|
|
102
|
+
"@haklex/rich-renderer-codeblock": "0.4.1",
|
|
103
|
+
"@haklex/rich-static-renderer": "0.4.1",
|
|
104
|
+
"@haklex/rich-renderer-linkcard": "0.4.1"
|
|
105
|
+
},
|
|
106
|
+
"peerDependencies": {
|
|
107
|
+
"@lexical/react": "^0.44.0",
|
|
108
|
+
"lexical": "^0.44.0",
|
|
109
|
+
"react": ">=19",
|
|
110
|
+
"react-dom": ">=19",
|
|
111
|
+
"@haklex/rich-editor": "0.4.1",
|
|
112
|
+
"@haklex/rich-ext-chat": "0.4.1",
|
|
113
|
+
"@haklex/rich-ext-embed": "0.4.1",
|
|
114
|
+
"@haklex/rich-ext-gallery": "0.4.1",
|
|
115
|
+
"@haklex/rich-ext-code-snippet": "0.4.1",
|
|
116
|
+
"@haklex/rich-renderer-linkcard": "0.4.1",
|
|
117
|
+
"@haklex/rich-static-renderer": "0.4.1",
|
|
118
|
+
"@haklex/rich-renderer-codeblock": "0.4.1"
|
|
119
|
+
},
|
|
120
|
+
"peerDependenciesMeta": {
|
|
121
|
+
"@haklex/rich-ext-chat": {
|
|
122
|
+
"optional": true
|
|
123
|
+
},
|
|
124
|
+
"@haklex/rich-ext-code-snippet": {
|
|
125
|
+
"optional": true
|
|
126
|
+
},
|
|
127
|
+
"@haklex/rich-ext-embed": {
|
|
128
|
+
"optional": true
|
|
129
|
+
},
|
|
130
|
+
"@haklex/rich-ext-gallery": {
|
|
131
|
+
"optional": true
|
|
132
|
+
},
|
|
133
|
+
"@haklex/rich-renderer-codeblock": {
|
|
134
|
+
"optional": true
|
|
135
|
+
},
|
|
136
|
+
"@haklex/rich-renderer-linkcard": {
|
|
137
|
+
"optional": true
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
"publishConfig": {
|
|
141
|
+
"access": "public"
|
|
142
|
+
},
|
|
143
|
+
"scripts": {
|
|
144
|
+
"build": "vite build",
|
|
145
|
+
"dev:build": "vite build --watch",
|
|
146
|
+
"test": "vitest run"
|
|
147
|
+
},
|
|
148
|
+
"types": "./dist/index.d.ts"
|
|
149
|
+
}
|