@cgboiler/biz-basic 1.0.48 → 1.0.50

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/es/index.d.ts CHANGED
@@ -5,6 +5,6 @@ declare namespace _default {
5
5
  }
6
6
  export default _default;
7
7
  export function install(app: any): void;
8
- export const version: "1.0.47";
8
+ export const version: "1.0.49";
9
9
  import RichTextEditor from './rich-text-editor';
10
10
  export { RichTextEditor };
package/es/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import RichTextEditor from "./rich-text-editor";
2
- const version = "1.0.47";
2
+ const version = "1.0.49";
3
3
  function install(app) {
4
4
  const components = [
5
5
  RichTextEditor
@@ -16,7 +16,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
16
16
  type: BooleanConstructor;
17
17
  default: boolean;
18
18
  };
19
- }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked")[], "blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
19
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked" | "customContent-triggered" | "customContent-input" | "customContent-exit" | "customContent-clicked")[], "blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked" | "customContent-triggered" | "customContent-input" | "customContent-exit" | "customContent-clicked", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
20
20
  modelValue: {
21
21
  type: StringConstructor;
22
22
  default: string;
@@ -44,6 +44,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
44
44
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
45
45
  "onMention-clicked"?: ((...args: any[]) => any) | undefined;
46
46
  "onHashTag-clicked"?: ((...args: any[]) => any) | undefined;
47
+ "onCustomContent-triggered"?: ((...args: any[]) => any) | undefined;
48
+ "onCustomContent-input"?: ((...args: any[]) => any) | undefined;
49
+ "onCustomContent-exit"?: ((...args: any[]) => any) | undefined;
50
+ "onCustomContent-clicked"?: ((...args: any[]) => any) | undefined;
47
51
  }>, {
48
52
  modelValue: string;
49
53
  placeholder: string;
@@ -31,7 +31,7 @@ import "./index.css";
31
31
  var stdin_default = defineComponent({
32
32
  name: "RichTextEditor",
33
33
  props: richTextEditorProps,
34
- emits: ["update:modelValue", "mention-triggered", "mention-input", "mention-exit", "mention-clicked", "hashTag-triggered", "hashTag-input", "hashTag-exit", "hashTag-clicked", "blur", "focus"],
34
+ emits: ["update:modelValue", "mention-triggered", "mention-input", "mention-exit", "mention-clicked", "hashTag-triggered", "hashTag-input", "hashTag-exit", "hashTag-clicked", "customContent-triggered", "customContent-input", "customContent-exit", "customContent-clicked", "blur", "focus"],
35
35
  setup(props, {
36
36
  emit,
37
37
  expose
@@ -99,10 +99,23 @@ var stdin_default = defineComponent({
99
99
  }
100
100
  });
101
101
  };
102
+ const insertCustomContent = (data) => {
103
+ editor.value.commands.insertContent({
104
+ type: "customContent",
105
+ attrs: {
106
+ id: data.id || `custom-${Date.now()}`,
107
+ label: data.label,
108
+ obj: data.obj,
109
+ color: data.color,
110
+ hoverColor: data.hoverColor
111
+ }
112
+ });
113
+ };
102
114
  expose({
103
115
  getEditor: () => editor.value,
104
116
  insertMention,
105
- insertHashTag
117
+ insertHashTag,
118
+ insertCustomContent
106
119
  });
107
120
  watch(() => props.modelValue, (newValue) => {
108
121
  var _a, _b;
@@ -185,6 +198,26 @@ var stdin_default = defineComponent({
185
198
  return;
186
199
  }
187
200
  };
201
+ const customContentClickHandler = (event) => {
202
+ const target = event.target;
203
+ const tagEl = target.closest(".custom-content") || null;
204
+ if (tagEl) {
205
+ const objStr = tagEl.getAttribute("obj") || "{}";
206
+ const label = tagEl.getAttribute("file-label") || "";
207
+ try {
208
+ const obj = JSON.parse(objStr);
209
+ emit("customContent-clicked", {
210
+ obj,
211
+ label
212
+ });
213
+ } catch (e) {
214
+ console.error("Failed to parse custom content obj:", e);
215
+ }
216
+ event.stopPropagation();
217
+ event.preventDefault();
218
+ return;
219
+ }
220
+ };
188
221
  const HISTORY_METADATA_KEY = "rich_text_editor_history_metadata";
189
222
  const MAX_HISTORY_ITEMS = 10;
190
223
  let saveTimeoutId = null;
@@ -238,6 +271,7 @@ var stdin_default = defineComponent({
238
271
  editorElement.addEventListener("click", imageClickHandler);
239
272
  editorElement.addEventListener("click", hashTagClickHandler);
240
273
  editorElement.addEventListener("click", mentionClickHandler);
274
+ editorElement.addEventListener("click", customContentClickHandler);
241
275
  }
242
276
  });
243
277
  });
@@ -251,6 +285,7 @@ var stdin_default = defineComponent({
251
285
  editorElement.removeEventListener("click", imageClickHandler);
252
286
  editorElement.removeEventListener("click", hashTagClickHandler);
253
287
  editorElement.removeEventListener("click", mentionClickHandler);
288
+ editorElement.removeEventListener("click", customContentClickHandler);
254
289
  }
255
290
  (_c = editor.value) == null ? void 0 : _c.destroy();
256
291
  });
@@ -1 +1 @@
1
- body .ProseMirror{flex:1;overflow:auto;outline:none;line-height:1.6;font-size:var(--font-base);--white: #fff;--black: #2e2b29;--gray-1: rgba(61, 37, 20, .05);--gray-2: rgba(61, 37, 20, .08);--gray-3: rgba(61, 37, 20, .12);--gray-4: rgba(53, 38, 28, .3);--gray-5: rgba(28, 25, 23, .6);--green: #22c55e;--purple: #6a00f5;--purple-contrast: #5800cc;--purple-light: rgba(88, 5, 255, .05);--yellow-contrast: #facc15;--yellow: rgba(250, 204, 21, .4);--yellow-light: #fffae5;--red: #ff5c33;--red-light: #ffebe5;--shadow: 0px 12px 33px 0px rgba(0, 0, 0, .06), 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04)}body .ProseMirror :first-child{margin-top:0}body .ProseMirror video{width:100%}body .ProseMirror ol{list-style:auto}body .ProseMirror ol ol,body .ProseMirror ul{list-style:disc}body .ProseMirror ol,body .ProseMirror ul{padding-left:1.5em;margin:0 0 12px}body .ProseMirror ol li p,body .ProseMirror ul li p{margin-top:.25em;margin-bottom:.25em}body .ProseMirror li::marker{text-align:start!important}body .ProseMirror h1,body .ProseMirror h2,body .ProseMirror h3,body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{line-height:1.1;margin-top:2.5rem;text-wrap:pretty}body .ProseMirror h1,body .ProseMirror h2{margin-top:1rem;margin-bottom:1rem}body .ProseMirror h1{font-size:1.4rem}body .ProseMirror h2{font-size:1.2rem}body .ProseMirror h3{font-size:1.1rem}body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{font-size:1rem}body .ProseMirror a,body .ProseMirror .editor-link{color:var(--purple);text-decoration:underline;cursor:pointer;transition:color .2s ease}body .ProseMirror a:hover,body .ProseMirror .editor-link:hover{color:var(--purple-contrast);text-decoration:underline}body .ProseMirror code{background-color:#ffe5e8;border-radius:.4rem;color:#c02537;padding:2px 4px}body .ProseMirror pre{border-radius:.5rem;font-family:JetBrainsMono,monospace;margin:1.5rem 0;padding:.75rem 1rem}body .ProseMirror pre code{background:none;color:inherit;font-size:.8rem;padding:0}body .ProseMirror blockquote{border-left:3px solid var(--gray-3);margin:1.5rem 0;padding-left:1rem}body .ProseMirror hr{border:none;border-top:1px solid var(--gray-2);margin:2rem 0}body .ProseMirror p.is-editor-empty:first-child:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror .is-empty:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror table{border-collapse:collapse;margin:0;overflow:hidden;table-layout:fixed;width:100%}body .ProseMirror table td,body .ProseMirror table th{border:1px solid var(--gray-3);box-sizing:border-box;min-width:1em;padding:6px 8px;position:relative;vertical-align:top}body .ProseMirror table td>*,body .ProseMirror table th>*{margin-bottom:0}body .ProseMirror table th{background-color:var(--gray-1);font-weight:700;text-align:left}body .ProseMirror table .selectedCell:after{background:var(--gray-2);content:"";left:0;right:0;top:0;bottom:0;pointer-events:none;position:absolute;z-index:2}body .ProseMirror table .column-resize-handle{background-color:var(--purple);bottom:-2px;pointer-events:none;position:absolute;right:-2px;top:0;width:4px}body .ProseMirror .tableWrapper{margin:1.5rem 0;overflow-x:auto}body .ProseMirror.resize-cursor{cursor:ew-resize;cursor:col-resize}body .ProseMirror img{max-width:100%}body .ProseMirror .mention,body .ProseMirror .hash-tag{color:#c02537;padding:0 .3em}.animation-indent--right{animation:indent-right .5s cubic-bezier(.68,-.55,.27,1.55) 1 alternate-reverse}@keyframes indent-right{0%{transform:translate(0)}to{transform:translate(12px)}}
1
+ body .ProseMirror{flex:1;overflow:auto;outline:none;line-height:1.6;font-size:var(--font-base);--white: #fff;--black: #2e2b29;--gray-1: rgba(61, 37, 20, .05);--gray-2: rgba(61, 37, 20, .08);--gray-3: rgba(61, 37, 20, .12);--gray-4: rgba(53, 38, 28, .3);--gray-5: rgba(28, 25, 23, .6);--green: #22c55e;--purple: #6a00f5;--purple-contrast: #5800cc;--purple-light: rgba(88, 5, 255, .05);--yellow-contrast: #facc15;--yellow: rgba(250, 204, 21, .4);--yellow-light: #fffae5;--red: #ff5c33;--red-light: #ffebe5;--shadow: 0px 12px 33px 0px rgba(0, 0, 0, .06), 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04)}body .ProseMirror :first-child{margin-top:0}body .ProseMirror video{width:100%}body .ProseMirror ol{list-style:auto}body .ProseMirror ol ol,body .ProseMirror ul{list-style:disc}body .ProseMirror ol,body .ProseMirror ul{padding-left:1.5em;margin:0 0 12px}body .ProseMirror ol li p,body .ProseMirror ul li p{margin-top:.25em;margin-bottom:.25em}body .ProseMirror li::marker{text-align:start!important}body .ProseMirror h1,body .ProseMirror h2,body .ProseMirror h3,body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{line-height:1.1;margin-top:2.5rem;text-wrap:pretty}body .ProseMirror h1,body .ProseMirror h2{margin-top:1rem;margin-bottom:1rem}body .ProseMirror h1{font-size:1.4rem}body .ProseMirror h2{font-size:1.2rem}body .ProseMirror h3{font-size:1.1rem}body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{font-size:1rem}body .ProseMirror a,body .ProseMirror .editor-link{color:var(--purple);text-decoration:underline;cursor:pointer;transition:color .2s ease}body .ProseMirror a:hover,body .ProseMirror .editor-link:hover{color:var(--purple-contrast);text-decoration:underline}body .ProseMirror code{background-color:#ffe5e8;border-radius:.4rem;color:#c02537;padding:2px 4px}body .ProseMirror pre{border-radius:.5rem;font-family:JetBrainsMono,monospace;margin:1.5rem 0;padding:.75rem 1rem}body .ProseMirror pre code{background:none;color:inherit;font-size:.8rem;padding:0}body .ProseMirror blockquote{border-left:3px solid var(--gray-3);margin:1.5rem 0;padding-left:1rem}body .ProseMirror hr{border:none;border-top:1px solid var(--gray-2);margin:2rem 0}body .ProseMirror p.is-editor-empty:first-child:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror .is-empty:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror table{border-collapse:collapse;margin:0;overflow:hidden;table-layout:fixed;width:100%}body .ProseMirror table td,body .ProseMirror table th{border:1px solid var(--gray-3);box-sizing:border-box;min-width:1em;padding:6px 8px;position:relative;vertical-align:top}body .ProseMirror table td>*,body .ProseMirror table th>*{margin-bottom:0}body .ProseMirror table th{background-color:var(--gray-1);font-weight:700;text-align:left}body .ProseMirror table .selectedCell:after{background:var(--gray-2);content:"";left:0;right:0;top:0;bottom:0;pointer-events:none;position:absolute;z-index:2}body .ProseMirror table .column-resize-handle{background-color:var(--purple);bottom:-2px;pointer-events:none;position:absolute;right:-2px;top:0;width:4px}body .ProseMirror .tableWrapper{margin:1.5rem 0;overflow-x:auto}body .ProseMirror.resize-cursor{cursor:ew-resize;cursor:col-resize}body .ProseMirror img{max-width:100%}body .ProseMirror .mention,body .ProseMirror .hash-tag{color:#c02537;padding:0 .3em}body .ProseMirror .custom-content{color:var(--custom-content-color, #000);padding:0 .3em;cursor:pointer;transition:color .2s ease}body .ProseMirror .custom-content:hover{color:var(--custom-content-hover-color, #c02537)}.animation-indent--right{animation:indent-right .5s cubic-bezier(.68,-.55,.27,1.55) 1 alternate-reverse}@keyframes indent-right{0%{transform:translate(0)}to{transform:translate(12px)}}
@@ -218,11 +218,22 @@ body .ProseMirror {
218
218
  img {
219
219
  max-width: 100%;
220
220
  }
221
- // @人的样式 #话题的样式
221
+ // @人的样式 #话题的样式 自定义内容的样式
222
222
  .mention, .hash-tag {
223
223
  color: #c02537;
224
224
  padding: 0 0.3em;
225
225
  }
226
+
227
+ .custom-content {
228
+ color: var(--custom-content-color, #000);
229
+ padding: 0 0.3em;
230
+ cursor: pointer;
231
+ transition: color 0.2s ease;
232
+
233
+ &:hover {
234
+ color: var(--custom-content-hover-color, #c02537);
235
+ }
236
+ }
226
237
  }
227
238
 
228
239
  // animation
@@ -26,6 +26,21 @@ export interface HashTagData {
26
26
  hashTagId: string;
27
27
  name: string;
28
28
  }
29
+ /**
30
+ * CustomContentData
31
+ * - 功能:自定义内容的数据结构。
32
+ * - 字段说明:
33
+ * - label: string 显示标签(如 )。
34
+ * - obj: 任意JSON对象,内容由用户自定义。
35
+ * - id: 可选及其他扩展字段。
36
+ */
37
+ export interface CustomContentData {
38
+ label: string;
39
+ obj: Record<string, any>;
40
+ color?: string;
41
+ hoverColor?: string;
42
+ [key: string]: any;
43
+ }
29
44
  /**
30
45
  * HashTagExitEvent
31
46
  * - 功能:在 `hashTag-exit` 事件中传递退出原因与是否为非连续输入。
@@ -56,6 +56,9 @@ function useExtensions({ props, emit }) {
56
56
  };
57
57
  const HashTag = Mention.extend({
58
58
  name: "hashTag",
59
+ parseHTML() {
60
+ return [{ tag: 'span[data-type="hashTag"]' }];
61
+ },
59
62
  renderHTML({ node }) {
60
63
  var _a, _b, _c, _d;
61
64
  const id = (_b = (_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.id) != null ? _b : "";
@@ -144,6 +147,103 @@ function useExtensions({ props, emit }) {
144
147
  }
145
148
  }
146
149
  });
150
+ const CustomContent = Mention.extend({
151
+ name: "customContent",
152
+ parseHTML() {
153
+ return [{ tag: 'span[data-type="custom-content"]' }];
154
+ },
155
+ addAttributes() {
156
+ return {
157
+ id: {
158
+ default: null,
159
+ parseHTML: (element) => element.getAttribute("data-id"),
160
+ renderHTML: (attributes) => {
161
+ if (!attributes.id) {
162
+ return {};
163
+ }
164
+ return {
165
+ "data-id": attributes.id
166
+ };
167
+ }
168
+ },
169
+ label: {
170
+ default: null,
171
+ parseHTML: (element) => element.getAttribute("file-label"),
172
+ renderHTML: (attributes) => {
173
+ if (!attributes.label) {
174
+ return {};
175
+ }
176
+ return {
177
+ "file-label": attributes.label
178
+ };
179
+ }
180
+ },
181
+ obj: {
182
+ default: null,
183
+ parseHTML: (element) => {
184
+ const objStr = element.getAttribute("obj");
185
+ try {
186
+ return objStr ? JSON.parse(objStr) : null;
187
+ } catch (e) {
188
+ return null;
189
+ }
190
+ },
191
+ renderHTML: (attributes) => {
192
+ if (!attributes.obj) {
193
+ return {};
194
+ }
195
+ return {
196
+ obj: JSON.stringify(attributes.obj)
197
+ };
198
+ }
199
+ },
200
+ color: {
201
+ default: null,
202
+ parseHTML: (element) => element.getAttribute("data-color"),
203
+ renderHTML: (attributes) => {
204
+ if (!attributes.color)
205
+ return {};
206
+ return { "data-color": attributes.color };
207
+ }
208
+ },
209
+ hoverColor: {
210
+ default: null,
211
+ parseHTML: (element) => element.getAttribute("data-hover-color"),
212
+ renderHTML: (attributes) => {
213
+ if (!attributes.hoverColor)
214
+ return {};
215
+ return { "data-hover-color": attributes.hoverColor };
216
+ }
217
+ }
218
+ };
219
+ },
220
+ renderHTML({ node }) {
221
+ var _a, _b, _c, _d, _e, _f;
222
+ const obj = (_b = (_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.obj) != null ? _b : {};
223
+ const label = (_d = (_c = node == null ? void 0 : node.attrs) == null ? void 0 : _c.label) != null ? _d : "";
224
+ const color = (_e = node == null ? void 0 : node.attrs) == null ? void 0 : _e.color;
225
+ const hoverColor = (_f = node == null ? void 0 : node.attrs) == null ? void 0 : _f.hoverColor;
226
+ const styleParts = [];
227
+ if (color)
228
+ styleParts.push(`--custom-content-color: ${color}`);
229
+ if (hoverColor)
230
+ styleParts.push(`--custom-content-hover-color: ${hoverColor}`);
231
+ return [
232
+ "span",
233
+ {
234
+ class: "custom-content",
235
+ "data-type": "custom-content",
236
+ obj: JSON.stringify(obj),
237
+ "file-label": label,
238
+ "data-color": color,
239
+ "data-hover-color": hoverColor,
240
+ style: styleParts.length ? styleParts.join(";") : void 0,
241
+ contenteditable: "false"
242
+ },
243
+ label
244
+ ];
245
+ }
246
+ });
147
247
  const extensions = [
148
248
  StarterKit,
149
249
  HtmlBlock,
@@ -291,7 +391,8 @@ function useExtensions({ props, emit }) {
291
391
  }
292
392
  }
293
393
  }),
294
- HashTag
394
+ HashTag,
395
+ CustomContent
295
396
  ];
296
397
  return extensions;
297
398
  }
package/lib/index.d.ts CHANGED
@@ -5,6 +5,6 @@ declare namespace _default {
5
5
  }
6
6
  export default _default;
7
7
  export function install(app: any): void;
8
- export const version: "1.0.47";
8
+ export const version: "1.0.49";
9
9
  import RichTextEditor from './rich-text-editor';
10
10
  export { RichTextEditor };
package/lib/index.js CHANGED
@@ -36,7 +36,7 @@ __export(stdin_exports, {
36
36
  module.exports = __toCommonJS(stdin_exports);
37
37
  var import_rich_text_editor = __toESM(require("./rich-text-editor"));
38
38
  __reExport(stdin_exports, require("./rich-text-editor"), module.exports);
39
- const version = "1.0.47";
39
+ const version = "1.0.49";
40
40
  function install(app) {
41
41
  const components = [
42
42
  import_rich_text_editor.default
@@ -16,7 +16,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
16
16
  type: BooleanConstructor;
17
17
  default: boolean;
18
18
  };
19
- }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked")[], "blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
19
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked" | "customContent-triggered" | "customContent-input" | "customContent-exit" | "customContent-clicked")[], "blur" | "focus" | "hashTag-triggered" | "hashTag-input" | "hashTag-exit" | "mention-triggered" | "mention-input" | "mention-exit" | "update:modelValue" | "mention-clicked" | "hashTag-clicked" | "customContent-triggered" | "customContent-input" | "customContent-exit" | "customContent-clicked", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
20
20
  modelValue: {
21
21
  type: StringConstructor;
22
22
  default: string;
@@ -44,6 +44,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
44
44
  "onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
45
45
  "onMention-clicked"?: ((...args: any[]) => any) | undefined;
46
46
  "onHashTag-clicked"?: ((...args: any[]) => any) | undefined;
47
+ "onCustomContent-triggered"?: ((...args: any[]) => any) | undefined;
48
+ "onCustomContent-input"?: ((...args: any[]) => any) | undefined;
49
+ "onCustomContent-exit"?: ((...args: any[]) => any) | undefined;
50
+ "onCustomContent-clicked"?: ((...args: any[]) => any) | undefined;
47
51
  }>, {
48
52
  modelValue: string;
49
53
  placeholder: string;
@@ -63,7 +63,7 @@ var import_index = require("./index.css");
63
63
  var stdin_default = (0, import_vue2.defineComponent)({
64
64
  name: "RichTextEditor",
65
65
  props: import_types.richTextEditorProps,
66
- emits: ["update:modelValue", "mention-triggered", "mention-input", "mention-exit", "mention-clicked", "hashTag-triggered", "hashTag-input", "hashTag-exit", "hashTag-clicked", "blur", "focus"],
66
+ emits: ["update:modelValue", "mention-triggered", "mention-input", "mention-exit", "mention-clicked", "hashTag-triggered", "hashTag-input", "hashTag-exit", "hashTag-clicked", "customContent-triggered", "customContent-input", "customContent-exit", "customContent-clicked", "blur", "focus"],
67
67
  setup(props, {
68
68
  emit,
69
69
  expose
@@ -131,10 +131,23 @@ var stdin_default = (0, import_vue2.defineComponent)({
131
131
  }
132
132
  });
133
133
  };
134
+ const insertCustomContent = (data) => {
135
+ editor.value.commands.insertContent({
136
+ type: "customContent",
137
+ attrs: {
138
+ id: data.id || `custom-${Date.now()}`,
139
+ label: data.label,
140
+ obj: data.obj,
141
+ color: data.color,
142
+ hoverColor: data.hoverColor
143
+ }
144
+ });
145
+ };
134
146
  expose({
135
147
  getEditor: () => editor.value,
136
148
  insertMention,
137
- insertHashTag
149
+ insertHashTag,
150
+ insertCustomContent
138
151
  });
139
152
  (0, import_vue2.watch)(() => props.modelValue, (newValue) => {
140
153
  var _a, _b;
@@ -217,6 +230,26 @@ var stdin_default = (0, import_vue2.defineComponent)({
217
230
  return;
218
231
  }
219
232
  };
233
+ const customContentClickHandler = (event) => {
234
+ const target = event.target;
235
+ const tagEl = target.closest(".custom-content") || null;
236
+ if (tagEl) {
237
+ const objStr = tagEl.getAttribute("obj") || "{}";
238
+ const label = tagEl.getAttribute("file-label") || "";
239
+ try {
240
+ const obj = JSON.parse(objStr);
241
+ emit("customContent-clicked", {
242
+ obj,
243
+ label
244
+ });
245
+ } catch (e) {
246
+ console.error("Failed to parse custom content obj:", e);
247
+ }
248
+ event.stopPropagation();
249
+ event.preventDefault();
250
+ return;
251
+ }
252
+ };
220
253
  const HISTORY_METADATA_KEY = "rich_text_editor_history_metadata";
221
254
  const MAX_HISTORY_ITEMS = 10;
222
255
  let saveTimeoutId = null;
@@ -270,6 +303,7 @@ var stdin_default = (0, import_vue2.defineComponent)({
270
303
  editorElement.addEventListener("click", imageClickHandler);
271
304
  editorElement.addEventListener("click", hashTagClickHandler);
272
305
  editorElement.addEventListener("click", mentionClickHandler);
306
+ editorElement.addEventListener("click", customContentClickHandler);
273
307
  }
274
308
  });
275
309
  });
@@ -283,6 +317,7 @@ var stdin_default = (0, import_vue2.defineComponent)({
283
317
  editorElement.removeEventListener("click", imageClickHandler);
284
318
  editorElement.removeEventListener("click", hashTagClickHandler);
285
319
  editorElement.removeEventListener("click", mentionClickHandler);
320
+ editorElement.removeEventListener("click", customContentClickHandler);
286
321
  }
287
322
  (_c = editor.value) == null ? void 0 : _c.destroy();
288
323
  });
@@ -1 +1 @@
1
- body .ProseMirror{flex:1;overflow:auto;outline:none;line-height:1.6;font-size:var(--font-base);--white: #fff;--black: #2e2b29;--gray-1: rgba(61, 37, 20, .05);--gray-2: rgba(61, 37, 20, .08);--gray-3: rgba(61, 37, 20, .12);--gray-4: rgba(53, 38, 28, .3);--gray-5: rgba(28, 25, 23, .6);--green: #22c55e;--purple: #6a00f5;--purple-contrast: #5800cc;--purple-light: rgba(88, 5, 255, .05);--yellow-contrast: #facc15;--yellow: rgba(250, 204, 21, .4);--yellow-light: #fffae5;--red: #ff5c33;--red-light: #ffebe5;--shadow: 0px 12px 33px 0px rgba(0, 0, 0, .06), 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04)}body .ProseMirror :first-child{margin-top:0}body .ProseMirror video{width:100%}body .ProseMirror ol{list-style:auto}body .ProseMirror ol ol,body .ProseMirror ul{list-style:disc}body .ProseMirror ol,body .ProseMirror ul{padding-left:1.5em;margin:0 0 12px}body .ProseMirror ol li p,body .ProseMirror ul li p{margin-top:.25em;margin-bottom:.25em}body .ProseMirror li::marker{text-align:start!important}body .ProseMirror h1,body .ProseMirror h2,body .ProseMirror h3,body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{line-height:1.1;margin-top:2.5rem;text-wrap:pretty}body .ProseMirror h1,body .ProseMirror h2{margin-top:1rem;margin-bottom:1rem}body .ProseMirror h1{font-size:1.4rem}body .ProseMirror h2{font-size:1.2rem}body .ProseMirror h3{font-size:1.1rem}body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{font-size:1rem}body .ProseMirror a,body .ProseMirror .editor-link{color:var(--purple);text-decoration:underline;cursor:pointer;transition:color .2s ease}body .ProseMirror a:hover,body .ProseMirror .editor-link:hover{color:var(--purple-contrast);text-decoration:underline}body .ProseMirror code{background-color:#ffe5e8;border-radius:.4rem;color:#c02537;padding:2px 4px}body .ProseMirror pre{border-radius:.5rem;font-family:JetBrainsMono,monospace;margin:1.5rem 0;padding:.75rem 1rem}body .ProseMirror pre code{background:none;color:inherit;font-size:.8rem;padding:0}body .ProseMirror blockquote{border-left:3px solid var(--gray-3);margin:1.5rem 0;padding-left:1rem}body .ProseMirror hr{border:none;border-top:1px solid var(--gray-2);margin:2rem 0}body .ProseMirror p.is-editor-empty:first-child:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror .is-empty:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror table{border-collapse:collapse;margin:0;overflow:hidden;table-layout:fixed;width:100%}body .ProseMirror table td,body .ProseMirror table th{border:1px solid var(--gray-3);box-sizing:border-box;min-width:1em;padding:6px 8px;position:relative;vertical-align:top}body .ProseMirror table td>*,body .ProseMirror table th>*{margin-bottom:0}body .ProseMirror table th{background-color:var(--gray-1);font-weight:700;text-align:left}body .ProseMirror table .selectedCell:after{background:var(--gray-2);content:"";left:0;right:0;top:0;bottom:0;pointer-events:none;position:absolute;z-index:2}body .ProseMirror table .column-resize-handle{background-color:var(--purple);bottom:-2px;pointer-events:none;position:absolute;right:-2px;top:0;width:4px}body .ProseMirror .tableWrapper{margin:1.5rem 0;overflow-x:auto}body .ProseMirror.resize-cursor{cursor:ew-resize;cursor:col-resize}body .ProseMirror img{max-width:100%}body .ProseMirror .mention,body .ProseMirror .hash-tag{color:#c02537;padding:0 .3em}.animation-indent--right{animation:indent-right .5s cubic-bezier(.68,-.55,.27,1.55) 1 alternate-reverse}@keyframes indent-right{0%{transform:translate(0)}to{transform:translate(12px)}}
1
+ body .ProseMirror{flex:1;overflow:auto;outline:none;line-height:1.6;font-size:var(--font-base);--white: #fff;--black: #2e2b29;--gray-1: rgba(61, 37, 20, .05);--gray-2: rgba(61, 37, 20, .08);--gray-3: rgba(61, 37, 20, .12);--gray-4: rgba(53, 38, 28, .3);--gray-5: rgba(28, 25, 23, .6);--green: #22c55e;--purple: #6a00f5;--purple-contrast: #5800cc;--purple-light: rgba(88, 5, 255, .05);--yellow-contrast: #facc15;--yellow: rgba(250, 204, 21, .4);--yellow-light: #fffae5;--red: #ff5c33;--red-light: #ffebe5;--shadow: 0px 12px 33px 0px rgba(0, 0, 0, .06), 0px 3.618px 9.949px 0px rgba(0, 0, 0, .04)}body .ProseMirror :first-child{margin-top:0}body .ProseMirror video{width:100%}body .ProseMirror ol{list-style:auto}body .ProseMirror ol ol,body .ProseMirror ul{list-style:disc}body .ProseMirror ol,body .ProseMirror ul{padding-left:1.5em;margin:0 0 12px}body .ProseMirror ol li p,body .ProseMirror ul li p{margin-top:.25em;margin-bottom:.25em}body .ProseMirror li::marker{text-align:start!important}body .ProseMirror h1,body .ProseMirror h2,body .ProseMirror h3,body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{line-height:1.1;margin-top:2.5rem;text-wrap:pretty}body .ProseMirror h1,body .ProseMirror h2{margin-top:1rem;margin-bottom:1rem}body .ProseMirror h1{font-size:1.4rem}body .ProseMirror h2{font-size:1.2rem}body .ProseMirror h3{font-size:1.1rem}body .ProseMirror h4,body .ProseMirror h5,body .ProseMirror h6{font-size:1rem}body .ProseMirror a,body .ProseMirror .editor-link{color:var(--purple);text-decoration:underline;cursor:pointer;transition:color .2s ease}body .ProseMirror a:hover,body .ProseMirror .editor-link:hover{color:var(--purple-contrast);text-decoration:underline}body .ProseMirror code{background-color:#ffe5e8;border-radius:.4rem;color:#c02537;padding:2px 4px}body .ProseMirror pre{border-radius:.5rem;font-family:JetBrainsMono,monospace;margin:1.5rem 0;padding:.75rem 1rem}body .ProseMirror pre code{background:none;color:inherit;font-size:.8rem;padding:0}body .ProseMirror blockquote{border-left:3px solid var(--gray-3);margin:1.5rem 0;padding-left:1rem}body .ProseMirror hr{border:none;border-top:1px solid var(--gray-2);margin:2rem 0}body .ProseMirror p.is-editor-empty:first-child:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror .is-empty:before{color:var(--gray-4);content:attr(data-placeholder);float:left;height:0;pointer-events:none}body .ProseMirror table{border-collapse:collapse;margin:0;overflow:hidden;table-layout:fixed;width:100%}body .ProseMirror table td,body .ProseMirror table th{border:1px solid var(--gray-3);box-sizing:border-box;min-width:1em;padding:6px 8px;position:relative;vertical-align:top}body .ProseMirror table td>*,body .ProseMirror table th>*{margin-bottom:0}body .ProseMirror table th{background-color:var(--gray-1);font-weight:700;text-align:left}body .ProseMirror table .selectedCell:after{background:var(--gray-2);content:"";left:0;right:0;top:0;bottom:0;pointer-events:none;position:absolute;z-index:2}body .ProseMirror table .column-resize-handle{background-color:var(--purple);bottom:-2px;pointer-events:none;position:absolute;right:-2px;top:0;width:4px}body .ProseMirror .tableWrapper{margin:1.5rem 0;overflow-x:auto}body .ProseMirror.resize-cursor{cursor:ew-resize;cursor:col-resize}body .ProseMirror img{max-width:100%}body .ProseMirror .mention,body .ProseMirror .hash-tag{color:#c02537;padding:0 .3em}body .ProseMirror .custom-content{color:var(--custom-content-color, #000);padding:0 .3em;cursor:pointer;transition:color .2s ease}body .ProseMirror .custom-content:hover{color:var(--custom-content-hover-color, #c02537)}.animation-indent--right{animation:indent-right .5s cubic-bezier(.68,-.55,.27,1.55) 1 alternate-reverse}@keyframes indent-right{0%{transform:translate(0)}to{transform:translate(12px)}}
@@ -218,11 +218,22 @@ body .ProseMirror {
218
218
  img {
219
219
  max-width: 100%;
220
220
  }
221
- // @人的样式 #话题的样式
221
+ // @人的样式 #话题的样式 自定义内容的样式
222
222
  .mention, .hash-tag {
223
223
  color: #c02537;
224
224
  padding: 0 0.3em;
225
225
  }
226
+
227
+ .custom-content {
228
+ color: var(--custom-content-color, #000);
229
+ padding: 0 0.3em;
230
+ cursor: pointer;
231
+ transition: color 0.2s ease;
232
+
233
+ &:hover {
234
+ color: var(--custom-content-hover-color, #c02537);
235
+ }
236
+ }
226
237
  }
227
238
 
228
239
  // animation
@@ -26,6 +26,21 @@ export interface HashTagData {
26
26
  hashTagId: string;
27
27
  name: string;
28
28
  }
29
+ /**
30
+ * CustomContentData
31
+ * - 功能:自定义内容的数据结构。
32
+ * - 字段说明:
33
+ * - label: string 显示标签(如 )。
34
+ * - obj: 任意JSON对象,内容由用户自定义。
35
+ * - id: 可选及其他扩展字段。
36
+ */
37
+ export interface CustomContentData {
38
+ label: string;
39
+ obj: Record<string, any>;
40
+ color?: string;
41
+ hoverColor?: string;
42
+ [key: string]: any;
43
+ }
29
44
  /**
30
45
  * HashTagExitEvent
31
46
  * - 功能:在 `hashTag-exit` 事件中传递退出原因与是否为非连续输入。
@@ -88,6 +88,9 @@ function useExtensions({ props, emit }) {
88
88
  };
89
89
  const HashTag = import_extension_mention.default.extend({
90
90
  name: "hashTag",
91
+ parseHTML() {
92
+ return [{ tag: 'span[data-type="hashTag"]' }];
93
+ },
91
94
  renderHTML({ node }) {
92
95
  var _a, _b, _c, _d;
93
96
  const id = (_b = (_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.id) != null ? _b : "";
@@ -176,6 +179,103 @@ function useExtensions({ props, emit }) {
176
179
  }
177
180
  }
178
181
  });
182
+ const CustomContent = import_extension_mention.default.extend({
183
+ name: "customContent",
184
+ parseHTML() {
185
+ return [{ tag: 'span[data-type="custom-content"]' }];
186
+ },
187
+ addAttributes() {
188
+ return {
189
+ id: {
190
+ default: null,
191
+ parseHTML: (element) => element.getAttribute("data-id"),
192
+ renderHTML: (attributes) => {
193
+ if (!attributes.id) {
194
+ return {};
195
+ }
196
+ return {
197
+ "data-id": attributes.id
198
+ };
199
+ }
200
+ },
201
+ label: {
202
+ default: null,
203
+ parseHTML: (element) => element.getAttribute("file-label"),
204
+ renderHTML: (attributes) => {
205
+ if (!attributes.label) {
206
+ return {};
207
+ }
208
+ return {
209
+ "file-label": attributes.label
210
+ };
211
+ }
212
+ },
213
+ obj: {
214
+ default: null,
215
+ parseHTML: (element) => {
216
+ const objStr = element.getAttribute("obj");
217
+ try {
218
+ return objStr ? JSON.parse(objStr) : null;
219
+ } catch (e) {
220
+ return null;
221
+ }
222
+ },
223
+ renderHTML: (attributes) => {
224
+ if (!attributes.obj) {
225
+ return {};
226
+ }
227
+ return {
228
+ obj: JSON.stringify(attributes.obj)
229
+ };
230
+ }
231
+ },
232
+ color: {
233
+ default: null,
234
+ parseHTML: (element) => element.getAttribute("data-color"),
235
+ renderHTML: (attributes) => {
236
+ if (!attributes.color)
237
+ return {};
238
+ return { "data-color": attributes.color };
239
+ }
240
+ },
241
+ hoverColor: {
242
+ default: null,
243
+ parseHTML: (element) => element.getAttribute("data-hover-color"),
244
+ renderHTML: (attributes) => {
245
+ if (!attributes.hoverColor)
246
+ return {};
247
+ return { "data-hover-color": attributes.hoverColor };
248
+ }
249
+ }
250
+ };
251
+ },
252
+ renderHTML({ node }) {
253
+ var _a, _b, _c, _d, _e, _f;
254
+ const obj = (_b = (_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.obj) != null ? _b : {};
255
+ const label = (_d = (_c = node == null ? void 0 : node.attrs) == null ? void 0 : _c.label) != null ? _d : "";
256
+ const color = (_e = node == null ? void 0 : node.attrs) == null ? void 0 : _e.color;
257
+ const hoverColor = (_f = node == null ? void 0 : node.attrs) == null ? void 0 : _f.hoverColor;
258
+ const styleParts = [];
259
+ if (color)
260
+ styleParts.push(`--custom-content-color: ${color}`);
261
+ if (hoverColor)
262
+ styleParts.push(`--custom-content-hover-color: ${hoverColor}`);
263
+ return [
264
+ "span",
265
+ {
266
+ class: "custom-content",
267
+ "data-type": "custom-content",
268
+ obj: JSON.stringify(obj),
269
+ "file-label": label,
270
+ "data-color": color,
271
+ "data-hover-color": hoverColor,
272
+ style: styleParts.length ? styleParts.join(";") : void 0,
273
+ contenteditable: "false"
274
+ },
275
+ label
276
+ ];
277
+ }
278
+ });
179
279
  const extensions = [
180
280
  import_starter_kit.default,
181
281
  import_HtmlBlock.default,
@@ -323,7 +423,8 @@ function useExtensions({ props, emit }) {
323
423
  }
324
424
  }
325
425
  }),
326
- HashTag
426
+ HashTag,
427
+ CustomContent
327
428
  ];
328
429
  return extensions;
329
430
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cgboiler/biz-basic",
3
- "version": "1.0.48",
3
+ "version": "1.0.50",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "module": "es/index.js",