@haklex/rich-static-renderer 0.0.38
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/LICENSE +28 -0
- package/README.md +133 -0
- package/dist/RichRenderer.d.ts +3 -0
- package/dist/RichRenderer.d.ts.map +1 -0
- package/dist/engine/renderBuiltinNode.d.ts +3 -0
- package/dist/engine/renderBuiltinNode.d.ts.map +1 -0
- package/dist/engine/renderNode.d.ts +3 -0
- package/dist/engine/renderNode.d.ts.map +1 -0
- package/dist/engine/renderTextNode.d.ts +3 -0
- package/dist/engine/renderTextNode.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +398 -0
- package/dist/preprocess/footnote.d.ts +7 -0
- package/dist/preprocess/footnote.d.ts.map +1 -0
- package/dist/preprocess/headingSlug.d.ts +2 -0
- package/dist/preprocess/headingSlug.d.ts.map +1 -0
- package/dist/rich-static-renderer.css +1 -0
- package/dist/table.css.d.ts +5 -0
- package/dist/table.css.d.ts.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Innei
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Additional Terms and Conditions
|
|
25
|
+
|
|
26
|
+
----------------
|
|
27
|
+
|
|
28
|
+
Use of this software is governed by the terms of MIT and, in addition, by the terms and conditions described in the additional file (ADDITIONAL_TERMS.md). By using this software, you agree to abide by these additional terms and conditions.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# @haklex/rich-static-renderer
|
|
2
|
+
|
|
3
|
+
Lexical 富文本的只读渲染引擎(Headless + React 输出)。
|
|
4
|
+
用于把 `SerializedEditorState` 渲染成可展示的 React 内容。
|
|
5
|
+
|
|
6
|
+
## 包定位
|
|
7
|
+
|
|
8
|
+
- 不提供编辑能力
|
|
9
|
+
- 适合文章详情页、评论展示、SSR 输出
|
|
10
|
+
- 默认支持 `@haklex/rich-editor` 内置节点(`allNodes`)
|
|
11
|
+
|
|
12
|
+
## 安装
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add @haklex/rich-static-renderer @haklex/rich-editor lexical react react-dom
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## 快速开始
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import { RichRenderer } from '@haklex/rich-static-renderer'
|
|
22
|
+
import type { SerializedEditorState } from 'lexical'
|
|
23
|
+
import '@haklex/rich-editor/style.css'
|
|
24
|
+
|
|
25
|
+
export function Article({
|
|
26
|
+
value,
|
|
27
|
+
}: {
|
|
28
|
+
value: SerializedEditorState
|
|
29
|
+
}) {
|
|
30
|
+
return <RichRenderer value={value} variant="article" theme="light" />
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
interface RichRendererProps {
|
|
38
|
+
value: SerializedEditorState
|
|
39
|
+
variant?: 'article' | 'comment' | 'note'
|
|
40
|
+
theme?: 'light' | 'dark'
|
|
41
|
+
className?: string
|
|
42
|
+
style?: CSSProperties
|
|
43
|
+
as?: keyof React.JSX.IntrinsicElements
|
|
44
|
+
rendererConfig?: RendererConfig
|
|
45
|
+
extraNodes?: Array<Klass<LexicalNode>>
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
字段说明:
|
|
50
|
+
|
|
51
|
+
- `value`:Lexical JSON(必填)
|
|
52
|
+
- `as`:渲染容器标签,默认 `div`
|
|
53
|
+
- `rendererConfig`:覆写某些节点的渲染组件(Image/CodeBlock/...)
|
|
54
|
+
- `extraNodes`:注册扩展节点(如 Tldraw、Embed、Gallery、CodeSnippet)
|
|
55
|
+
|
|
56
|
+
## 与增强渲染器一起用
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { RichRenderer } from '@haklex/rich-static-renderer'
|
|
60
|
+
import {
|
|
61
|
+
codeSnippetNodes,
|
|
62
|
+
embedNodes,
|
|
63
|
+
enhancedRendererConfig,
|
|
64
|
+
galleryNodes,
|
|
65
|
+
TldrawNode,
|
|
66
|
+
} from '@haklex/rich-renderers'
|
|
67
|
+
|
|
68
|
+
import '@haklex/rich-editor/style.css'
|
|
69
|
+
import '@haklex/rich-renderers/style.css'
|
|
70
|
+
import '@haklex/rich-ext-code-snippet/style.css'
|
|
71
|
+
import '@haklex/rich-ext-embed/style.css'
|
|
72
|
+
import 'katex/dist/katex.min.css'
|
|
73
|
+
import 'tldraw/tldraw.css'
|
|
74
|
+
|
|
75
|
+
const extraNodes = [
|
|
76
|
+
TldrawNode,
|
|
77
|
+
...embedNodes,
|
|
78
|
+
...galleryNodes,
|
|
79
|
+
...codeSnippetNodes,
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
<RichRenderer
|
|
83
|
+
value={value}
|
|
84
|
+
rendererConfig={enhancedRendererConfig}
|
|
85
|
+
extraNodes={extraNodes}
|
|
86
|
+
/>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 渲染行为说明
|
|
90
|
+
|
|
91
|
+
- 内部使用 `@lexical/headless` 构建只读 editor,再将节点树转为 React
|
|
92
|
+
- 标题会自动生成 slug 与锚点(重复标题自动去重)
|
|
93
|
+
- 脚注会先预处理编号,再统一渲染引用与定义
|
|
94
|
+
- `Alert/Banner/Grid` 等嵌套内容通过 `NestedContentRendererProvider` 递归渲染
|
|
95
|
+
|
|
96
|
+
## 设计模式
|
|
97
|
+
|
|
98
|
+
### 1) 节点注册与渲染器覆写解耦
|
|
99
|
+
|
|
100
|
+
- 节点协议(JSON 结构)由 Node class 决定
|
|
101
|
+
- 显示层由 `rendererConfig` 决定
|
|
102
|
+
- 扩展节点只需通过 `extraNodes` 注册,不要求侵入核心渲染器
|
|
103
|
+
|
|
104
|
+
### 2) Static / Edit 拆分协作
|
|
105
|
+
|
|
106
|
+
`@haklex/rich-static-renderer` 只消费静态节点。
|
|
107
|
+
编辑态重依赖(Popover、Dialog 等)应该放在 edit 节点/编辑包里,不进入只读包。
|
|
108
|
+
|
|
109
|
+
## 常见问题
|
|
110
|
+
|
|
111
|
+
### Q1: 为什么有些节点不显示?
|
|
112
|
+
|
|
113
|
+
通常是忘了注册扩展节点(`extraNodes`),例如 `embed`、`tldraw`、`gallery`、`code-snippet`。
|
|
114
|
+
|
|
115
|
+
### Q2: 为什么公式样式不对?
|
|
116
|
+
|
|
117
|
+
需要手动引入:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import 'katex/dist/katex.min.css'
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Q3: 为什么 tldraw 画布样式错乱?
|
|
124
|
+
|
|
125
|
+
需要手动引入:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import 'tldraw/tldraw.css'
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { RichRendererProps } from './types';
|
|
2
|
+
export declare function RichRenderer({ value, variant, theme, className, style, as: Component, rendererConfig, extraNodes, }: 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/RichRenderer.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AA+JhD,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,OAAmB,EACnB,KAAe,EACf,SAAS,EACT,KAAK,EACL,EAAE,EAAE,SAAiB,EACrB,cAAc,EACd,UAAU,GACX,EAAE,iBAAiB,2CAmCnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderBuiltinNode.d.ts","sourceRoot":"","sources":["../../src/engine/renderBuiltinNode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAmBtC,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,GAChC,SAAS,CAwLX"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderNode.d.ts","sourceRoot":"","sources":["../../src/engine/renderNode.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderTextNode.d.ts","sourceRoot":"","sources":["../../src/engine/renderTextNode.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AA6BrD,wBAAgB,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,CAuBhE"}
|
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,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { getVariantClass, allNodes, ColorSchemeProvider, RendererConfigProvider, FootnoteDefinitionsProvider, NestedContentRendererProvider, editorTheme } from "@haklex/rich-editor/static";
|
|
3
|
+
import { PortalThemeProvider } from "@haklex/rich-style-token";
|
|
4
|
+
import { createHeadlessEditor } from "@lexical/headless";
|
|
5
|
+
import { $getRoot } from "lexical";
|
|
6
|
+
import { isValidElement, cloneElement, createElement } from "react";
|
|
7
|
+
var tableWrapper = "_1v9yxw30";
|
|
8
|
+
var table = "_1v9yxw31";
|
|
9
|
+
var tableHead = "_1v9yxw32";
|
|
10
|
+
var tableCell = "_1v9yxw33";
|
|
11
|
+
function textToSlug(text) {
|
|
12
|
+
return text.toLowerCase().trim().replaceAll(/[^\w\s\u3001-\u9fff\uac00-\ud7af\uff00-\uffef-]/g, "").replaceAll(/[\s_]+/g, "-").replaceAll(/^-+|-+$/g, "");
|
|
13
|
+
}
|
|
14
|
+
function extractText(node) {
|
|
15
|
+
if (node.text) return node.text;
|
|
16
|
+
if (node.children) return node.children.map(extractText).join("");
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
function renderBuiltinNode(node, key, children, headingSlugs) {
|
|
20
|
+
switch (node.type) {
|
|
21
|
+
case "root":
|
|
22
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
23
|
+
case "paragraph": {
|
|
24
|
+
const align = node.format ? { textAlign: node.format } : void 0;
|
|
25
|
+
return /* @__PURE__ */ jsx("p", { className: "rich-paragraph", style: align, children }, key);
|
|
26
|
+
}
|
|
27
|
+
case "heading": {
|
|
28
|
+
const Tag = node.tag;
|
|
29
|
+
const text = extractText(node);
|
|
30
|
+
const baseSlug = textToSlug(text);
|
|
31
|
+
let slug = baseSlug;
|
|
32
|
+
if (baseSlug) {
|
|
33
|
+
const count = headingSlugs.get(baseSlug);
|
|
34
|
+
if (count !== void 0) {
|
|
35
|
+
slug = `${baseSlug}-${count}`;
|
|
36
|
+
headingSlugs.set(baseSlug, count + 1);
|
|
37
|
+
} else {
|
|
38
|
+
headingSlugs.set(baseSlug, 1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return /* @__PURE__ */ jsxs(Tag, { id: slug || void 0, className: `rich-heading-${Tag}`, children: [
|
|
42
|
+
slug && /* @__PURE__ */ jsx(
|
|
43
|
+
"a",
|
|
44
|
+
{
|
|
45
|
+
className: "rich-heading-anchor",
|
|
46
|
+
"aria-hidden": "true",
|
|
47
|
+
tabIndex: -1,
|
|
48
|
+
href: `#${slug}`
|
|
49
|
+
}
|
|
50
|
+
),
|
|
51
|
+
children
|
|
52
|
+
] }, key);
|
|
53
|
+
}
|
|
54
|
+
case "quote":
|
|
55
|
+
return /* @__PURE__ */ jsx("blockquote", { className: "rich-quote", children }, key);
|
|
56
|
+
case "list": {
|
|
57
|
+
const Tag = node.listType === "number" ? "ol" : "ul";
|
|
58
|
+
const cls = node.listType === "number" ? "rich-list-ol" : node.listType === "check" ? "rich-checklist rich-list-ul" : "rich-list-ul";
|
|
59
|
+
return /* @__PURE__ */ jsx(
|
|
60
|
+
Tag,
|
|
61
|
+
{
|
|
62
|
+
className: cls,
|
|
63
|
+
start: node.start !== 1 ? node.start : void 0,
|
|
64
|
+
children
|
|
65
|
+
},
|
|
66
|
+
key
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
case "listitem": {
|
|
70
|
+
const isChecklist = node.checked !== void 0;
|
|
71
|
+
const hasNestedList = node.children?.some((c) => c.type === "list");
|
|
72
|
+
let cls;
|
|
73
|
+
if (hasNestedList) {
|
|
74
|
+
cls = "rich-list-nested-item";
|
|
75
|
+
} else if (isChecklist) {
|
|
76
|
+
cls = node.checked ? "rich-list-item rich-list-item-checked" : "rich-list-item rich-list-item-unchecked";
|
|
77
|
+
} else {
|
|
78
|
+
cls = "rich-list-item";
|
|
79
|
+
}
|
|
80
|
+
return /* @__PURE__ */ jsx("li", { className: cls, value: node.value, children }, key);
|
|
81
|
+
}
|
|
82
|
+
case "link":
|
|
83
|
+
return /* @__PURE__ */ jsx(
|
|
84
|
+
"a",
|
|
85
|
+
{
|
|
86
|
+
className: "rich-link",
|
|
87
|
+
href: node.url,
|
|
88
|
+
target: node.target,
|
|
89
|
+
rel: node.rel,
|
|
90
|
+
children
|
|
91
|
+
},
|
|
92
|
+
key
|
|
93
|
+
);
|
|
94
|
+
case "autolink":
|
|
95
|
+
return /* @__PURE__ */ jsx(
|
|
96
|
+
"a",
|
|
97
|
+
{
|
|
98
|
+
className: "rich-link",
|
|
99
|
+
href: node.url,
|
|
100
|
+
target: "_blank",
|
|
101
|
+
rel: "noopener noreferrer",
|
|
102
|
+
children
|
|
103
|
+
},
|
|
104
|
+
key
|
|
105
|
+
);
|
|
106
|
+
case "horizontalrule":
|
|
107
|
+
return /* @__PURE__ */ jsx("hr", { className: "rich-hr" }, key);
|
|
108
|
+
case "table":
|
|
109
|
+
return /* @__PURE__ */ jsx("div", { className: tableWrapper, children: /* @__PURE__ */ jsx("table", { className: table, children }) }, key);
|
|
110
|
+
case "tablerow":
|
|
111
|
+
return /* @__PURE__ */ jsx("tr", { children }, key);
|
|
112
|
+
case "tablecell": {
|
|
113
|
+
const CellTag = node.headerState ? "th" : "td";
|
|
114
|
+
const cls = node.headerState ? tableHead : tableCell;
|
|
115
|
+
return /* @__PURE__ */ jsx(
|
|
116
|
+
CellTag,
|
|
117
|
+
{
|
|
118
|
+
className: cls,
|
|
119
|
+
colSpan: node.colSpan > 1 ? node.colSpan : void 0,
|
|
120
|
+
children
|
|
121
|
+
},
|
|
122
|
+
key
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
case "details": {
|
|
126
|
+
const summary = node.summary || "";
|
|
127
|
+
return /* @__PURE__ */ jsxs(
|
|
128
|
+
"details",
|
|
129
|
+
{
|
|
130
|
+
className: "rich-details",
|
|
131
|
+
open: node.open || void 0,
|
|
132
|
+
children: [
|
|
133
|
+
/* @__PURE__ */ jsxs("summary", { className: "rich-details-summary", children: [
|
|
134
|
+
/* @__PURE__ */ jsx("span", { className: "rich-details-summary-text", children: summary }),
|
|
135
|
+
/* @__PURE__ */ jsx("span", { className: "rich-details-chevron", children: /* @__PURE__ */ jsx(
|
|
136
|
+
"svg",
|
|
137
|
+
{
|
|
138
|
+
width: "20",
|
|
139
|
+
height: "20",
|
|
140
|
+
viewBox: "0 0 20 20",
|
|
141
|
+
fill: "none",
|
|
142
|
+
stroke: "currentColor",
|
|
143
|
+
strokeWidth: "1.5",
|
|
144
|
+
strokeLinecap: "round",
|
|
145
|
+
strokeLinejoin: "round",
|
|
146
|
+
children: /* @__PURE__ */ jsx("path", { d: "M6 8L10 12L14 8" })
|
|
147
|
+
}
|
|
148
|
+
) })
|
|
149
|
+
] }),
|
|
150
|
+
/* @__PURE__ */ jsx("div", { className: "rich-details-content", children })
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
key
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
case "spoiler":
|
|
157
|
+
return /* @__PURE__ */ jsx("span", { className: "rich-spoiler", role: "button", tabIndex: 0, children }, key);
|
|
158
|
+
case "code":
|
|
159
|
+
return /* @__PURE__ */ jsx("pre", { className: "rich-code-block", children: /* @__PURE__ */ jsx("code", { children }) }, key);
|
|
160
|
+
case "code-highlight":
|
|
161
|
+
return /* @__PURE__ */ jsx("span", { children: node.text }, key);
|
|
162
|
+
case "linebreak":
|
|
163
|
+
return /* @__PURE__ */ jsx("br", {}, key);
|
|
164
|
+
case "tab":
|
|
165
|
+
return /* @__PURE__ */ jsx("span", { children: " " }, key);
|
|
166
|
+
default:
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const FORMAT_FLAGS = [
|
|
171
|
+
[1, "rich-text-bold"],
|
|
172
|
+
[2, "rich-text-italic"],
|
|
173
|
+
[4, "rich-text-strikethrough"],
|
|
174
|
+
[8, "rich-text-underline"],
|
|
175
|
+
[16, "rich-text-code"],
|
|
176
|
+
[32, "rich-text-subscript"],
|
|
177
|
+
[64, "rich-text-superscript"],
|
|
178
|
+
[128, "rich-text-highlight"]
|
|
179
|
+
];
|
|
180
|
+
function parseCSSText(cssText) {
|
|
181
|
+
const style = {};
|
|
182
|
+
for (const part of cssText.split(";")) {
|
|
183
|
+
const colonIndex = part.indexOf(":");
|
|
184
|
+
if (colonIndex === -1) continue;
|
|
185
|
+
const prop = part.slice(0, colonIndex).trim();
|
|
186
|
+
const value = part.slice(colonIndex + 1).trim();
|
|
187
|
+
if (!prop || !value) continue;
|
|
188
|
+
const camelProp = prop.replaceAll(
|
|
189
|
+
/-([a-z])/g,
|
|
190
|
+
(_, c) => c.toUpperCase()
|
|
191
|
+
);
|
|
192
|
+
style[camelProp] = value;
|
|
193
|
+
}
|
|
194
|
+
return style;
|
|
195
|
+
}
|
|
196
|
+
function renderTextNode(node, key) {
|
|
197
|
+
let element = node.text;
|
|
198
|
+
const format = node.format || 0;
|
|
199
|
+
for (const [flag, className] of FORMAT_FLAGS) {
|
|
200
|
+
if (format & flag) {
|
|
201
|
+
element = /* @__PURE__ */ jsx("span", { className, children: element }, `${key}-${flag}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (node.style) {
|
|
205
|
+
element = /* @__PURE__ */ jsx("span", { style: parseCSSText(node.style), children: element }, key);
|
|
206
|
+
}
|
|
207
|
+
return element;
|
|
208
|
+
}
|
|
209
|
+
function preprocessFootnotes(state) {
|
|
210
|
+
const definitions = {};
|
|
211
|
+
const seen = /* @__PURE__ */ new Set();
|
|
212
|
+
const displayNumberMap = {};
|
|
213
|
+
let counter = 1;
|
|
214
|
+
function walk(node) {
|
|
215
|
+
if (node.type === "footnote" && node.identifier) {
|
|
216
|
+
const id = node.identifier;
|
|
217
|
+
if (!seen.has(id)) {
|
|
218
|
+
seen.add(id);
|
|
219
|
+
displayNumberMap[id] = counter++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (node.type === "footnote-section" && node.definitions) {
|
|
223
|
+
Object.assign(definitions, node.definitions);
|
|
224
|
+
}
|
|
225
|
+
if (node.children) {
|
|
226
|
+
for (const child of node.children) walk(child);
|
|
227
|
+
}
|
|
228
|
+
if (node.root) walk(node.root);
|
|
229
|
+
if (node.content && typeof node.content === "object" && node.content.root) {
|
|
230
|
+
walk(node.content);
|
|
231
|
+
}
|
|
232
|
+
if (node.cells && Array.isArray(node.cells)) {
|
|
233
|
+
for (const cell of node.cells) {
|
|
234
|
+
if (cell && cell.root) walk(cell);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
walk(state);
|
|
239
|
+
for (const id of seen) {
|
|
240
|
+
if (!(id in definitions)) {
|
|
241
|
+
definitions[id] = "";
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return { definitions, displayNumberMap };
|
|
245
|
+
}
|
|
246
|
+
function wrapDecoration(serialized, key, decoration) {
|
|
247
|
+
switch (serialized.type) {
|
|
248
|
+
case "alert-quote":
|
|
249
|
+
return createElement(
|
|
250
|
+
"div",
|
|
251
|
+
{ key, className: `rich-alert rich-alert-${serialized.alertType}` },
|
|
252
|
+
decoration
|
|
253
|
+
);
|
|
254
|
+
case "banner":
|
|
255
|
+
return createElement(
|
|
256
|
+
"div",
|
|
257
|
+
{ key, className: `rich-banner rich-banner-${serialized.bannerType}` },
|
|
258
|
+
decoration
|
|
259
|
+
);
|
|
260
|
+
case "grid-container":
|
|
261
|
+
return createElement(
|
|
262
|
+
"div",
|
|
263
|
+
{ key, className: "rich-grid-container" },
|
|
264
|
+
decoration
|
|
265
|
+
);
|
|
266
|
+
default:
|
|
267
|
+
if (isValidElement(decoration)) {
|
|
268
|
+
return cloneElement(decoration, { key });
|
|
269
|
+
}
|
|
270
|
+
return decoration;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function renderTree(node, editor, editorConfig, headingSlugs, key) {
|
|
274
|
+
const nodeKey = node.getKey ? node.getKey() : key;
|
|
275
|
+
if (typeof node.decorate === "function") {
|
|
276
|
+
try {
|
|
277
|
+
const decoration = node.decorate(editor, editorConfig);
|
|
278
|
+
if (decoration != null) {
|
|
279
|
+
const serialized2 = node.exportJSON ? node.exportJSON() : {};
|
|
280
|
+
return wrapDecoration(serialized2, nodeKey, decoration);
|
|
281
|
+
}
|
|
282
|
+
} catch {
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const serialized = node.exportJSON ? node.exportJSON() : {};
|
|
286
|
+
if (serialized.type === "text") {
|
|
287
|
+
return renderTextNode(serialized, nodeKey);
|
|
288
|
+
}
|
|
289
|
+
let children = null;
|
|
290
|
+
if (node.getChildren) {
|
|
291
|
+
const childNodes = node.getChildren();
|
|
292
|
+
if (childNodes.length > 0) {
|
|
293
|
+
children = childNodes.map(
|
|
294
|
+
(child, i) => renderTree(
|
|
295
|
+
child,
|
|
296
|
+
editor,
|
|
297
|
+
editorConfig,
|
|
298
|
+
headingSlugs,
|
|
299
|
+
`${nodeKey}-${i}`
|
|
300
|
+
)
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return renderBuiltinNode(serialized, nodeKey, children, headingSlugs);
|
|
305
|
+
}
|
|
306
|
+
function renderEditorToReact(value, nodes) {
|
|
307
|
+
const editor = createHeadlessEditor({
|
|
308
|
+
nodes,
|
|
309
|
+
theme: editorTheme,
|
|
310
|
+
editable: false,
|
|
311
|
+
onError: (error) => {
|
|
312
|
+
console.error("[RichRenderer]", error);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
const editorConfig = { namespace: "ssr", theme: editorTheme };
|
|
316
|
+
const editorState = editor.parseEditorState(value);
|
|
317
|
+
editor.setEditorState(editorState);
|
|
318
|
+
const footnoteData = preprocessFootnotes(value);
|
|
319
|
+
let content = null;
|
|
320
|
+
editorState.read(() => {
|
|
321
|
+
const root = $getRoot();
|
|
322
|
+
const headingSlugs = /* @__PURE__ */ new Map();
|
|
323
|
+
const children = root.getChildren().map(
|
|
324
|
+
(child, i) => renderTree(child, editor, editorConfig, headingSlugs, `ssr-${i}`)
|
|
325
|
+
);
|
|
326
|
+
content = /* @__PURE__ */ jsx(Fragment, { children });
|
|
327
|
+
});
|
|
328
|
+
const renderNestedContent = (state) => {
|
|
329
|
+
const nestedEditor = createHeadlessEditor({
|
|
330
|
+
nodes,
|
|
331
|
+
theme: editorTheme,
|
|
332
|
+
editable: false,
|
|
333
|
+
onError: (error) => {
|
|
334
|
+
console.error("[RichRenderer:nested]", error);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
const nestedEditorConfig = {
|
|
338
|
+
namespace: "ssr-nested",
|
|
339
|
+
theme: editorTheme
|
|
340
|
+
};
|
|
341
|
+
const nestedState = nestedEditor.parseEditorState(state);
|
|
342
|
+
nestedEditor.setEditorState(nestedState);
|
|
343
|
+
let nested = null;
|
|
344
|
+
nestedState.read(() => {
|
|
345
|
+
const root = $getRoot();
|
|
346
|
+
const headingSlugs = /* @__PURE__ */ new Map();
|
|
347
|
+
const ch = root.getChildren().map(
|
|
348
|
+
(child, i) => renderTree(
|
|
349
|
+
child,
|
|
350
|
+
nestedEditor,
|
|
351
|
+
nestedEditorConfig,
|
|
352
|
+
headingSlugs,
|
|
353
|
+
`nested-${i}`
|
|
354
|
+
)
|
|
355
|
+
);
|
|
356
|
+
nested = /* @__PURE__ */ jsx(Fragment, { children: ch });
|
|
357
|
+
});
|
|
358
|
+
return nested;
|
|
359
|
+
};
|
|
360
|
+
return { content, footnoteData, renderNestedContent };
|
|
361
|
+
}
|
|
362
|
+
function RichRenderer({
|
|
363
|
+
value,
|
|
364
|
+
variant = "article",
|
|
365
|
+
theme = "light",
|
|
366
|
+
className,
|
|
367
|
+
style,
|
|
368
|
+
as: Component = "div",
|
|
369
|
+
rendererConfig,
|
|
370
|
+
extraNodes
|
|
371
|
+
}) {
|
|
372
|
+
const variantClass = getVariantClass(variant);
|
|
373
|
+
const nodes = extraNodes ? [...allNodes, ...extraNodes] : allNodes;
|
|
374
|
+
const { content, footnoteData, renderNestedContent } = renderEditorToReact(
|
|
375
|
+
value,
|
|
376
|
+
nodes
|
|
377
|
+
);
|
|
378
|
+
const classes = ["rich-content", variantClass, className].filter(Boolean).join(" ");
|
|
379
|
+
return /* @__PURE__ */ jsx(PortalThemeProvider, { className: variantClass, theme, children: /* @__PURE__ */ jsx(ColorSchemeProvider, { colorScheme: theme, children: /* @__PURE__ */ jsx(
|
|
380
|
+
RendererConfigProvider,
|
|
381
|
+
{
|
|
382
|
+
config: rendererConfig,
|
|
383
|
+
mode: "renderer",
|
|
384
|
+
variant,
|
|
385
|
+
children: /* @__PURE__ */ jsx(
|
|
386
|
+
FootnoteDefinitionsProvider,
|
|
387
|
+
{
|
|
388
|
+
definitions: footnoteData.definitions,
|
|
389
|
+
displayNumberMap: footnoteData.displayNumberMap,
|
|
390
|
+
children: /* @__PURE__ */ jsx(NestedContentRendererProvider, { value: renderNestedContent, children: /* @__PURE__ */ jsx(Component, { className: classes, style, "data-theme": theme, children: content }) })
|
|
391
|
+
}
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
) }) });
|
|
395
|
+
}
|
|
396
|
+
export {
|
|
397
|
+
RichRenderer
|
|
398
|
+
};
|
|
@@ -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/preprocess/footnote.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEpD,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACzC;AAED,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,qBAAqB,GAC3B,YAAY,CAwCd"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headingSlug.d.ts","sourceRoot":"","sources":["../../src/preprocess/headingSlug.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #2563eb;--rc-quote-bg: #eff6ff;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: 700px;--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-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{--rc-text: #fafafa;--rc-text-secondary: #a1a1aa;--rc-text-tertiary: #71717a;--rc-text-quaternary: #52525b;--rc-bg: #09090b;--rc-bg-secondary: #18181b;--rc-bg-tertiary: #27272a;--rc-border: #27272a;--rc-accent: #60a5fa;--rc-accent-light: #60a5fa20;--rc-link: #60a5fa;--rc-code-text: #e4e4e7;--rc-code-bg: #27272a;--rc-hr-border: #27272a;--rc-quote-border: #60a5fa;--rc-quote-bg: #1e3a5f;--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-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-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}.km6fx0{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #2563eb;--rc-quote-bg: #eff6ff;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: 700px;--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-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}.km6fx1{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #2563eb;--rc-quote-bg: #eff6ff;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: 700px;--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-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}.km6fx2{--rc-text: #000;--rc-text-secondary: #27272a;--rc-text-tertiary: #71717a;--rc-text-quaternary: #a1a1aa;--rc-bg: #ffffff;--rc-bg-secondary: #fafafa;--rc-bg-tertiary: #f4f4f5;--rc-border: #f4f4f5;--rc-accent: #2563eb;--rc-accent-light: #2563eb20;--rc-link: #2563eb;--rc-code-text: #3f3f46;--rc-code-bg: #f4f4f5;--rc-hr-border: #e4e4e7;--rc-quote-border: #a1a1aa;--rc-quote-bg: #fafafa;--rc-alert-info: #006bb7;--rc-alert-warning: #cc5500;--rc-alert-tip: #11cc00;--rc-alert-caution: #cc0011;--rc-alert-important: #5500cc;--rc-max-width: none;--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-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: 8px}.dark .km6fx0,[data-theme=dark] .km6fx0,.dark.km6fx0,[data-theme=dark].km6fx0,.dark .km6fx1,[data-theme=dark] .km6fx1,.dark.km6fx1,[data-theme=dark].km6fx1,.dark .km6fx2,[data-theme=dark] .km6fx2,.dark.km6fx2,[data-theme=dark].km6fx2{--rc-text: #fafafa;--rc-text-secondary: #a1a1aa;--rc-text-tertiary: #71717a;--rc-text-quaternary: #52525b;--rc-bg: #09090b;--rc-bg-secondary: #18181b;--rc-bg-tertiary: #27272a;--rc-border: #27272a;--rc-accent: #60a5fa;--rc-accent-light: #60a5fa20;--rc-link: #60a5fa;--rc-code-text: #e4e4e7;--rc-code-bg: #27272a;--rc-hr-border: #27272a;--rc-quote-border: #60a5fa;--rc-quote-bg: #1e3a5f;--rc-alert-info: #7db9e5;--rc-alert-warning: #da864a;--rc-alert-tip: #54da48;--rc-alert-caution: #e16973;--rc-alert-important: #9966e0}._1v9yxw30{overflow-x:auto}._1v9yxw31{width:100%;caption-side:bottom;border-collapse:collapse;font-size:var(--rc-font-size-small)}._1v9yxw32{height:2.5rem;padding:0 var(--rc-space-lg);vertical-align:middle;font-weight:500;white-space:nowrap;color:var(--rc-text-secondary);line-height:1.5}._1v9yxw33{padding:var(--rc-space-lg);vertical-align:middle;line-height:1.5}._1v9yxw31 tr:has(._1v9yxw32){border-bottom:1px solid var(--rc-border)}._1v9yxw31 tr:has(._1v9yxw33):nth-child(2n){background-color:var(--rc-bg-secondary)}._1v9yxw31:has(tr:hover) tr:has(._1v9yxw33):nth-child(2n):not(:hover){background-color:transparent}._1v9yxw31 tr:has(._1v9yxw33){transition:background-color .15s}._1v9yxw31 tr:has(._1v9yxw33):hover{background-color:var(--rc-bg-tertiary)}._1v9yxw31 .rich-paragraph{margin:0;padding:0;line-height:inherit}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.css.d.ts","sourceRoot":"","sources":["../src/table.css.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,QAEvB,CAAA;AAEF,eAAO,MAAM,KAAK,QAKhB,CAAA;AAEF,eAAO,MAAM,SAAS,QAQpB,CAAA;AAEF,eAAO,MAAM,SAAS,QAIpB,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ColorScheme, RendererConfig, RichEditorVariant } from '@haklex/rich-editor/static';
|
|
2
|
+
import { Klass, LexicalNode, SerializedEditorState } from 'lexical';
|
|
3
|
+
import { CSSProperties } from 'react';
|
|
4
|
+
export interface RichRendererProps {
|
|
5
|
+
value: SerializedEditorState;
|
|
6
|
+
variant?: RichEditorVariant;
|
|
7
|
+
theme?: ColorScheme;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
as?: keyof React.JSX.IntrinsicElements;
|
|
11
|
+
rendererConfig?: RendererConfig;
|
|
12
|
+
extraNodes?: Array<Klass<LexicalNode>>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,iBAAiB,EAClB,MAAM,4BAA4B,CAAA;AACnC,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,qBAAqB,CAAA;IAC5B,OAAO,CAAC,EAAE,iBAAiB,CAAA;IAC3B,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAA;IACtC,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAA;CACvC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@haklex/rich-static-renderer",
|
|
3
|
+
"version": "0.0.38",
|
|
4
|
+
"description": "Headless SSR engine for Lexical rich content",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.mjs",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.mjs",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@lexical/headless": "^0.41.0",
|
|
19
|
+
"@haklex/rich-editor": "0.0.38",
|
|
20
|
+
"@haklex/rich-style-token": "0.0.38"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@lexical/code": "^0.41.0",
|
|
24
|
+
"@lexical/extension": "^0.41.0",
|
|
25
|
+
"@lexical/link": "^0.41.0",
|
|
26
|
+
"@lexical/list": "^0.41.0",
|
|
27
|
+
"@lexical/rich-text": "^0.41.0",
|
|
28
|
+
"@lexical/table": "^0.41.0",
|
|
29
|
+
"@types/react": "^19.2.14",
|
|
30
|
+
"@vanilla-extract/css": "^1.18.0",
|
|
31
|
+
"@vanilla-extract/vite-plugin": "^4.0.20",
|
|
32
|
+
"lexical": "^0.41.0",
|
|
33
|
+
"markdown-to-jsx": "npm:@innei/markdown-to-jsx-yet@7.7.7-11",
|
|
34
|
+
"react": "^19.2.4",
|
|
35
|
+
"react-dom": "^19.2.4",
|
|
36
|
+
"typescript": "^5.9.3",
|
|
37
|
+
"vite": "^7.3.1",
|
|
38
|
+
"vite-plugin-dts": "^4.5.4"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"@lexical/code": "^0.41.0",
|
|
42
|
+
"@lexical/extension": "^0.41.0",
|
|
43
|
+
"@lexical/link": "^0.41.0",
|
|
44
|
+
"@lexical/list": "^0.41.0",
|
|
45
|
+
"@lexical/rich-text": "^0.41.0",
|
|
46
|
+
"@lexical/table": "^0.41.0",
|
|
47
|
+
"lexical": "^0.41.0",
|
|
48
|
+
"react": ">=19",
|
|
49
|
+
"react-dom": ">=19"
|
|
50
|
+
},
|
|
51
|
+
"publishConfig": {
|
|
52
|
+
"access": "public"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"bench": "node benchmark/build-and-run.mjs",
|
|
56
|
+
"build": "vite build"
|
|
57
|
+
},
|
|
58
|
+
"types": "./dist/index.d.ts"
|
|
59
|
+
}
|