remons-markdown-editor 1.0.0-beta.2 → 1.0.0-beta.4

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Toolbar/renderers/TablePicker/index.module.less","../src/App.css"],"sourcesContent":[".container {\n padding: 4px;\n display: block;\n min-width: 200px;\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n.grid {\n display: grid;\n gap: 2px;\n transition: all 0.1s ease;\n justify-content: flex-start;\n}\n.grid .cell {\n width: 24px;\n height: 24px;\n border: 1px solid #e8e8e8;\n border-radius: 2px;\n background: transparent;\n cursor: pointer;\n transition: all 0.1s ease;\n}\n.grid .cell.cellActive {\n border-color: #91caff;\n background: #ddf4ff;\n}\n.hint {\n padding: 12px 16px;\n color: #999;\n font-size: 12px;\n text-align: center;\n cursor: pointer;\n}\n.label {\n margin-top: 8px;\n font-size: 13px;\n color: #666;\n font-weight: 500;\n min-height: 20px;\n text-align: center;\n}\n","@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&display=swap');\n\n\n.app {\n height: 100vh;\n display: flex;\n flex-direction: column;\n}\n\n.app.fullscreen {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 9999;\n background: #fff;\n width: 100vw;\n height: 100vh;\n}\n\n.toolbar {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n padding: 4px 8px;\n background: #f6f8fa;\n border-bottom: 1px solid #d0d7de;\n gap: 4px;\n overflow-x: auto;\n}\n\n.toolbar-group {\n display: flex;\n align-items: center;\n gap: 2px;\n}\n\n.toolbar-button {\n display: flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n height: 32px;\n padding: 0 8px;\n border: none;\n border-radius: 6px;\n background: transparent;\n cursor: pointer;\n font-size: 16px;\n font-weight: 500;\n color: #24292f;\n transition: background-color 0.15s, color 0.15s;\n white-space: nowrap;\n}\n\n.toolbar-button:hover {\n background: #e1e4e8;\n color: #0969da;\n}\n\n.toolbar-button:active {\n background: #d0d7de;\n}\n\n.toolbar-button.ant-btn {\n min-width: 32px;\n height: 32px;\n padding: 0 8px;\n border-color: transparent !important;\n box-shadow: none !important;\n}\n\n.toolbar-button.ant-btn:hover {\n background: #e1e4e8;\n color: #0969da;\n border-color: transparent !important;\n box-shadow: none !important;\n}\n\n.toolbar-button.ant-btn:active {\n border-color: transparent !important;\n box-shadow: none !important;\n}\n\n:where(.css-dev-only-do-not-override-u6izyw).ant-btn:not(:disabled):not(.ant-btn-disabled):hover {\n border: none !important\n}\n\n.toolbar-separator {\n width: 1px;\n height: 24px;\n background: #d0d7de;\n margin: 0 4px;\n}\n\n.split-panels {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n}\n\n.split-panels .ant-splitter {\n height: 100%;\n}\n\n.split-panels .ant-splitter-panel {\n min-height: 0;\n}\n\n.editor {\n height: 100%;\n \n}\n\n.cm-scroller {\n font-family: Consolas,Inter,Noto Sans SC,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Microsoft YaHei,sans-serif !important;\n}\n\n.cm-editor {\n height: 100%;\n}\n\n.preview {\n height: 100%;\n overflow: auto;\n}\n\n\n/* 通用容器基类 */\n.md-container {\n margin: 16px 0;\n border-radius: 6px;\n border: 1px solid #d0d7de;\n overflow: hidden;\n}\n\n/* 链接卡片 */\n.link-card {\n background: #f6f8fa;\n}\n\n.link-card-content {\n padding: 16px;\n}\n\n.link-card-title {\n margin: 0 0 4px;\n font-size: 16px;\n font-weight: 600;\n}\n\n.link-card-title a {\n color: #0969da;\n text-decoration: none;\n}\n\n.link-card-title a:hover {\n text-decoration: underline;\n}\n\n.link-card-desc {\n margin: 0;\n font-size: 14px;\n color: #57606a;\n line-height: 1.5;\n}\n\n.link-card-primary {\n background: #ddf4ff;\n border-color: #54aeff;\n}\n\n.link-card-primary .link-card-title a {\n color: #0550ae;\n}\n\n.link-card-warning {\n background: #fff8c5;\n border-color: #d4a72c;\n}\n\n.link-card-warning .link-card-title a {\n color: #7d4e00;\n}\n\n/* 注释组件 */\n.note {\n padding: 12px 16px;\n}\n\n.note-info {\n background: #ddf4ff;\n border-color: #54aeff;\n}\n\n.note-tip {\n background: #dafbe1;\n border-color: #4ac26b;\n}\n\n.note-warning {\n background: #fff8c5;\n border-color: #d4a72c;\n}\n\n.note-danger {\n background: #ffebe9;\n border-color: #fb857b;\n}\n\n.note-title {\n margin: 0 0 4px;\n font-size: 14px;\n font-weight: 600;\n}\n\n.note-text {\n font-size: 14px;\n line-height: 1.5;\n}\n\n/* 编辑弹窗样式 */\n.edit-dialog {\n padding: 8px 0;\n}\n\n.edit-dialog-field {\n margin-bottom: 16px;\n}\n\n.edit-dialog-label {\n display: block;\n margin-bottom: 6px;\n font-size: 14px;\n font-weight: 500;\n color: #24292f;\n}\n\n.edit-dialog-input {\n width: 100%;\n padding: 6px 10px;\n font-size: 14px;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n outline: none;\n transition: border-color 0.15s;\n}\n\n.edit-dialog-input:focus {\n border-color: #0969da;\n box-shadow: 0 0 0 3px rgba(9, 105, 218, 0.1);\n}\n\n.edit-dialog-textarea {\n resize: vertical;\n font-family: inherit;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/components/Toolbar/renderers/TablePicker/index.module.less"],"sourcesContent":[".container {\n padding: 4px;\n display: block;\n min-width: 200px;\n background: #fff;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n}\n.grid {\n display: grid;\n gap: 2px;\n transition: all 0.1s ease;\n justify-content: flex-start;\n}\n.grid .cell {\n width: 24px;\n height: 24px;\n border: 1px solid #e8e8e8;\n border-radius: 2px;\n background: transparent;\n cursor: pointer;\n transition: all 0.1s ease;\n}\n.grid .cell.cellActive {\n border-color: #91caff;\n background: #ddf4ff;\n}\n.hint {\n padding: 12px 16px;\n color: #999;\n font-size: 12px;\n text-align: center;\n cursor: pointer;\n}\n.label {\n margin-top: 8px;\n font-size: 13px;\n color: #666;\n font-weight: 500;\n min-height: 20px;\n text-align: center;\n}\n"],"mappings":";AAAA,CAAC;AACC,WAAS;AACT,WAAS;AACT,aAAW;AACX,cAAY;AACZ,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY,EAAE,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AACvC;AACA,CAAC;AACC,WAAS;AACT,OAAK;AACL,cAAY,IAAI,KAAK;AACrB,mBAAiB;AACnB;AACA,CANC,KAMK,CAAC;AACL,SAAO;AACP,UAAQ;AACR,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,UAAQ;AACR,cAAY,IAAI,KAAK;AACvB;AACA,CAfC,KAeK,CATC,IASI,CAAC;AACV,gBAAc;AACd,cAAY;AACd;AACA,CAAC;AACC,WAAS,KAAK;AACd,SAAO;AACP,aAAW;AACX,cAAY;AACZ,UAAQ;AACV;AACA,CAAC;AACC,cAAY;AACZ,aAAW;AACX,SAAO;AACP,eAAa;AACb,cAAY;AACZ,cAAY;AACd;","names":[]}
package/dist/index.d.cts CHANGED
@@ -2,23 +2,7 @@ import * as React from 'react';
2
2
  import React__default from 'react';
3
3
  import { EditorView } from '@codemirror/view';
4
4
  import { EditorState } from '@codemirror/state';
5
-
6
- interface MarkdownEditorRef {
7
- getContent: () => string;
8
- }
9
- interface MarkdownEditorProps {
10
- /** 初始内容 */
11
- defaultValue?: string;
12
- /** 受控内容 */
13
- value?: string;
14
- /** 内容变化回调 */
15
- onChange?: (value: string) => void;
16
- /** 是否显示预览面板 */
17
- showPreview?: boolean;
18
- /** 是否支持全屏 */
19
- fullscreen?: boolean;
20
- }
21
- declare const _default: React.ForwardRefExoticComponent<MarkdownEditorProps & React.RefAttributes<MarkdownEditorRef>>;
5
+ import { RenderMarkdownProps } from 'remons-render-markdown';
22
6
 
23
7
  interface ToolbarButtonConfig {
24
8
  id?: string;
@@ -28,6 +12,8 @@ interface ToolbarButtonConfig {
28
12
  handler?: (view: EditorView, state: EditorState) => void;
29
13
  separatorBefore?: boolean;
30
14
  customRender?: () => React__default.ReactNode;
15
+ wrapTags?: [string, string];
16
+ disabled?: boolean;
31
17
  }
32
18
  /**
33
19
  * 弹窗属性配置
@@ -42,6 +28,7 @@ interface DialogField {
42
28
  /**
43
29
  * 组件 Schema
44
30
  * 每个容器组件(如 :::linkCard)定义可编辑字段和弹窗渲染逻辑
31
+ * 也支持简单的标签包裹模式(通过 wrapTags)
45
32
  */
46
33
  interface ComponentSchema {
47
34
  /** 容器名称,对应 :::name 语法 */
@@ -50,24 +37,83 @@ interface ComponentSchema {
50
37
  label: string;
51
38
  /** 工具栏按钮显示的图标 */
52
39
  icon?: React__default.ReactNode;
53
- /** 弹窗属性配置 — 用于定义 Markdown 内容中需要填充的字段 */
54
- fields: DialogField[];
55
40
  /**
56
- * 弹窗内容渲染函数(必填)
41
+ * 标签包裹配置:设置为 [openTag, closeTag] 时,使用标签包裹模式(而非 :::name 容器)
42
+ * 配置后无需提供 fields 和 renderDialog
43
+ */
44
+ wrapTags?: [string, string];
45
+ /** 弹窗属性配置 — 用于定义 Markdown 内容中需要填充的字段(wrapTags 模式下可选) */
46
+ fields?: DialogField[];
47
+ /**
48
+ * 弹窗内容渲染函数(wrapTags 模式下可选)
57
49
  * 接收当前属性值和回调函数,由用户完全自定义弹窗内容的渲染
58
50
  * @param props 当前属性值,用于回显
59
51
  * @param onChange 属性变更回调,用于更新表单值
60
52
  * @returns 弹窗内容的 ReactNode
61
53
  */
62
- renderDialog: (props: Record<string, string>, onChange: (key: string, value: string) => void) => React__default.ReactNode;
54
+ renderDialog?: (props: Record<string, string>, onChange: (key: string, value: string) => void) => React__default.ReactNode;
55
+ }
56
+ /**
57
+ * 图片上传配置
58
+ */
59
+ interface ImageUploadConfig {
60
+ /**
61
+ * 图片上传接口地址
62
+ * 需与 onUploadImage 二选一(优先级低于 onUploadImage)
63
+ */
64
+ uploadUrl?: string;
65
+ /**
66
+ * 自定义上传函数(优先级高于 uploadUrl)
67
+ * 传入此函数时,将完全接管上传逻辑
68
+ * @param file 要上传的图片文件
69
+ * @returns Promise<string> - 返回图片 URL,失败返回 null
70
+ */
71
+ onUploadImage?: (file: File) => Promise<string | null>;
72
+ /**
73
+ * 处理服务器返回结果的回调,允许转换 URL
74
+ * 当使用 uploadUrl 方式上传时,可以使用此回调来自定义处理响应数据
75
+ * @param result 服务器返回的原始响应数据
76
+ * @returns 图片 URL,如果返回 null 则上传失败
77
+ */
78
+ onGetUploadUrl?: (result: any) => string | null;
63
79
  }
64
80
 
81
+ type PreviewOptions = Omit<RenderMarkdownProps, 'content'> & {
82
+ languages?: Record<string, any> | null | undefined;
83
+ };
84
+
85
+ interface MarkdownEditorRef {
86
+ getContent: () => string;
87
+ }
88
+ interface MarkdownEditorProps {
89
+ /** 初始内容 */
90
+ defaultValue?: string;
91
+ /** 受控内容 */
92
+ value?: string;
93
+ /** 内容变化回调 */
94
+ onChange?: (value: string) => void;
95
+ /** 是否显示预览面板 */
96
+ showPreview?: boolean;
97
+ /** 是否支持全屏 */
98
+ fullscreen?: boolean;
99
+ /** Preview 渲染配置 */
100
+ previewOptions?: PreviewOptions;
101
+ /** 图片上传配置 */
102
+ uploadConfig?: ImageUploadConfig;
103
+ }
104
+ declare const _default: React.ForwardRefExoticComponent<MarkdownEditorProps & React.RefAttributes<MarkdownEditorRef>>;
105
+
65
106
  /**
66
107
  * 注册自定义容器组件到工具栏。支持单个或批量注册。
67
- * 支持 linkCard 形式的 schema(name + fields + renderDialog)。
68
- * fields 定义 Markdown 属性字段,renderDialog 定义弹窗内容。
108
+ * 支持两种模式:
109
+ *
110
+ * 1. 容器模式(linkCard):name + fields + renderDialog
111
+ * 插入 :::name 格式的容器,支持弹窗编辑属性
112
+ *
113
+ * 2. 标签包裹模式:name + wrapTags
114
+ * 插入简单的标签包裹文本,如 <plugin-container>...</plugin-container>
69
115
  *
70
- * @example 单个注册
116
+ * @example 容器模式
71
117
  * ```tsx
72
118
  * const schema: ComponentSchema = {
73
119
  * name: 'alert',
@@ -85,6 +131,19 @@ interface ComponentSchema {
85
131
  * }
86
132
  * ```
87
133
  *
134
+ * @example 标签包裹模式
135
+ * ```tsx
136
+ * function MyPage() {
137
+ * useRegisterToolbar({
138
+ * name: 'plugin-container',
139
+ * label: '自定义容器',
140
+ * icon: <AlertOutlined />,
141
+ * wrapTags: ['<plugin-container>', '</plugin-container>'],
142
+ * })
143
+ * return <MarkdownEditor />
144
+ * }
145
+ * ```
146
+ *
88
147
  * @example 批量注册
89
148
  * ```tsx
90
149
  * function MyPage() {
@@ -95,4 +154,4 @@ interface ComponentSchema {
95
154
  */
96
155
  declare function useRegisterToolbar(schemas: ComponentSchema | ComponentSchema[]): void;
97
156
 
98
- export { type ComponentSchema, type DialogField, _default as MarkdownEditor, type MarkdownEditorProps, type MarkdownEditorRef, type ToolbarButtonConfig, useRegisterToolbar };
157
+ export { type ComponentSchema, type DialogField, type ImageUploadConfig, _default as MarkdownEditor, type MarkdownEditorProps, type MarkdownEditorRef, type PreviewOptions, type ToolbarButtonConfig, useRegisterToolbar };
package/dist/index.d.ts CHANGED
@@ -2,23 +2,7 @@ import * as React from 'react';
2
2
  import React__default from 'react';
3
3
  import { EditorView } from '@codemirror/view';
4
4
  import { EditorState } from '@codemirror/state';
5
-
6
- interface MarkdownEditorRef {
7
- getContent: () => string;
8
- }
9
- interface MarkdownEditorProps {
10
- /** 初始内容 */
11
- defaultValue?: string;
12
- /** 受控内容 */
13
- value?: string;
14
- /** 内容变化回调 */
15
- onChange?: (value: string) => void;
16
- /** 是否显示预览面板 */
17
- showPreview?: boolean;
18
- /** 是否支持全屏 */
19
- fullscreen?: boolean;
20
- }
21
- declare const _default: React.ForwardRefExoticComponent<MarkdownEditorProps & React.RefAttributes<MarkdownEditorRef>>;
5
+ import { RenderMarkdownProps } from 'remons-render-markdown';
22
6
 
23
7
  interface ToolbarButtonConfig {
24
8
  id?: string;
@@ -28,6 +12,8 @@ interface ToolbarButtonConfig {
28
12
  handler?: (view: EditorView, state: EditorState) => void;
29
13
  separatorBefore?: boolean;
30
14
  customRender?: () => React__default.ReactNode;
15
+ wrapTags?: [string, string];
16
+ disabled?: boolean;
31
17
  }
32
18
  /**
33
19
  * 弹窗属性配置
@@ -42,6 +28,7 @@ interface DialogField {
42
28
  /**
43
29
  * 组件 Schema
44
30
  * 每个容器组件(如 :::linkCard)定义可编辑字段和弹窗渲染逻辑
31
+ * 也支持简单的标签包裹模式(通过 wrapTags)
45
32
  */
46
33
  interface ComponentSchema {
47
34
  /** 容器名称,对应 :::name 语法 */
@@ -50,24 +37,83 @@ interface ComponentSchema {
50
37
  label: string;
51
38
  /** 工具栏按钮显示的图标 */
52
39
  icon?: React__default.ReactNode;
53
- /** 弹窗属性配置 — 用于定义 Markdown 内容中需要填充的字段 */
54
- fields: DialogField[];
55
40
  /**
56
- * 弹窗内容渲染函数(必填)
41
+ * 标签包裹配置:设置为 [openTag, closeTag] 时,使用标签包裹模式(而非 :::name 容器)
42
+ * 配置后无需提供 fields 和 renderDialog
43
+ */
44
+ wrapTags?: [string, string];
45
+ /** 弹窗属性配置 — 用于定义 Markdown 内容中需要填充的字段(wrapTags 模式下可选) */
46
+ fields?: DialogField[];
47
+ /**
48
+ * 弹窗内容渲染函数(wrapTags 模式下可选)
57
49
  * 接收当前属性值和回调函数,由用户完全自定义弹窗内容的渲染
58
50
  * @param props 当前属性值,用于回显
59
51
  * @param onChange 属性变更回调,用于更新表单值
60
52
  * @returns 弹窗内容的 ReactNode
61
53
  */
62
- renderDialog: (props: Record<string, string>, onChange: (key: string, value: string) => void) => React__default.ReactNode;
54
+ renderDialog?: (props: Record<string, string>, onChange: (key: string, value: string) => void) => React__default.ReactNode;
55
+ }
56
+ /**
57
+ * 图片上传配置
58
+ */
59
+ interface ImageUploadConfig {
60
+ /**
61
+ * 图片上传接口地址
62
+ * 需与 onUploadImage 二选一(优先级低于 onUploadImage)
63
+ */
64
+ uploadUrl?: string;
65
+ /**
66
+ * 自定义上传函数(优先级高于 uploadUrl)
67
+ * 传入此函数时,将完全接管上传逻辑
68
+ * @param file 要上传的图片文件
69
+ * @returns Promise<string> - 返回图片 URL,失败返回 null
70
+ */
71
+ onUploadImage?: (file: File) => Promise<string | null>;
72
+ /**
73
+ * 处理服务器返回结果的回调,允许转换 URL
74
+ * 当使用 uploadUrl 方式上传时,可以使用此回调来自定义处理响应数据
75
+ * @param result 服务器返回的原始响应数据
76
+ * @returns 图片 URL,如果返回 null 则上传失败
77
+ */
78
+ onGetUploadUrl?: (result: any) => string | null;
63
79
  }
64
80
 
81
+ type PreviewOptions = Omit<RenderMarkdownProps, 'content'> & {
82
+ languages?: Record<string, any> | null | undefined;
83
+ };
84
+
85
+ interface MarkdownEditorRef {
86
+ getContent: () => string;
87
+ }
88
+ interface MarkdownEditorProps {
89
+ /** 初始内容 */
90
+ defaultValue?: string;
91
+ /** 受控内容 */
92
+ value?: string;
93
+ /** 内容变化回调 */
94
+ onChange?: (value: string) => void;
95
+ /** 是否显示预览面板 */
96
+ showPreview?: boolean;
97
+ /** 是否支持全屏 */
98
+ fullscreen?: boolean;
99
+ /** Preview 渲染配置 */
100
+ previewOptions?: PreviewOptions;
101
+ /** 图片上传配置 */
102
+ uploadConfig?: ImageUploadConfig;
103
+ }
104
+ declare const _default: React.ForwardRefExoticComponent<MarkdownEditorProps & React.RefAttributes<MarkdownEditorRef>>;
105
+
65
106
  /**
66
107
  * 注册自定义容器组件到工具栏。支持单个或批量注册。
67
- * 支持 linkCard 形式的 schema(name + fields + renderDialog)。
68
- * fields 定义 Markdown 属性字段,renderDialog 定义弹窗内容。
108
+ * 支持两种模式:
109
+ *
110
+ * 1. 容器模式(linkCard):name + fields + renderDialog
111
+ * 插入 :::name 格式的容器,支持弹窗编辑属性
112
+ *
113
+ * 2. 标签包裹模式:name + wrapTags
114
+ * 插入简单的标签包裹文本,如 <plugin-container>...</plugin-container>
69
115
  *
70
- * @example 单个注册
116
+ * @example 容器模式
71
117
  * ```tsx
72
118
  * const schema: ComponentSchema = {
73
119
  * name: 'alert',
@@ -85,6 +131,19 @@ interface ComponentSchema {
85
131
  * }
86
132
  * ```
87
133
  *
134
+ * @example 标签包裹模式
135
+ * ```tsx
136
+ * function MyPage() {
137
+ * useRegisterToolbar({
138
+ * name: 'plugin-container',
139
+ * label: '自定义容器',
140
+ * icon: <AlertOutlined />,
141
+ * wrapTags: ['<plugin-container>', '</plugin-container>'],
142
+ * })
143
+ * return <MarkdownEditor />
144
+ * }
145
+ * ```
146
+ *
88
147
  * @example 批量注册
89
148
  * ```tsx
90
149
  * function MyPage() {
@@ -95,4 +154,4 @@ interface ComponentSchema {
95
154
  */
96
155
  declare function useRegisterToolbar(schemas: ComponentSchema | ComponentSchema[]): void;
97
156
 
98
- export { type ComponentSchema, type DialogField, _default as MarkdownEditor, type MarkdownEditorProps, type MarkdownEditorRef, type ToolbarButtonConfig, useRegisterToolbar };
157
+ export { type ComponentSchema, type DialogField, type ImageUploadConfig, _default as MarkdownEditor, type MarkdownEditorProps, type MarkdownEditorRef, type PreviewOptions, type ToolbarButtonConfig, useRegisterToolbar };