@haklex/rich-compose 0.5.0 → 0.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/README.md CHANGED
@@ -2,11 +2,9 @@
2
2
 
3
3
  Compose primitives for haklex rich content renderers — Gundam-style assembly of Lexical nodes, sync/lazy renderers, and Provider stacks.
4
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
5
  ## Why
8
6
 
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:
7
+ The legacy `@haklex/rich-kit-shiro/renderer` (now removed) shipped every default renderer eagerly: even when a consumer overrode `CodeBlock` or `LinkCard`, the upstream `shiki` and `LinkCardRenderer` chains stayed in the production bundle. `rich-compose` solves three problems at once:
10
8
 
11
9
  1. **Subtractable** — drop a module by not importing it.
12
10
  2. **Replaceable** — swap a default renderer with no leftover bytes from the original.
@@ -22,12 +20,11 @@ pnpm add @haklex/rich-compose
22
20
 
23
21
  ## Peer Dependencies
24
22
 
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 |
23
+ | Package | Version |
24
+ | ---------------------------- | --------- |
25
+ | `react` / `react-dom` | `>=19` |
26
+ | `lexical` / `@lexical/react` | `^0.44.0` |
27
+ | `@haklex/rich-editor` | workspace |
31
28
 
32
29
  Per-module upstream packages (`@haklex/rich-ext-*`, `@haklex/rich-renderer-*`) are optional peers — install only those you compose into your renderer.
33
30
 
