Skip to content

富文本优化同时支持列表和链接渲染#2066

Open
kkxxkk2019 wants to merge 1 commit intodevelopfrom
fix/richText
Open

富文本优化同时支持列表和链接渲染#2066
kkxxkk2019 wants to merge 1 commit intodevelopfrom
fix/richText

Conversation

@kkxxkk2019
Copy link
Copy Markdown
Contributor

@kkxxkk2019 kkxxkk2019 commented Mar 31, 2026

Add 264 tests across 6 suites for richtext modules. Optimize Segmenter caching, early exits, object creation. Fix TS type errors and 2 pre-existing test assertions.

[中文版模板 / Chinese template]

🤔 This is a ...

  • New feature
  • Bug fix
  • TypeScript definition update
  • Bundle size optimization
  • Performance optimization
  • Enhancement feature
  • Refactoring
  • Update dependency
  • Code style optimization
  • Test Case
  • Branch merge
  • Site / documentation update
  • Demo update
  • Workflow
  • Release
  • Other (about what?)

🔗 Related issue link

🐞 Bugserver case id

💡 Background and solution

📝 Changelog

Language Changelog
🇺🇸 English
🇨🇳 Chinese

☑️ Self-Check before Merge

⚠️ Please check all items below before requesting a reviewing. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • TypeScript definition is updated/provided or not needed
  • Changelog is provided or not needed

🚀 Summary

copilot:summary

🔍 Walkthrough

copilot:walkthrough

Add 264 tests across 6 suites for richtext modules.
Optimize Segmenter caching, early exits, object creation.
Fix TS type errors and 2 pre-existing test assertions.
Copilot AI review requested due to automatic review settings March 31, 2026 13:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enhances RichText to support list item layout (including hanging indents + auto numbering) and clickable link rendering (hover/click hit-testing + events), while also improving editor behaviors and adding extensive test coverage.

Changes:

  • Add list item character type + layout handling (marker generation, indentation, cursor mapping for editing).
  • Add link attributes, link hit-testing/hover/click event emission, and editor commands to add/remove links.
  • Add/expand test suites and browser demos; minor sidebar search UI improvements in test browsers.

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
packages/vrender/tests/browser/src/style.css Adds sidebar search styling; adjusts menu list height.
packages/vrender/tests/browser/src/main.ts Adds sidebar search + filtered menu rendering for demos.
packages/vrender-core/src/plugins/builtin-plugin/richtext-edit-plugin.ts Adds link format/remove commands; improves cleanup and drag selection behavior.
packages/vrender-core/src/plugins/builtin-plugin/edit-module.ts Adds list-aware cursor mapping, list enter behavior, textarea lazy creation, and safer release.
packages/vrender-core/src/interface/graphic/richText.ts Extends richtext character types with link and list item support; adds link region tracking types.
packages/vrender-core/src/graphic/richtext/wrapper.ts Implements hanging indent support and registers link regions per line for hit-testing.
packages/vrender-core/src/graphic/richtext/paragraph.ts Preserves _listIndent / _linkId when splitting paragraphs.
packages/vrender-core/src/graphic/richtext/frame.ts Adds links map and getLineDrawingPosition used by draw + link hit-testing.
packages/vrender-core/src/graphic/richtext.ts Adds list marker generation/indentation, link styling + event, element picking, and Segmenter caching.
packages/vrender-core/tests/richtext_utils/richtext_utils.test.ts New tests for richtext utils + Paragraph/Frame/Wrapper branches.
packages/vrender-core/tests/richtext_list_link/richtext_list_link.test.ts New tests for list/link behavior and wrapper indent/link-region logic.
packages/vrender-core/tests/richtext_editor/richtext_editor.test.ts Refactors/expands cursor mapping tests and default config tests.
packages/vrender-core/tests/richtext_edit_plugin/richtext_edit_plugin.test.ts New tests for RichTextEditPlugin selection + commands (incl. link commands).
packages/vrender-core/tests/richtext_edit_module/richtext_edit_module.test.ts New tests for edit-module cursor mapping incl. list items.
packages/vrender-core/tests/richtext_core/richtext_core.test.ts New tests for RichText static logic (split/single-char transform), replicated for isolation.
packages/vrender-core/tests/browser/src/style.css Adds sidebar search styling.
packages/vrender-core/tests/browser/src/pages/richtext-list-link.ts New browser demo page for lists + links.
packages/vrender-core/tests/browser/src/pages/richtext-editor.ts New browser demo page for richtext editor + link/list tooling.
packages/vrender-core/tests/browser/src/pages/index.ts Adds new demo entries for list/link and editor pages.
packages/vrender-core/tests/browser/src/main.ts Adds sidebar search + filtered menu rendering for demo pages.
packages/vrender-components/tests/browser/vite.config.ts Adds alias for @visactor/vrender-components in browser tests.
packages/vrender-components/tests/browser/style.css Adds sidebar search styling; adjusts menu list height.
packages/vrender-components/tests/browser/main.ts Adds sidebar search + filtered menu rendering for components demos.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

