@pixui-dev/pixui-richtext-helper 0.1.1-beta.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42,7 +42,7 @@ export declare class RichText_Refactor {
42
42
  * 处理单个段落片段,返回转换后的片段 HTML
43
43
  */
44
44
  private static processSegment;
45
- private static handleIndentClass;
45
+ private static preprocess;
46
46
  private static fixImgSizeUnit;
47
47
  /** 列表处理(将 ol/ul/li 替换为 div 结构) */
48
48
  private static handleLists;
@@ -214,7 +214,7 @@ var RichText_Refactor = /** @class */ (function () {
214
214
  RichText_Refactor.processSegment = function (segmentHtml, config) {
215
215
  var $ = cheerio.load(segmentHtml, null, false);
216
216
  // 按旧实现顺序进行处理,但重构为独立函数划分
217
- this.handleIndentClass($);
217
+ this.preprocess($);
218
218
  this.fixImgSizeUnit($);
219
219
  this.handleLists($, (config === null || config === void 0 ? void 0 : config.lineHeightScale) || 1);
220
220
  this.replaceBrWithPlaceholder($);
@@ -230,19 +230,24 @@ var RichText_Refactor = /** @class */ (function () {
230
230
  this.adjustLineHeightAndLetterSpacing($, config);
231
231
  this.transferTextAlign($);
232
232
  this.removeEmptyText($);
233
- this.fixHeadingFontSize($);
233
+ // this.fixHeadingFontSize($);
234
234
  // 最后:修正 img 结束标签、nbsp
235
235
  var res = $.html();
236
- res = res.replaceAll(/<img([^>]+)>/g, "<img$1 />").replaceAll(/&nbsp;/g, " ");
236
+ res = res
237
+ .replaceAll(/<img([^>]+)>/g, "<img$1 />")
238
+ .replaceAll(/&nbsp;/g, " ")
239
+ .replaceAll(/&amp;/g, "&")
240
+ .replaceAll(/&quot;/g, '"')
241
+ .replaceAll("\"", "\"");
237
242
  return res;
238
243
  };
239
244
  // ------------------------------
240
245
  // 各独立处理步骤实现
241
246
  // ------------------------------
242
- RichText_Refactor.handleIndentClass = function ($) {
247
+ RichText_Refactor.preprocess = function ($) {
243
248
  var _loop_1 = function (i) {
244
249
  var indent = "ql-indent-".concat(i);
245
- var extStyle = "padding-left: ".concat(i * 2, "rem");
250
+ var extStyle = "padding-left: ".concat(i * 2, "em");
246
251
  $(".".concat(indent)).each(function () {
247
252
  var ori = $(this).attr("style") || "";
248
253
  $(this).attr("style", mergeStyles(ori, extStyle));
@@ -252,6 +257,30 @@ var RichText_Refactor = /** @class */ (function () {
252
257
  for (var i = 1; i <= 10; i++) {
253
258
  _loop_1(i);
254
259
  }
260
+ // 在所有标题标签后插入换行 <br>
261
+ $("h1, h2, h3, h4, h5, h6").each(function () {
262
+ // 若标题后紧跟已有换行则不再追加
263
+ var next = $(this).next();
264
+ if (!next.is("br")) {
265
+ $(this).after("<br>");
266
+ }
267
+ });
268
+ // 将所有的margin-left转换为padding-left
269
+ $("*").each(function () {
270
+ var oriStyle = $(this).attr("style") || "";
271
+ if (!oriStyle)
272
+ return;
273
+ var styleObj = parseStyleString(oriStyle);
274
+ var marginLeftVal = styleObj["margin-left"];
275
+ if (marginLeftVal !== undefined) {
276
+ // 移除 margin-left
277
+ delete styleObj["margin-left"];
278
+ // 如果原本没有 padding-left,则直接设置;若已有,简单覆盖(遵循后写优先规则)
279
+ styleObj["padding-left"] = styleObj["padding-left"] || marginLeftVal;
280
+ // 写回合并后的样式
281
+ $(this).attr("style", serializeStyleObject(styleObj));
282
+ }
283
+ });
255
284
  };
256
285
  RichText_Refactor.fixImgSizeUnit = function ($) {
257
286
  $("img").each(function () {
@@ -281,7 +310,7 @@ var RichText_Refactor = /** @class */ (function () {
281
310
  orderIndex = $child.prevAll("li").length + 1;
282
311
  }
283
312
  var marker = isOrdered ? "".concat(orderIndex, ".") : "•";
284
- var paddingLeft = currentLevel * 2; // 每层缩进 2rem
313
+ var paddingLeft = currentLevel * 2; // 每层缩进 2em
285
314
  var $liClone = $child.clone();
286
315
  $liClone.find("ol, ul").remove();
287
316
  var textContent = $liClone.text().trim() || "";
@@ -328,16 +357,16 @@ var RichText_Refactor = /** @class */ (function () {
328
357
  var placeholder = listInfo.placeholder, items = listInfo.items;
329
358
  var html = items
330
359
  .map(function (it, idx) {
331
- // 所有列表项默认上下 0.5 * lineHeightScale rem
360
+ // 所有列表项默认上下 0.5 * lineHeightScale em
332
361
  var marginTopVal = idx === 0 ? 1 * lineHeightScale : 0.5 * lineHeightScale;
333
362
  var marginBottomVal = idx === items.length - 1 ? 1 * lineHeightScale : 0.5 * lineHeightScale;
334
- var marginAdjust = ["margin-top: ".concat(marginTopVal, "rem"), "margin-bottom: ".concat(marginBottomVal, "rem")];
335
- return ("<div style=\"".concat(mergeStyles.apply(void 0, __spreadArray(__spreadArray([it.style], marginAdjust, false), ["padding-left: ".concat(it.paddingLeft, "rem"), "flex-shrink: 0",
363
+ var marginAdjust = ["margin-top: ".concat(marginTopVal, "em"), "margin-bottom: ".concat(marginBottomVal, "em")];
364
+ return ("<div style=\"".concat(mergeStyles.apply(void 0, __spreadArray(__spreadArray([it.style], marginAdjust, false), ["padding-left: ".concat(it.paddingLeft, "em"), "flex-shrink: 0",
336
365
  "width: 100%",
337
366
  "flex-direction: row",
338
367
  "display: flex"], false)), "\" data-list-item=\"true\">") +
339
368
  "<text style=\"".concat(mergeStyles("flex-shrink: 0", "width: 100%", "line-height: 1", "display: flex", "flex-direction: row"), "\">") +
340
- "<div style=\"".concat(mergeStyles("word-break: break-word", "flex-shrink: 0", "margin-right: 0.5rem"), "\">").concat(it.marker, "</div>") +
369
+ "<div style=\"".concat(mergeStyles("word-break: break-word", "flex-shrink: 0", "padding-right: 0.5em"), "\">").concat(it.marker, "</div>") +
341
370
  "<div style=\"".concat(mergeStyles("word-break: break-word", "flex-shrink: 0", "flex: 1"), "\">").concat(it.textContent, "</div>") +
342
371
  "</text></div>");
343
372
  })
@@ -349,7 +378,7 @@ var RichText_Refactor = /** @class */ (function () {
349
378
  /** 将连续 <br> 替换为透明占位文字,确保 PixUI 换行 */
350
379
  RichText_Refactor.replaceBrWithPlaceholder = function ($) {
351
380
  $("br").each(function () {
352
- $(this).replaceWith("<span style=\"".concat(mergeStyles("color: transparent", "flex-shrink: 0", "font-size: 20px"), "\" class='pixui-richtext-br-placeholder'>1</span>"));
381
+ $(this).replaceWith("<div style=\"".concat(mergeStyles("color: transparent", "flex-shrink: 0", "font-size: 20px"), "\" class='pixui-richtext-br-placeholder'>1</div>"));
353
382
  });
354
383
  };
355
384
  /** 处理 <a> 标签:转为 div、保留样式、记录链接 */
@@ -420,19 +449,27 @@ var RichText_Refactor = /** @class */ (function () {
420
449
  u: "text-decoration: underline",
421
450
  s: "text-decoration: line-through",
422
451
  };
423
- Object.entries(tagToStyle).forEach(function (_a) {
424
- var tag = _a[0], style = _a[1];
425
- $(tag).each(function () {
452
+ var hasLeftover = true;
453
+ while (hasLeftover) {
454
+ hasLeftover = false;
455
+ // 处理 strong / em / u / s
456
+ Object.entries(tagToStyle).forEach(function (_a) {
457
+ var tag = _a[0], style = _a[1];
458
+ $(tag).each(function () {
459
+ var html = $(this).html();
460
+ var oriStyle = $(this).attr("style") || "";
461
+ $(this).replaceWith("<text style=\"".concat(mergeStyles(oriStyle, style, "flex-shrink: 0"), "\">").concat(html, "</text>"));
462
+ hasLeftover = true;
463
+ });
464
+ });
465
+ // 处理 span
466
+ $("span").each(function () {
426
467
  var html = $(this).html();
427
468
  var oriStyle = $(this).attr("style") || "";
428
- $(this).replaceWith("<text style=\"".concat(mergeStyles(oriStyle, style, "flex-shrink: 0"), "\">").concat(html, "</text>"));
469
+ $(this).replaceWith("<text style=\"".concat(mergeStyles(oriStyle, "flex-shrink: 0"), "\">").concat(html, "</text>"));
470
+ hasLeftover = true;
429
471
  });
430
- });
431
- $("span").each(function () {
432
- var html = $(this).html();
433
- var oriStyle = $(this).attr("style") || "";
434
- $(this).replaceWith("<text style=\"".concat(mergeStyles(oriStyle, "flex-shrink: 0"), "\">").concat(html, "</text>"));
435
- });
472
+ }
436
473
  };
437
474
  /** p → div */
438
475
  RichText_Refactor.replacePTag = function ($) {
@@ -453,8 +490,11 @@ var RichText_Refactor = /** @class */ (function () {
453
490
  self.linkNodes.push({ type: LinkNodeType.IMG, href: href, id: id });
454
491
  }
455
492
  $(this).attr("href", "");
456
- $(this).attr("class", "PA_RichTextHref_ImgTag");
457
- $(this).attr("data-href", href);
493
+ var prevClass = $(this).attr("class") || "";
494
+ var newClasses = new Set(prevClass.split(/\s+/).filter(Boolean));
495
+ newClasses.add("PA_RichTextHref_ImgTag"); // 超链接专用标记(保持原有逻辑)
496
+ newClasses.add("PA_RichTextImgTag"); // 富文本图片通用标记
497
+ $(this).attr("class", Array.from(newClasses).join(" "));
458
498
  });
459
499
  };
460
500
  /** 给指定标签补 flex-shrink:0 */
@@ -587,7 +627,7 @@ var RichText_Refactor = /** @class */ (function () {
587
627
  });
588
628
  if (maxLS > 0) {
589
629
  var currentStyle = $text.attr("style") || "";
590
- $text.attr("style", mergeStyles(currentStyle, "letter-spacing: ".concat(maxLS, "rem")));
630
+ $text.attr("style", mergeStyles(currentStyle, "letter-spacing: ".concat(maxLS, "em")));
591
631
  }
592
632
  });
593
633
  };
@@ -620,7 +660,7 @@ var RichText_Refactor = /** @class */ (function () {
620
660
  };
621
661
  /** 补默认 heading 字体大小 */
622
662
  RichText_Refactor.fixHeadingFontSize = function ($) {
623
- var hRem = ["2rem", "1.5rem", "1.17rem", "1rem", "0.83rem", "0.67rem"];
663
+ var hRem = ["2em", "1.5em", "1.17em", "1em", "0.83em", "0.67em"];
624
664
  ["h1", "h2", "h3", "h4", "h5", "h6"].forEach(function (tag) {
625
665
  $(tag).each(function () {
626
666
  var idx = parseInt(tag.replace("h", "")) - 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixui-dev/pixui-richtext-helper",
3
- "version": "0.1.1-beta.5",
3
+ "version": "0.2.0",
4
4
  "description": "pixui richtext helper",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,7 +20,6 @@
20
20
  "license": "ISC",
21
21
  "devDependencies": {
22
22
  "@types/node": "^22.15.33",
23
- "ts-node": "^10.9.2",
24
23
  "typescript": "^5.8.3"
25
24
  },
26
25
  "dependencies": {
package/readme.md CHANGED
@@ -1,13 +1,13 @@
1
1
  安装
2
2
 
3
3
  ```bash
4
- yarn add pixui-richtext-helper
4
+ yarn add @pixui-dev/pixui-richtext-helper
5
5
  ```
6
6
 
7
7
  使用
8
8
 
9
9
  ```tsx
10
- import { RichText } from "pixui-richtext-helper";
10
+ import { RichText } from "@pixui-dev/pixui-richtext-helper";
11
11
 
12
12
  const richText; // 从管理端获取的富文本数据
13
13
  const pixuiStyle = RichText.convertRichTextToPixuiStyle(richText);
@@ -26,3 +26,53 @@ componentDidMount() { // 在节点渲染后绑定点击事件
26
26
  });
27
27
  }
28
28
  ```
29
+
30
+ ### 自定义节点样式
31
+
32
+ `convertRichTextToPixuiStyle` 在转换过程中会为特定节点增加 class 或 data-attribute,方便业务侧按需覆盖样式:
33
+
34
+ | 节点类型 | 标记 | 说明 |
35
+ | --- | --- | --- |
36
+ | 超链接文本(`div`) | `.PA_RichTextHref_ATag` | 原 `a` 标签被替换后的容器,可通过样式控制颜色、下划线等效果 |
37
+ | 带超链接的图片(`img`) | `.PA_RichTextHref_ImgTag` | 图片本身存在跳转链接时添加 |
38
+ | 所有图片(`img`) | `.PA_RichTextImgTag` | 富文本中的通用图片标记 |
39
+ | 占位换行节点(`div`/`span`) | `.pixui-richtext-br-placeholder` | 连续 `<br>` 会被替换为透明字符占位,可调整段落之间的间距 |
40
+ | 列表条目容器(`div`) | `data-list-item="true"` | 每个列表项均带此属性,方便定制行距、缩进等 |
41
+ | 超链接节点(任何) | `id="PA_RichTextHrefId_xxx"` | 与 `bindLinkClickEvents` 配合,可用 `[id^="PA_RichTextHrefId_"]` 选择 |
42
+
43
+ 示例:
44
+
45
+ ```css
46
+ /* 修改超链接颜色及鼠标样式 */
47
+ .PA_RichTextHref_ATag {
48
+ color: #1e90ff;
49
+ cursor: pointer;
50
+ text-decoration: underline;
51
+ }
52
+
53
+ /* 统一图片最大宽度 */
54
+ .PA_RichTextImgTag {
55
+ max-width: 100%;
56
+ }
57
+
58
+ /* 调整列表行距 */
59
+ [data-list-item="true"] {
60
+ line-height: 20px;
61
+ }
62
+
63
+ /* 自定义换行占位符大小 */
64
+ .pixui-richtext-br-placeholder {
65
+ font-size: 12px;
66
+ }
67
+ ```
68
+
69
+ 版本更新记录
70
+
71
+ 0.1.1-beta.5
72
+ 1. 新增:防止重复转换
73
+
74
+ 0.2.0
75
+ 1. 组件默认样式长度单位修改为em
76
+ 2. 图片节点统一补充PA_RichTextImgTag的class
77
+ 3. 将列表的margin-left统一修改为padding-left
78
+ 4. 修复某些情况下多余的span标签