@@ -1 +1 @@
1
- {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/core/compose.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,OAAO,CAAC;AAIxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAsB,MAAM,SAAS,CAAC;AAkCjG,wBAAgB,eAAe,CAC7B,IAAI,EAAE,sBAAsB,GAC3B,aAAa,CAAC,qBAAqB,CAAC,CA4CtC"}
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/core/compose.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,aAAa,EAA+C,MAAM,OAAO,CAAC;AAKxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAsB,MAAM,SAAS,CAAC;AAkCjG,wBAAgB,eAAe,CAC7B,IAAI,EAAE,sBAAsB,GAC3B,aAAa,CAAC,qBAAqB,CAAC,CA4CtC"}
@@ -1,7 +1,7 @@
1
1
  import { RendererConfig, RichEditorVariant } from '@haklex/rich-editor';
2
- import { BuiltinNodeRenderer } from '@haklex/rich-static-renderer';
3
2
  import { Klass, LexicalNode, SerializedEditorState } from 'lexical';
4
3
  import { ComponentType, CSSProperties, ReactNode } from 'react';
4
+ import { BuiltinNodeRenderer } from '../static-renderer/types';
5
5
  export type RendererKey = keyof RendererConfig;
6
6
  export interface RichRendererModule {
7
7
  /**
@@ -1 +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,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC;;;;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,CAAC;IAEH,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;IAE7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAElD,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAEpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,8EAA8E;IAC9E,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACpC,oEAAoE;IACpE,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,qBAAqB,CAAC;IAC7B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B"}
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,CAAC;AAC7E,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,MAAM,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC;;;;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,CAAC;IAEH,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IAEb;;;;OAIG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;IAE7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,aAAa,CAAC;QAAE,QAAQ,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAElD,4CAA4C;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAEpC;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,8EAA8E;IAC9E,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IACpC,oEAAoE;IACpE,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACzB,KAAK,EAAE,qBAAqB,CAAC;IAC7B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export type { ComposeRendererOptions, RendererKey, RichRendererBaseProps, RichRendererModule, } from './core';
2
2
  export { composeRenderer, dedupNodes, mergeModules, wrapLazy } from './core';
3
+ export type { BuiltinNodeRenderer, RichRendererProps } from './static-renderer';
4
+ export { RichRenderer } from './static-renderer';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC7E,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,432 @@
1
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";
2
+ import { Fragment, Suspense, cloneElement, createElement, isValidElement, lazy, memo, useCallback, useEffect, useMemo, useRef } from "react";
3
+ import { ColorSchemeProvider, FootnoteDefinitionsProvider, LinkFavicon, NestedContentRendererProvider as NestedContentRendererProvider$1, RendererConfigProvider, RendererWrapper, RubyRenderer, allNodes, detailsClassNames, detailsStyles, editorTheme, getTagBgColor, getVariantClass, gridClassNames, gridStyles, normalizeSerializedEditorState, semanticClassNames, sharedStyles, useOptionalNestedContentRenderer } from "@haklex/rich-editor/static";
4
+ import { PortalThemeProvider } from "@haklex/rich-style-token";
5
+ import { createHeadlessEditor } from "@lexical/headless";
6
+ import { $getRoot } from "lexical";
7
+ import { Link } from "lucide-react";
8
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
+ //#region src/static-renderer/components/HtmlComment.tsx
10
+ function HtmlComment({ text }) {
11
+ const anchorRef = useRef(null);
12
+ const commentRef = useRef(null);
13
+ useEffect(() => {
14
+ const anchor = anchorRef.current;
15
+ if (!anchor) return;
16
+ const parent = anchor.parentNode;
17
+ if (!parent) return;
18
+ let comment = commentRef.current;
19
+ if (!comment || comment.parentNode !== parent) {
20
+ comment = document.createComment(text);
21
+ parent.insertBefore(comment, anchor);
22
+ commentRef.current = comment;
23
+ } else if (comment.data !== text) comment.data = text;
24
+ return () => {
25
+ if (commentRef.current?.parentNode) commentRef.current.parentNode.removeChild(commentRef.current);
26
+ commentRef.current = null;
27
+ };
28
+ }, [text]);
29
+ return /* @__PURE__ */ jsx("template", {
30
+ suppressHydrationWarning: true,
31
+ "data-rich-comment-anchor": "",
32
+ ref: anchorRef
33
+ });
34
+ }
35
+ //#endregion
36
+ //#region src/static-renderer/table.css.ts
37
+ var tableWrapper = "icqzyn0";
38
+ var table = "icqzyn1";
39
+ var tableHead = "icqzyn2";
40
+ var tableCell = "icqzyn3";
41
+ //#endregion
42
+ //#region src/static-renderer/engine/renderBuiltinNode.tsx
43
+ var shared$1 = (key) => `${semanticClassNames[key]} ${sharedStyles[key]}`;
44
+ var headingClassNames = {
45
+ h1: shared$1("headingH1"),
46
+ h2: shared$1("headingH2"),
47
+ h3: shared$1("headingH3"),
48
+ h4: shared$1("headingH4"),
49
+ h5: shared$1("headingH5"),
50
+ h6: shared$1("headingH6")
51
+ };
52
+ function textToSlug(text) {
53
+ return text.toLowerCase().trim().replaceAll(/[^\s\w\u3000-\u9FFF\uAC00-\uD7AF\uFF00-\uFFEF-]/g, "").replaceAll(/[\s_]+/g, "-").replaceAll(/^-+|-+$/g, "");
54
+ }
55
+ function extractText(node) {
56
+ if (node.type === "comment") return "";
57
+ if (node.text) return node.text;
58
+ if (node.children) return node.children.map(extractText).join("");
59
+ return "";
60
+ }
61
+ function renderBuiltinNode(node, key, children, headingSlugs, textContent) {
62
+ switch (node.type) {
63
+ case "root": return /* @__PURE__ */ jsx(Fragment$1, { children });
64
+ case "paragraph": {
65
+ const align = node.format ? { textAlign: node.format } : void 0;
66
+ return /* @__PURE__ */ jsx("p", {
67
+ className: shared$1("paragraph"),
68
+ style: align,
69
+ children
70
+ }, key);
71
+ }
72
+ case "heading": {
73
+ const Tag = node.tag;
74
+ const baseSlug = textToSlug(textContent || extractText(node));
75
+ let slug = baseSlug;
76
+ if (baseSlug) {
77
+ const count = headingSlugs.get(baseSlug);
78
+ if (count !== void 0) {
79
+ slug = `${baseSlug}-${count}`;
80
+ headingSlugs.set(baseSlug, count + 1);
81
+ } else headingSlugs.set(baseSlug, 1);
82
+ }
83
+ return /* @__PURE__ */ jsxs(Tag, {
84
+ className: headingClassNames[Tag],
85
+ id: slug || void 0,
86
+ children: [slug && /* @__PURE__ */ jsx("a", {
87
+ className: shared$1("headingAnchor"),
88
+ href: `#${slug}`,
89
+ tabIndex: 0,
90
+ children: /* @__PURE__ */ jsx(Link, {
91
+ "aria-hidden": true,
92
+ size: 14,
93
+ strokeWidth: 2
94
+ })
95
+ }), children]
96
+ }, key);
97
+ }
98
+ case "quote": return /* @__PURE__ */ jsx("blockquote", {
99
+ className: shared$1("quote"),
100
+ children
101
+ }, key);
102
+ case "list": return /* @__PURE__ */ jsx(node.listType === "number" ? "ol" : "ul", {
103
+ className: node.listType === "number" ? shared$1("listOl") : node.listType === "check" ? `${shared$1("checklist")} ${shared$1("listUl")}` : shared$1("listUl"),
104
+ start: node.start !== 1 ? node.start : void 0,
105
+ children
106
+ }, key);
107
+ case "listitem": {
108
+ const isChecklist = node.checked !== void 0;
109
+ const hasNestedList = node.children?.some((c) => c.type === "list");
110
+ const value = typeof node.value === "number" && node.value > 1 ? node.value : void 0;
111
+ let cls;
112
+ if (hasNestedList) cls = shared$1("listNestedItem");
113
+ else if (isChecklist) cls = node.checked ? `${shared$1("listItem")} ${shared$1("listItemChecked")}` : `${shared$1("listItem")} ${shared$1("listItemUnchecked")}`;
114
+ else cls = shared$1("listItem");
115
+ return /* @__PURE__ */ jsx("li", {
116
+ className: cls,
117
+ value,
118
+ children
119
+ }, key);
120
+ }
121
+ case "link": return /* @__PURE__ */ jsxs("a", {
122
+ className: shared$1("link"),
123
+ href: node.url,
124
+ rel: node.rel || "noopener",
125
+ target: node.target || "_blank",
126
+ children: [/* @__PURE__ */ jsx(LinkFavicon, { href: node.url }), children]
127
+ }, key);
128
+ case "autolink": return /* @__PURE__ */ jsxs("a", {
129
+ className: shared$1("link"),
130
+ href: node.url,
131
+ rel: "noopener",
132
+ target: "_blank",
133
+ children: [/* @__PURE__ */ jsx(LinkFavicon, { href: node.url }), children]
134
+ }, key);
135
+ case "horizontalrule": return /* @__PURE__ */ jsx("hr", { className: shared$1("hr") }, key);
136
+ case "table": return /* @__PURE__ */ jsx("div", {
137
+ className: tableWrapper,
138
+ children: /* @__PURE__ */ jsx("table", {
139
+ className: table,
140
+ children
141
+ })
142
+ }, key);
143
+ case "tablerow": return /* @__PURE__ */ jsx("tr", { children }, key);
144
+ case "tablecell": return /* @__PURE__ */ jsx(node.headerState ? "th" : "td", {
145
+ className: node.headerState ? tableHead : tableCell,
146
+ colSpan: node.colSpan > 1 ? node.colSpan : void 0,
147
+ children
148
+ }, key);
149
+ case "details": {
150
+ const summary = node.summary || "";
151
+ return /* @__PURE__ */ jsxs("details", {
152
+ className: `${detailsClassNames.details} ${detailsStyles.details}`,
153
+ open: node.open || void 0,
154
+ children: [/* @__PURE__ */ jsxs("summary", {
155
+ className: `${detailsClassNames.summary} ${detailsStyles.summary}`,
156
+ children: [/* @__PURE__ */ jsx("span", {
157
+ "aria-hidden": "true",
158
+ className: `${detailsClassNames.chevron} ${detailsStyles.chevron}`,
159
+ children: /* @__PURE__ */ jsx("svg", {
160
+ fill: "none",
161
+ height: "20",
162
+ stroke: "currentColor",
163
+ strokeLinecap: "round",
164
+ strokeLinejoin: "round",
165
+ strokeWidth: "1.5",
166
+ viewBox: "0 0 20 20",
167
+ width: "20",
168
+ children: /* @__PURE__ */ jsx("path", { d: "M8 6L12 10L8 14" })
169
+ })
170
+ }), /* @__PURE__ */ jsx("span", {
171
+ className: `${detailsClassNames.summaryText} ${detailsStyles.summaryText}`,
172
+ children: summary
173
+ })]
174
+ }), /* @__PURE__ */ jsx("div", {
175
+ className: `${detailsClassNames.content} ${detailsStyles.content}`,
176
+ children
177
+ })]
178
+ }, key);
179
+ }
180
+ case "spoiler": return /* @__PURE__ */ jsx("span", {
181
+ className: shared$1("spoiler"),
182
+ role: "button",
183
+ tabIndex: 0,
184
+ children
185
+ }, key);
186
+ case "tag": return /* @__PURE__ */ jsx("span", {
187
+ className: shared$1("tag"),
188
+ style: { backgroundColor: getTagBgColor(node.text) },
189
+ children: node.text
190
+ }, key);
191
+ case "comment": return /* @__PURE__ */ jsx(HtmlComment, { text: node.text ?? "" }, key);
192
+ case "ruby": return createElement(RendererWrapper, {
193
+ key,
194
+ rendererKey: "Ruby",
195
+ defaultRenderer: RubyRenderer,
196
+ props: {
197
+ reading: node.reading ?? "",
198
+ children
199
+ }
200
+ });
201
+ case "code": return /* @__PURE__ */ jsx("pre", {
202
+ className: "rich-code-block",
203
+ children: /* @__PURE__ */ jsx("code", { children })
204
+ }, key);
205
+ case "code-highlight": return /* @__PURE__ */ jsx("span", { children: node.text }, key);
206
+ case "linebreak": return /* @__PURE__ */ jsx("br", {}, key);
207
+ case "tab": return /* @__PURE__ */ jsx("span", { children: " " }, key);
208
+ default: return null;
209
+ }
210
+ }
211
+ //#endregion
212
+ //#region src/static-renderer/engine/renderTextNode.tsx
213
+ var shared = (key) => `${semanticClassNames[key]} ${sharedStyles[key]}`;
214
+ var FORMAT_FLAGS = [
215
+ [1, "textBold"],
216
+ [2, "textItalic"],
217
+ [4, "textStrikethrough"],
218
+ [8, "textUnderline"],
219
+ [16, "textCode"],
220
+ [32, "textSubscript"],
221
+ [64, "textSuperscript"],
222
+ [128, "textHighlight"]
223
+ ];
224
+ function parseCSSText(cssText) {
225
+ const style = {};
226
+ for (const part of cssText.split(";")) {
227
+ const colonIndex = part.indexOf(":");
228
+ if (colonIndex === -1) continue;
229
+ const prop = part.slice(0, colonIndex).trim();
230
+ const value = part.slice(colonIndex + 1).trim();
231
+ if (!prop || !value) continue;
232
+ const camelProp = prop.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
233
+ style[camelProp] = value;
234
+ }
235
+ return style;
236
+ }
237
+ function renderTextNode(node, key) {
238
+ let element = node.text;
239
+ const format = node.format || 0;
240
+ for (const [flag, styleKey] of FORMAT_FLAGS) if (format & flag) element = /* @__PURE__ */ jsx("span", {
241
+ className: shared(styleKey),
242
+ children: element
243
+ }, `${key}-${flag}`);
244
+ if (node.style) element = /* @__PURE__ */ jsx("span", {
245
+ style: parseCSSText(node.style),
246
+ children: element
247
+ }, key);
248
+ return element;
249
+ }
250
+ //#endregion
251
+ //#region src/static-renderer/preprocess/footnote.ts
252
+ function preprocessFootnotes(state) {
253
+ const definitions = {};
254
+ const seen = /* @__PURE__ */ new Set();
255
+ const displayNumberMap = {};
256
+ let counter = 1;
257
+ function walk(node) {
258
+ if (node.type === "footnote" && node.identifier) {
259
+ const id = node.identifier;
260
+ if (!seen.has(id)) {
261
+ seen.add(id);
262
+ displayNumberMap[id] = counter++;
263
+ }
264
+ }
265
+ if (node.type === "footnote-section" && node.definitions) Object.assign(definitions, node.definitions);
266
+ if (node.children) for (const child of node.children) walk(child);
267
+ if (node.root) walk(node.root);
268
+ if (node.content && typeof node.content === "object" && node.content.root) walk(node.content);
269
+ if (node.cells && Array.isArray(node.cells)) {
270
+ for (const cell of node.cells) if (cell && cell.root) walk(cell);
271
+ }
272
+ }
273
+ walk(state);
274
+ for (const id of seen) if (!(id in definitions)) definitions[id] = "";
275
+ return {
276
+ definitions,
277
+ displayNumberMap
278
+ };
279
+ }
280
+ //#endregion
281
+ //#region src/static-renderer/RichRenderer.tsx
282
+ var alertClassName = (type) => `${semanticClassNames.alert} ${sharedStyles.alert} rich-alert-${type}`;
283
+ function wrapDecoration(serialized, key, decoration) {
284
+ switch (serialized.type) {
285
+ case "alert-quote": return createElement("div", {
286
+ key,
287
+ className: alertClassName(serialized.alertType)
288
+ }, decoration);
289
+ case "banner": return createElement("div", {
290
+ key,
291
+ className: `rich-banner rich-banner-${serialized.bannerType}`
292
+ }, decoration);
293
+ case "grid-container": return createElement("div", {
294
+ key,
295
+ className: `${gridClassNames.container} ${gridStyles.container}`
296
+ }, decoration);
297
+ default:
298
+ if (isValidElement(decoration)) return cloneElement(decoration, { key });
299
+ return decoration;
300
+ }
301
+ }
302
+ function applyBlockId(element, blockId, nodeKey) {
303
+ if (!blockId) return element;
304
+ if (isValidElement(element) && typeof element.type === "string") return cloneElement(element, { "data-block-id": blockId });
305
+ return /* @__PURE__ */ jsx("div", {
306
+ className: "rich-block-anchor",
307
+ "data-block-id": blockId,
308
+ children: element
309
+ }, `${nodeKey}-block-anchor`);
310
+ }
311
+ function renderTree(node, editor, editorConfig, headingSlugs, key, blockId, builtinNodeOverrides) {
312
+ const nodeKey = node.getKey ? node.getKey() : key;
313
+ if (typeof node.decorate === "function") try {
314
+ const decoration = node.decorate(editor, editorConfig);
315
+ if (decoration != null) return applyBlockId(wrapDecoration(node.exportJSON ? node.exportJSON() : {}, nodeKey, decoration), blockId, nodeKey);
316
+ } catch {}
317
+ const serialized = node.exportJSON ? node.exportJSON() : {};
318
+ if (serialized.type === "text") return renderTextNode(serialized, nodeKey);
319
+ const childNodes = typeof node.getChildren === "function" ? node.getChildren() : [];
320
+ if (Array.isArray(serialized.children) && serialized.children.length === 0 && childNodes.length > 0) serialized.children = childNodes.map((c) => ({ type: typeof c.getType === "function" ? c.getType() : c.__type }));
321
+ let children = null;
322
+ if (childNodes.length > 0) children = childNodes.map((child, i) => renderTree(child, editor, editorConfig, headingSlugs, `${nodeKey}-${i}`, void 0, builtinNodeOverrides));
323
+ const textContent = node.getTextContent ? node.getTextContent() : void 0;
324
+ const override = builtinNodeOverrides?.[serialized.type];
325
+ if (override) {
326
+ const defaultRenderer = () => renderBuiltinNode(serialized, nodeKey, children, headingSlugs, textContent);
327
+ return applyBlockId(override(serialized, nodeKey, children, defaultRenderer), blockId, nodeKey);
328
+ }
329
+ return applyBlockId(renderBuiltinNode(serialized, nodeKey, children, headingSlugs, textContent), blockId, nodeKey);
330
+ }
331
+ function renderEditorToReact(value, nodes, builtinNodeOverrides) {
332
+ const editor = createHeadlessEditor({
333
+ nodes,
334
+ theme: editorTheme,
335
+ editable: false,
336
+ onError: (error) => {
337
+ console.error("[RichRenderer]", error);
338
+ }
339
+ });
340
+ const editorConfig = {
341
+ namespace: "ssr",
342
+ theme: editorTheme
343
+ };
344
+ const normalizedValue = normalizeSerializedEditorState(value);
345
+ const editorState = editor.parseEditorState(normalizedValue);
346
+ editor.setEditorState(editorState);
347
+ const footnoteData = preprocessFootnotes(normalizedValue);
348
+ const rawRootChildren = normalizedValue.root?.children;
349
+ let content = null;
350
+ editorState.read(() => {
351
+ const root = $getRoot();
352
+ const headingSlugs = /* @__PURE__ */ new Map();
353
+ content = /* @__PURE__ */ jsx(Fragment$1, { children: root.getChildren().map((child, i) => renderTree(child, editor, editorConfig, headingSlugs, `ssr-${i}`, rawRootChildren?.[i]?.$?.blockId, builtinNodeOverrides)) });
354
+ });
355
+ const renderNestedContent = (state) => {
356
+ const nestedEditor = createHeadlessEditor({
357
+ nodes,
358
+ theme: editorTheme,
359
+ editable: false,
360
+ onError: (error) => {
361
+ console.error("[RichRenderer:nested]", error);
362
+ }
363
+ });
364
+ const nestedEditorConfig = {
365
+ namespace: "ssr-nested",
366
+ theme: editorTheme
367
+ };
368
+ const normalizedState = normalizeSerializedEditorState(state);
369
+ const nestedState = nestedEditor.parseEditorState(normalizedState);
370
+ nestedEditor.setEditorState(nestedState);
371
+ let nested = null;
372
+ const nestedRawChildren = normalizedState.root?.children;
373
+ nestedState.read(() => {
374
+ const root = $getRoot();
375
+ const headingSlugs = /* @__PURE__ */ new Map();
376
+ nested = /* @__PURE__ */ jsx(Fragment$1, { children: root.getChildren().map((child, i) => renderTree(child, nestedEditor, nestedEditorConfig, headingSlugs, `nested-${i}`, nestedRawChildren?.[i]?.$?.blockId, builtinNodeOverrides)) });
377
+ });
378
+ return nested;
379
+ };
380
+ return {
381
+ content,
382
+ footnoteData,
383
+ renderNestedContent
384
+ };
385
+ }
386
+ function RichRenderer({ value, variant = "article", theme = "light", className, style, as: Component = "div", nested = false, rendererConfig, extraNodes, builtinNodeOverrides }) {
387
+ const variantClass = getVariantClass(variant);
388
+ const outerRenderNestedContent = useOptionalNestedContentRenderer();
389
+ const { content, footnoteData, renderNestedContent } = useMemo(() => {
390
+ return renderEditorToReact(value, extraNodes ? [...allNodes, ...extraNodes] : allNodes, builtinNodeOverrides);
391
+ }, [
392
+ builtinNodeOverrides,
393
+ extraNodes,
394
+ value
395
+ ]);
396
+ const classes = [
397
+ "rich-content",
398
+ variantClass,
399
+ className
400
+ ].filter(Boolean).join(" ");
401
+ return /* @__PURE__ */ jsx(PortalThemeProvider, {
402
+ className: variantClass,
403
+ theme,
404
+ children: /* @__PURE__ */ jsx(ColorSchemeProvider, {
405
+ colorScheme: theme,
406
+ children: /* @__PURE__ */ jsx(RendererConfigProvider, {
407
+ config: rendererConfig,
408
+ mode: "renderer",
409
+ variant,
410
+ children: /* @__PURE__ */ jsx(FootnoteDefinitionsProvider, {
411
+ definitions: footnoteData.definitions,
412
+ displayNumberMap: footnoteData.displayNumberMap,
413
+ children: /* @__PURE__ */ jsx(NestedContentRendererProvider$1, {
414
+ value: outerRenderNestedContent ?? renderNestedContent,
415
+ children: /* @__PURE__ */ jsx(Component, {
416
+ suppressHydrationWarning: true,
417
+ className: classes,
418
+ "data-rich-nested": nested ? "true" : void 0,
419
+ "data-theme": theme,
420
+ style,
421
+ children: content
422
+ })
423
+ })
424
+ })
425
+ })
426
+ })
427
+ });
428
+ }
429
+ //#endregion
5
430
  //#region src/core/dedup.ts
6
431
  /**
7
432
  * Merge preset and modules, deduplicating by:
@@ -143,4 +568,4 @@ function composeRenderer(opts) {
143
568
  return memo(ComposedRenderer);
144
569
  }
145
570
  //#endregion
146
- export { composeRenderer, dedupNodes, mergeModules, wrapLazy };
571
+ export { RichRenderer, composeRenderer, dedupNodes, mergeModules, wrapLazy };
@@ -1,5 +1,5 @@
1
1
  export { pollModule } from './module';
2
2
  export type { SerializedPollNode } from './node';
3
- export { $createPollNode, $isPollNode, PollNode, pollNodes, } from './node';
3
+ export { $createPollNode, $isPollNode, PollNode, pollNodes } from './node';
4
4
  export { PollRenderer } from './renderer';
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/poll/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EACL,eAAe,EACf,WAAW,EACX,QAAQ,EACR,SAAS,GACV,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/modules/poll/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAC3E,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
@@ -1,3 +1,3 @@
1
1
  export type { SerializedPollNode } from '@haklex/rich-ext-poll/node';
2
- export { $createPollNode, $isPollNode, PollNode, pollNodes, } from '@haklex/rich-ext-poll/node';
2
+ export { $createPollNode, $isPollNode, PollNode, pollNodes } from '@haklex/rich-ext-poll/node';
3
3
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/modules/poll/node.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EACL,eAAe,EACf,WAAW,EACX,QAAQ,EACR,SAAS,GACV,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../src/modules/poll/node.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC"}
@@ -0,0 +1,2 @@
1
+ :root{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}:root.dark,[data-theme=dark]{--rc-text:#fafafa;--rc-text-secondary:#a3a3a3;--rc-text-tertiary:#737373;--rc-text-quaternary:#525252;--rc-bg:#0a0a0a;--rc-bg-secondary:#171717;--rc-bg-tertiary:#262626;--rc-fill:#2a2a2a;--rc-fill-secondary:#222;--rc-fill-tertiary:#1a1a1a;--rc-fill-quaternary:#141414;--rc-border:#262626;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#d4d4d4;--rc-code-bg:#262626;--rc-hr-border:#262626;--rc-quote-border:#60a5fa;--rc-quote-bg:#262626;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._1tdqahx0{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.7;--rc-line-height-tight:1.4;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._1tdqahx1{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#2563eb;--rc-quote-bg:#f5f5f5;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:700px;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:4px;--rc-space-sm:8px;--rc-space-md:16px;--rc-space-lg:24px;--rc-space-xl:32px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:16px;--rc-font-size-small:14px;--rc-line-height:1.8;--rc-line-height-tight:1.4;--rc-font-family:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-radius-sm:4px;--rc-radius-md:8px;--rc-radius-lg:12px}._1tdqahx2{--rc-text:#000;--rc-text-secondary:#262626;--rc-text-tertiary:#737373;--rc-text-quaternary:#a3a3a3;--rc-bg:#fff;--rc-bg-secondary:#fafafa;--rc-bg-tertiary:#f5f5f5;--rc-fill:#e8e8e8;--rc-fill-secondary:#eee;--rc-fill-tertiary:#f5f5f5;--rc-fill-quaternary:#fafafa;--rc-border:#f5f5f5;--rc-accent:#2563eb;--rc-accent-light:#2563eb20;--rc-link:#2563eb;--rc-code-text:#404040;--rc-code-bg:#f5f5f5;--rc-hr-border:#e5e5e5;--rc-quote-border:#a3a3a3;--rc-quote-bg:#fafafa;--rc-alert-info:#006bb7;--rc-alert-warning:#c50;--rc-alert-tip:#1c0;--rc-alert-caution:#c01;--rc-alert-important:#50c;--rc-max-width:none;--rc-shadow-top-bar:0 8px 30px #0000001f, 0 2px 8px #0000000f;--rc-shadow-modal:0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a;--rc-shadow-menu:0 1px 4px #0000000a, 0 4px 16px #00000014;--rc-space-xs:2px;--rc-space-sm:4px;--rc-space-md:10px;--rc-space-lg:16px;--rc-space-xl:20px;--rc-font-family-sans:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-font-family-serif:"Noto Serif CJK SC", "Source Han Serif SC", "Source Han Serif", "source-han-serif-sc", "Songti SC", STSong, "华文宋体", serif;--rc-font-family-kai:"楷体", KaiTi, STKaiti, "Kaiti SC", "LXGW WenKai", "霞鹜文楷", "Noto Serif CJK SC", serif;--rc-font-mono:"SF Mono", SFMono-Regular, ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace;--rc-font-size-2xs:.625em;--rc-font-size-xs:.75em;--rc-font-size-sm:.8125em;--rc-font-size-md:.875em;--rc-font-size-lg:1.25em;--rc-font-size-base:14px;--rc-font-size-small:12px;--rc-line-height:1.5;--rc-line-height-tight:1.3;--rc-font-family:"PingFang SC", "Microsoft YaHei", "Segoe UI", Roboto, Helvetica, "noto sans sc", "hiragino sans gb", -apple-system, system-ui, sans-serif, Apple Color Emoji, Segoe UI Emoji, Not Color Emoji;--rc-radius-sm:3px;--rc-radius-md:6px;--rc-radius-lg:12px}.dark ._1tdqahx0,[data-theme=dark] ._1tdqahx0,.dark._1tdqahx0,[data-theme=dark]._1tdqahx0,.dark ._1tdqahx1,[data-theme=dark] ._1tdqahx1,.dark._1tdqahx1,[data-theme=dark]._1tdqahx1,.dark ._1tdqahx2,[data-theme=dark] ._1tdqahx2,.dark._1tdqahx2,[data-theme=dark]._1tdqahx2{--rc-text:#fafafa;--rc-text-secondary:#a3a3a3;--rc-text-tertiary:#737373;--rc-text-quaternary:#525252;--rc-bg:#0a0a0a;--rc-bg-secondary:#171717;--rc-bg-tertiary:#262626;--rc-fill:#2a2a2a;--rc-fill-secondary:#222;--rc-fill-tertiary:#1a1a1a;--rc-fill-quaternary:#141414;--rc-border:#262626;--rc-accent:#60a5fa;--rc-accent-light:#60a5fa20;--rc-link:#60a5fa;--rc-code-text:#d4d4d4;--rc-code-bg:#262626;--rc-hr-border:#262626;--rc-quote-border:#60a5fa;--rc-quote-bg:#262626;--rc-alert-info:#7db9e5;--rc-alert-warning:#da864a;--rc-alert-tip:#54da48;--rc-alert-caution:#e16973;--rc-alert-important:#9966e0;--rc-shadow-top-bar:0 8px 30px #00000073, 0 2px 8px #0000004d;--rc-shadow-modal:0 10px 15px -3px #0006, 0 4px 6px -4px #00000059;--rc-shadow-menu:0 1px 4px #00000040, 0 4px 16px #0006}.icqzyn0{overflow-x:auto}.icqzyn1{caption-side:bottom;border-collapse:collapse;width:100%;font-size:var(--rc-font-size-small)}.icqzyn2{height:2.5rem;padding:0 var(--rc-space-lg);vertical-align:middle;white-space:nowrap;color:var(--rc-text-secondary);font-weight:500;line-height:1.5}.icqzyn3{padding:var(--rc-space-lg);vertical-align:middle;line-height:1.5}.icqzyn1 tr:has(.icqzyn2){border-bottom:1px solid var(--rc-border)}.icqzyn1 tr:has(.icqzyn3):nth-child(2n){background-color:var(--rc-bg-secondary)}.icqzyn1:has(tr:hover) tr:has(.icqzyn3):nth-child(2n):not(:hover){background-color:#0000}.icqzyn1 tr:has(.icqzyn3){transition:background-color .15s}.icqzyn1 tr:has(.icqzyn3):hover{background-color:var(--rc-fill-tertiary)}.icqzyn1 .rich-paragraph{line-height:inherit;margin:0;padding:0}
2
+ /*$vite$:1*/
@@ -0,0 +1,3 @@
1
+ import { RichRendererProps } from './types';
2
+ export declare function RichRenderer({ value, variant, theme, className, style, as: Component, nested, rendererConfig, extraNodes, builtinNodeOverrides, }: RichRendererProps): import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=RichRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RichRenderer.d.ts","sourceRoot":"","sources":["../../src/static-renderer/RichRenderer.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAuB,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAiOtE,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,OAAmB,EACnB,KAAe,EACf,SAAS,EACT,KAAK,EACL,EAAE,EAAE,SAAiB,EACrB,MAAc,EACd,cAAc,EACd,UAAU,EACV,oBAAoB,GACrB,EAAE,iBAAiB,2CAoCnB"}
@@ -0,0 +1,6 @@
1
+ interface HtmlCommentProps {
2
+ text: string;
3
+ }
4
+ export declare function HtmlComment({ text }: HtmlCommentProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
6
+ //# sourceMappingURL=HtmlComment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HtmlComment.d.ts","sourceRoot":"","sources":["../../../src/static-renderer/components/HtmlComment.tsx"],"names":[],"mappings":"AAEA,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE,gBAAgB,2CA6BrD"}
@@ -0,0 +1,3 @@
1
+ import { ReactNode } from 'react';
2
+ export declare function renderBuiltinNode(node: any, key: string, children: ReactNode[] | null, headingSlugs: Map<string, number>, textContent?: string): ReactNode;
3
+ //# sourceMappingURL=renderBuiltinNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderBuiltinNode.d.ts","sourceRoot":"","sources":["../../../src/static-renderer/engine/renderBuiltinNode.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAkCtD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,GAAG,EACT,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAC5B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,WAAW,CAAC,EAAE,MAAM,GACnB,SAAS,CAiNX"}
@@ -0,0 +1,3 @@
1
+ import { ReactNode } from 'react';
2
+ export declare function renderTextNode(node: any, key: string): ReactNode;
3
+ //# sourceMappingURL=renderTextNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderTextNode.d.ts","sourceRoot":"","sources":["../../../src/static-renderer/engine/renderTextNode.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AA6BtD,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAuBhE"}
@@ -0,0 +1,3 @@
1
+ export { RichRenderer } from './RichRenderer';
2
+ export type { BuiltinNodeRenderer, RichRendererProps } from './types';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/static-renderer/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { SerializedEditorState } from 'lexical';
2
+ export interface FootnoteData {
3
+ definitions: Record<string, string>;
4
+ displayNumberMap: Record<string, number>;
5
+ }
6
+ export declare function preprocessFootnotes(state: SerializedEditorState): FootnoteData;
7
+ //# sourceMappingURL=footnote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footnote.d.ts","sourceRoot":"","sources":["../../../src/static-renderer/preprocess/footnote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,qBAAqB,GAAG,YAAY,CAwC9E"}
@@ -0,0 +1,5 @@
1
+ export declare const tableWrapper: string;
2
+ export declare const table: string;
3
+ export declare const tableHead: string;
4
+ export declare const tableCell: string;
5
+ //# sourceMappingURL=table.css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.css.d.ts","sourceRoot":"","sources":["../../src/static-renderer/table.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,QAEvB,CAAC;AAEH,eAAO,MAAM,KAAK,QAKhB,CAAC;AAEH,eAAO,MAAM,SAAS,QAQpB,CAAC;AAEH,eAAO,MAAM,SAAS,QAIpB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { ColorScheme, RendererConfig, RichEditorVariant } from '@haklex/rich-editor/static';
2
+ import { Klass, LexicalNode, SerializedEditorState } from 'lexical';
3
+ import { CSSProperties, ReactNode } from 'react';
4
+ export type BuiltinNodeRenderer = (node: any, key: string, children: ReactNode[] | null, defaultRenderer: () => ReactNode) => ReactNode;
5
+ export interface RichRendererProps {
6
+ as?: keyof React.JSX.IntrinsicElements;
7
+ builtinNodeOverrides?: Record<string, BuiltinNodeRenderer>;
8
+ className?: string;
9
+ extraNodes?: Array<Klass<LexicalNode>>;
10
+ nested?: boolean;
11
+ rendererConfig?: RendererConfig;
12
+ style?: CSSProperties;
13
+ theme?: ColorScheme;
14
+ value: SerializedEditorState;
15
+ variant?: RichEditorVariant;
16
+ }
17
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/static-renderer/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AACjG,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG,CAChC,IAAI,EAAE,GAAG,EACT,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAC5B,eAAe,EAAE,MAAM,SAAS,KAC7B,SAAS,CAAC;AAEf,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC;IACvC,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,qBAAqB,CAAC;IAC7B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haklex/rich-compose",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Compose primitives for haklex rich content renderers — Gundam-style assembly of Lexical nodes, sync/lazy renderers, and Provider stacks.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -167,59 +167,66 @@
167
167
  "files": [
168
168
  "dist"
169
169
  ],
170
+ "dependencies": {
171
+ "@lexical/headless": "^0.44.0"
172
+ },
170
173
  "devDependencies": {
171
174
  "@lexical/react": "^0.44.0",
172
175
  "@types/react": "^19.2.14",
173
176
  "@types/react-dom": "^19.2.3",
177
+ "@vanilla-extract/css": "^1.20.1",
178
+ "@vanilla-extract/vite-plugin": "^5.2.2",
174
179
  "lexical": "^0.44.0",
180
+ "lucide-react": "^1.0.0",
175
181
  "react": "19.2.5",
176
182
  "react-dom": "19.2.5",
177
183
  "typescript": "^5.9.3",
178
184
  "vite": "^8.0.10",
179
185
  "vite-plugin-dts": "^4.5.4",
180
186
  "vitest": "^4.1.5",
181
- "@haklex/rich-editor": "0.5.0",
182
- "@haklex/rich-ext-chat": "0.5.0",
183
- "@haklex/rich-ext-code-snippet": "0.5.0",
184
- "@haklex/rich-ext-embed": "0.5.0",
185
- "@haklex/rich-ext-nested-doc": "0.5.0",
186
- "@haklex/rich-ext-poll": "0.5.0",
187
- "@haklex/rich-renderer-banner": "0.5.0",
188
- "@haklex/rich-renderer-codeblock": "0.5.0",
189
- "@haklex/rich-ext-excalidraw": "0.5.0",
190
- "@haklex/rich-renderer-alert": "0.5.0",
191
- "@haklex/rich-ext-gallery": "0.5.0",
192
- "@haklex/rich-renderer-linkcard": "0.5.0",
193
- "@haklex/rich-renderer-image": "0.5.0",
194
- "@haklex/rich-renderer-mention": "0.5.0",
195
- "@haklex/rich-renderer-mermaid": "0.5.0",
196
- "@haklex/rich-renderer-video": "0.5.0",
197
- "@haklex/rich-renderer-ruby": "0.5.0",
198
- "@haklex/rich-static-renderer": "0.5.0"
187
+ "@haklex/rich-editor": "0.6.0",
188
+ "@haklex/rich-ext-code-snippet": "0.6.0",
189
+ "@haklex/rich-ext-chat": "0.6.0",
190
+ "@haklex/rich-ext-embed": "0.6.0",
191
+ "@haklex/rich-ext-poll": "0.6.0",
192
+ "@haklex/rich-ext-nested-doc": "0.6.0",
193
+ "@haklex/rich-ext-gallery": "0.6.0",
194
+ "@haklex/rich-renderer-alert": "0.6.0",
195
+ "@haklex/rich-renderer-image": "0.6.0",
196
+ "@haklex/rich-ext-excalidraw": "0.6.0",
197
+ "@haklex/rich-renderer-codeblock": "0.6.0",
198
+ "@haklex/rich-renderer-banner": "0.6.0",
199
+ "@haklex/rich-renderer-mention": "0.6.0",
200
+ "@haklex/rich-renderer-linkcard": "0.6.0",
201
+ "@haklex/rich-renderer-mermaid": "0.6.0",
202
+ "@haklex/rich-renderer-ruby": "0.6.0",
203
+ "@haklex/rich-style-token": "0.6.0",
204
+ "@haklex/rich-renderer-video": "0.6.0"
199
205
  },
200
206
  "peerDependencies": {
201
207
  "@lexical/react": "^0.44.0",
202
208
  "lexical": "^0.44.0",
209
+ "lucide-react": "^1.0.0",
203
210
  "react": ">=19",
204
211
  "react-dom": ">=19",
205
- "@haklex/rich-editor": "0.5.0",
206
- "@haklex/rich-ext-code-snippet": "0.5.0",
207
- "@haklex/rich-ext-embed": "0.5.0",
208
- "@haklex/rich-ext-excalidraw": "0.5.0",
209
- "@haklex/rich-ext-chat": "0.5.0",
210
- "@haklex/rich-ext-gallery": "0.5.0",
211
- "@haklex/rich-ext-poll": "0.5.0",
212
- "@haklex/rich-ext-nested-doc": "0.5.0",
213
- "@haklex/rich-renderer-banner": "0.5.0",
214
- "@haklex/rich-renderer-mermaid": "0.5.0",
215
- "@haklex/rich-renderer-image": "0.5.0",
216
- "@haklex/rich-renderer-mention": "0.5.0",
217
- "@haklex/rich-renderer-linkcard": "0.5.0",
218
- "@haklex/rich-renderer-alert": "0.5.0",
219
- "@haklex/rich-renderer-codeblock": "0.5.0",
220
- "@haklex/rich-renderer-ruby": "0.5.0",
221
- "@haklex/rich-renderer-video": "0.5.0",
222
- "@haklex/rich-static-renderer": "0.5.0"
212
+ "@haklex/rich-ext-chat": "0.6.0",
213
+ "@haklex/rich-ext-code-snippet": "0.6.0",
214
+ "@haklex/rich-ext-embed": "0.6.0",
215
+ "@haklex/rich-editor": "0.6.0",
216
+ "@haklex/rich-ext-excalidraw": "0.6.0",
217
+ "@haklex/rich-ext-nested-doc": "0.6.0",
218
+ "@haklex/rich-ext-poll": "0.6.0",
219
+ "@haklex/rich-ext-gallery": "0.6.0",
220
+ "@haklex/rich-renderer-alert": "0.6.0",
221
+ "@haklex/rich-renderer-banner": "0.6.0",
222
+ "@haklex/rich-renderer-codeblock": "0.6.0",
223
+ "@haklex/rich-renderer-image": "0.6.0",
224
+ "@haklex/rich-renderer-linkcard": "0.6.0",
225
+ "@haklex/rich-renderer-mermaid": "0.6.0",
226
+ "@haklex/rich-renderer-mention": "0.6.0",
227
+ "@haklex/rich-style-token": "0.6.0",
228
+ "@haklex/rich-renderer-video": "0.6.0",
229
+ "@haklex/rich-renderer-ruby": "0.6.0"
223
230
  },
224
231
  "peerDependenciesMeta": {
225
232
  "@haklex/rich-ext-chat": {