!keyword || child.name.toLowerCase().includes(keyword) || child.path.toLowerCase().includes(keyword)
)
.map(child => {
return `<p class="menu-item" data-path="${child.path}"data-type="${child.type ?? 'spec'}">${
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the generated menu HTML for child entries, the data-path and data-type attributes are concatenated without whitespace (..."${child.path}"data-type=...). This produces invalid HTML and can break attribute parsing in some browsers; add a space between attributes.

Suggested change
return `<p class="menu-item" data-path="${child.path}"data-type="${child.type ?? 'spec'}">${
return `<p class="menu-item" data-path="${child.path}" data-type="${child.type ?? 'spec'}">${

Copilot uses AI. Check for mistakes.
delete item.href;
delete item.linkColor;
delete item.linkHoverColor;
item.underline = false;
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removeLinkCommandCb unconditionally sets underline = false for all selected items. This can unintentionally remove an underline that existed before the link was applied. Consider only deleting link-related properties (href, linkColor, linkHoverColor) and leaving underline unchanged (or only removing it when it was implicitly added by link formatting).

Suggested change
item.underline = false;

Copilot uses AI. Check for mistakes.
Comment on lines +395 to +396
// Note: wrapper does not yet propagate _listIndent to continuation lines across paragraphs
expect(frame.lines[1].left).toBe(0);
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test asserts frame.lines[1].left is 0, but the updated Wrapper.cut() now propagates _listIndent when the content paragraph wraps to a new line (it sets _currentLineIndent = paragraph._listIndent before re-dealing). The expectation and comment are now inconsistent with the implementation and should be updated to assert the hanging indent is preserved (i.e., equals content._listIndent).

Suggested change
// Note: wrapper does not yet propagate _listIndent to continuation lines across paragraphs
expect(frame.lines[1].left).toBe(0);
// Wrapper should preserve the hanging indent on continuation lines using content._listIndent
expect(frame.lines[1].left).toBe(content._listIndent);

Copilot uses AI. Check for mistakes.
Comment on lines +424 to +431
// ===================== 链接点击事件 =====================
richText.bindIconEvent();
richText.addEventListener('bindLinkClick', (e: any) => {
const { href, text } = e.detail || {};
if (href) {
infoPanel.textContent = `链接点击:${text} → ${href}`;
}
});
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The richtext link click event emitted by RichText.bindIconEvent() is named richtext-link-click, but this demo listens to bindLinkClick, so the handler will never fire. Update the event name (and keep it consistent with richtext-list-link.ts).

Copilot uses AI. Check for mistakes.
Comment on lines +303 to +356
export type IRichTextListItemCharacter = IRichTextBasicCharacter & {
/**
* 列表类型
* ordered: 有序列表
* unordered: 无序列表
*/
listType: 'ordered' | 'unordered';
/**
* 文本内容
*/
text: string | number;
/**
* 嵌套层级,1-based,默认1
*/
listLevel?: number;
/**
* 有序列表显式序号,省略时自动计算
*/
listIndex?: number;
/**
* 自定义标记符(如 '◦', 'a.', 'i.')
*/
listMarker?: string;
/**
* 每级缩进量,默认20px
*/
listIndentPerLevel?: number;
/**
* 标记颜色,默认跟随fill
*/
markerColor?: IColor;

// 文本样式属性
fontSize?: number;
fontFamily?: string;
fill?: IColor | boolean;
stroke?: IColor | boolean;
fontWeight?: string;
lineWidth?: number;
fontStyle?: RichTextFontStyle;
textDecoration?: RichTextTextDecoration;
script?: RichTextScript;
underline?: boolean;
lineThrough?: boolean;
opacity?: number;
fillOpacity?: number;
strokeOpacity?: number;
background?: string;
backgroundOpacity?: number;
space?: number;
dx?: number;
dy?: number;
lineHeight?: number | string;
};
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IRichTextListItemCharacter repeats many of the same style fields already present on IRichTextParagraphCharacter (fontSize/fill/stroke/etc.), which increases maintenance cost and risks the two types diverging. Consider defining list items as an extension of IRichTextParagraphCharacter (e.g., IRichTextParagraphCharacter & { listType: ...; ... }) rather than duplicating the style surface.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants