Skip to content

chore: merge feature to main#1931

Closed
kimteayon wants to merge 5 commits into
mainfrom
feature
Closed

chore: merge feature to main#1931
kimteayon wants to merge 5 commits into
mainfrom
feature

Conversation

@kimteayon

@kimteayon kimteayon commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

中文版模板 / Chinese template

🤔 This is a ...

  • 🆕 New feature
  • 🐞 Bug fix
  • 📝 Site / documentation improvement
  • 📽️ Demo improvement
  • 💄 Component style improvement
  • 🤖 TypeScript definition improvement
  • 📦 Bundle size optimization
  • ⚡️ Performance optimization
  • ⭐️ Feature enhancement
  • 🌐 Internationalization
  • 🛠 Refactoring
  • 🎨 Code style optimization
  • ✅ Test Case
  • 🔀 Branch merge
  • ⏩ Workflow
  • ⌨️ Accessibility improvement
  • ❓ Other (about what?)

🔗 Related Issues

  • Describe the source of related requirements, such as links to relevant issue discussions.
  • For example: close #xxxx, fix #xxxx

💡 Background and Solution

  • The specific problem to be addressed.
  • List the final API implementation and usage if needed.
  • If there are UI/interaction changes, consider providing screenshots or GIFs.

📝 Change Log

Language Changelog
🇺🇸 English
🇨🇳 Chinese

Summary by CodeRabbit

发布说明

  • New Features

    • 新增 disableCustomTagBlockMarkdown 选项,禁用自定义标签内的块级 Markdown 解析,保留行内解析
    • 新增 disableDefaultStyles 配置,支持全局或按标签选择性禁用内置默认样式
    • Folder 组件新增右键菜单功能,支持全局和节点级配置
    • Folder 组件新增命令式 API 方法(getNode、updateNode、deleteNode、addNode)
  • Improvements

    • 改进自定义标签换行保护逻辑
    • 增强 DOMPurify 环保兼容性支持
    • 优化流式 Markdown 输出稳定性
  • Chores

    • 版本号更新至 2.8.0

kimteayon and others added 5 commits June 8, 2026 11:20
* feat: folder

* feat: folder feat

* feat: folder feat

* feat: folder feat

* feat: folder feat

* chore: update version

* feat: lingxi-dev

* chore: update version

* chore: update version

* feat: lingxi-dev

* feat: lingxi-dev

* chore: update version

* chore: update version

* fix: exclude .dumi directory from TypeScript type checking

* revert: restore .dumi tsconfig to original state

* chore: update version

* chore: update version

* fix: add dumi type declarations to fix lint errors

* feat: lint

* feat: lint

* feat: lint

* feat: lint
* fix: fix ci

* feat: folder

* feat: folder feat

* feat: folder feat

* feat: folder feat

* feat: folder feat

* feat(x-markdown): add disableDefaultStyles to opt out of default tag styles

Default tag styles are applied via descendant selectors on the `.x-markdown`
container (e.g. `.x-markdown ul`, `.x-markdown li`, `.x-markdown code`), so they
leak into elements rendered by custom components (such as antd `Collapse`) that
are mounted inside the container, polluting their styles.

Add a `disableDefaultStyles` prop:
- `true` disables all built-in tag styles
- an array (e.g. `['ul', 'ol', 'li']`) disables only the listed tags

Implemented purely at the view layer: the root container gets `x-md-disable-all`
or per-tag `x-md-disable-<tag>` classes, and each default rule in index.css is
gated behind `:not(.x-md-disable-all):not(.x-md-disable-<tag>)`. The descendant
selector strategy (so nested Markdown inherits defaults) is preserved; only the
opt-out is added. Parser/Renderer core is untouched.

closes #1908

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x): coerce string|number design tokens before arithmetic

CI's antd version types `fontSizeHeading1/2` tokens as `string | number`,
breaking `token.fontSizeHeading1 + 10` (TS2365) and `token.fontSizeHeading2 * 2`
(TS2362). Wrap with `Number()` so the arithmetic is valid regardless of the
token's declared type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): gate list markers by list container disable class

`list-style` on `ul > li` / `ol > li` was gated only by `:not(.x-md-disable-li)`,
so `disableDefaultStyles={['ul']}` left the bullets/numbers in place — users had
to also pass `'li'`. Also gate these selectors by the container's disable class
so disabling `ul`/`ol` removes their markers as expected, while keeping the `li`
clause (no regression) and ordered/unordered independence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: fix ci

* fix: fix ci

* fix: avoid jank when initial streaming output is non-streaming

Seed output with full input for non-streaming to prevent layout jitter.

Signed-off-by: Waiter <waitersong2012@gmail.com>

* Refactor streaming output handling in useStreaming hook

Signed-off-by: Waiter <waitersong2012@gmail.com>

* chore: update test snapshot

* test(x-markdown): fix nodeName getter for happy-dom regression

happy-dom (>= 20.10.x) returns '' from the Node.prototype.nodeName getter
for element instances. DOMPurify reads nodeName via Node.prototype, so every
element was treated as an unknown tag and stripped (keeping only text),
causing 24 Renderer streamStatus tests to fail. Restore a spec-correct
nodeName getter on Node.prototype in the jest setup. Test-env only;
real browsers and jsdom are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): guard DOMPurify against SSR (no DOM)

The streaming refactor seeds non-streaming output synchronously on first
render, so XMarkdown now renders during SSR too. DOMPurify's default export
has no `sanitize` method without a `window`, so server pre-render crashed
with "sanitize is not a function". Return null from processHtml when there
is no DOM, letting the client hydrate — same as the pre-refactor server
behavior. No new deps, no XSS exposure (server emits nothing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(x-markdown): cover SSR no-DOM guard in Renderer.processHtml

Exercise the branch where DOMPurify.sanitize is unavailable (server pre-render)
by temporarily clearing it, asserting processHtml/render return null instead of
throwing. Raises patch coverage for the SSR guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: fix outdated type name in Prompts API table (#1915)

The Prompts API documentation referenced the old type name `PromptProps`,
which has been renamed to `PromptsItemType` in the source. Update the
`items`, `onItemClick` and child item type references in both the
Chinese and English docs accordingly.

Closes #1863

* fix(x): refresh FileCard.List scroll ping state on items change (#1914)

* fix(x): refresh FileCard.List scroll ping state on items change

When Attachments uses overflow="scrollX" and items are updated from
outside (not via the internal upload flow), the scroll container's
clientWidth stays the same while only scrollWidth grows. The
ResizeObserver therefore does not fire and onScroll never happens, so
checkPing() is not called and the prev/next scroll buttons never show.

Add a useLayoutEffect that re-runs checkPing() via requestAnimationFrame
whenever the rendered list (or overflow mode) changes, covering the
controlled items-update case that ResizeObserver misses.

Closes #1911

* refactor(x): memoize checkPing with useCallback to satisfy exhaustive-deps

Address review feedback: wrap checkPing in React.useCallback (deps:
[overflow]) and add it to the useLayoutEffect dependency array so the
exhaustive-deps rule is satisfied.

* revert: drop unnecessary useCallback wrapping of checkPing

The project's biome config disables `useExhaustiveDependencies`
(see biome.json), so wrapping checkPing in useCallback to satisfy the
exhaustive-deps rule is unnecessary. Since checkPing only depends on
`overflow` (already in the effect deps), the memoization changes nothing
behaviorally. Revert to keep the code consistent with the file's style.

* chore: update version

* feat: lingxi-dev

* chore: update version

* chore: update version

* feat: lingxi-dev

* feat: lingxi-dev

* chore: update version

* chore: update version

* fix: exclude .dumi directory from TypeScript type checking

* revert: restore .dumi tsconfig to original state

* chore: update version

* chore: update version

* fix: add dumi type declarations to fix lint errors

* feat: lint

* feat: lint

* feat: lint

* feat: lint

* fix: add missing DOMPurify import in Renderer.test.ts

* feat: lint

* ci: pinned dumi version to 2.4.28 (#1922)

* feat: lingxi-dev

---------

Signed-off-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Div627 <chenyang_nn@163.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Div627 <54497462+Div627@users.noreply.github.com>
Co-authored-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Ryker_Feng <90562015+18062706139fcz@users.noreply.github.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
* fix: fix ci

* feat: folder

* feat: folder feat

* feat: folder feat

* feat: folder feat

* feat: folder feat

* feat(x-markdown): add disableDefaultStyles to opt out of default tag styles

Default tag styles are applied via descendant selectors on the `.x-markdown`
container (e.g. `.x-markdown ul`, `.x-markdown li`, `.x-markdown code`), so they
leak into elements rendered by custom components (such as antd `Collapse`) that
are mounted inside the container, polluting their styles.

Add a `disableDefaultStyles` prop:
- `true` disables all built-in tag styles
- an array (e.g. `['ul', 'ol', 'li']`) disables only the listed tags

Implemented purely at the view layer: the root container gets `x-md-disable-all`
or per-tag `x-md-disable-<tag>` classes, and each default rule in index.css is
gated behind `:not(.x-md-disable-all):not(.x-md-disable-<tag>)`. The descendant
selector strategy (so nested Markdown inherits defaults) is preserved; only the
opt-out is added. Parser/Renderer core is untouched.

closes #1908

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x): coerce string|number design tokens before arithmetic

CI's antd version types `fontSizeHeading1/2` tokens as `string | number`,
breaking `token.fontSizeHeading1 + 10` (TS2365) and `token.fontSizeHeading2 * 2`
(TS2362). Wrap with `Number()` so the arithmetic is valid regardless of the
token's declared type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): gate list markers by list container disable class

`list-style` on `ul > li` / `ol > li` was gated only by `:not(.x-md-disable-li)`,
so `disableDefaultStyles={['ul']}` left the bullets/numbers in place — users had
to also pass `'li'`. Also gate these selectors by the container's disable class
so disabling `ul`/`ol` removes their markers as expected, while keeping the `li`
clause (no regression) and ordered/unordered independence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: fix ci

* fix: fix ci

* fix: avoid jank when initial streaming output is non-streaming

Seed output with full input for non-streaming to prevent layout jitter.

Signed-off-by: Waiter <waitersong2012@gmail.com>

* Refactor streaming output handling in useStreaming hook

Signed-off-by: Waiter <waitersong2012@gmail.com>

* chore: update test snapshot

* test(x-markdown): fix nodeName getter for happy-dom regression

happy-dom (>= 20.10.x) returns '' from the Node.prototype.nodeName getter
for element instances. DOMPurify reads nodeName via Node.prototype, so every
element was treated as an unknown tag and stripped (keeping only text),
causing 24 Renderer streamStatus tests to fail. Restore a spec-correct
nodeName getter on Node.prototype in the jest setup. Test-env only;
real browsers and jsdom are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): guard DOMPurify against SSR (no DOM)

The streaming refactor seeds non-streaming output synchronously on first
render, so XMarkdown now renders during SSR too. DOMPurify's default export
has no `sanitize` method without a `window`, so server pre-render crashed
with "sanitize is not a function". Return null from processHtml when there
is no DOM, letting the client hydrate — same as the pre-refactor server
behavior. No new deps, no XSS exposure (server emits nothing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(x-markdown): cover SSR no-DOM guard in Renderer.processHtml

Exercise the branch where DOMPurify.sanitize is unavailable (server pre-render)
by temporarily clearing it, asserting processHtml/render return null instead of
throwing. Raises patch coverage for the SSR guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: fix outdated type name in Prompts API table (#1915)

The Prompts API documentation referenced the old type name `PromptProps`,
which has been renamed to `PromptsItemType` in the source. Update the
`items`, `onItemClick` and child item type references in both the
Chinese and English docs accordingly.

Closes #1863

* fix(x): refresh FileCard.List scroll ping state on items change (#1914)

* fix(x): refresh FileCard.List scroll ping state on items change

When Attachments uses overflow="scrollX" and items are updated from
outside (not via the internal upload flow), the scroll container's
clientWidth stays the same while only scrollWidth grows. The
ResizeObserver therefore does not fire and onScroll never happens, so
checkPing() is not called and the prev/next scroll buttons never show.

Add a useLayoutEffect that re-runs checkPing() via requestAnimationFrame
whenever the rendered list (or overflow mode) changes, covering the
controlled items-update case that ResizeObserver misses.

Closes #1911

* refactor(x): memoize checkPing with useCallback to satisfy exhaustive-deps

Address review feedback: wrap checkPing in React.useCallback (deps:
[overflow]) and add it to the useLayoutEffect dependency array so the
exhaustive-deps rule is satisfied.

* revert: drop unnecessary useCallback wrapping of checkPing

The project's biome config disables `useExhaustiveDependencies`
(see biome.json), so wrapping checkPing in useCallback to satisfy the
exhaustive-deps rule is unnecessary. Since checkPing only depends on
`overflow` (already in the effect deps), the memoization changes nothing
behaviorally. Revert to keep the code consistent with the file's style.

* chore: update version

* feat: lingxi-dev

* chore: update version

* chore: update version

* feat: lingxi-dev

* feat: lingxi-dev

* chore: update version

* chore: update version

* fix: exclude .dumi directory from TypeScript type checking

* revert: restore .dumi tsconfig to original state

* chore: update version

* chore: update version

* fix: add dumi type declarations to fix lint errors

* feat: lint

* feat: lint

* feat: lint

* feat: lint

* fix: add missing DOMPurify import in Renderer.test.ts

* feat: lint

* ci: pinned dumi version to 2.4.28 (#1922)

* feat: lingxi-dev

* chore: merge

---------

Signed-off-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Div627 <chenyang_nn@163.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Div627 <54497462+Div627@users.noreply.github.com>
Co-authored-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Ryker_Feng <90562015+18062706139fcz@users.noreply.github.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
* fix: fix ci

* feat(x-markdown): add disableDefaultStyles to opt out of default tag styles

Default tag styles are applied via descendant selectors on the `.x-markdown`
container (e.g. `.x-markdown ul`, `.x-markdown li`, `.x-markdown code`), so they
leak into elements rendered by custom components (such as antd `Collapse`) that
are mounted inside the container, polluting their styles.

Add a `disableDefaultStyles` prop:
- `true` disables all built-in tag styles
- an array (e.g. `['ul', 'ol', 'li']`) disables only the listed tags

Implemented purely at the view layer: the root container gets `x-md-disable-all`
or per-tag `x-md-disable-<tag>` classes, and each default rule in index.css is
gated behind `:not(.x-md-disable-all):not(.x-md-disable-<tag>)`. The descendant
selector strategy (so nested Markdown inherits defaults) is preserved; only the
opt-out is added. Parser/Renderer core is untouched.

closes #1908

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x): coerce string|number design tokens before arithmetic

CI's antd version types `fontSizeHeading1/2` tokens as `string | number`,
breaking `token.fontSizeHeading1 + 10` (TS2365) and `token.fontSizeHeading2 * 2`
(TS2362). Wrap with `Number()` so the arithmetic is valid regardless of the
token's declared type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): gate list markers by list container disable class

`list-style` on `ul > li` / `ol > li` was gated only by `:not(.x-md-disable-li)`,
so `disableDefaultStyles={['ul']}` left the bullets/numbers in place — users had
to also pass `'li'`. Also gate these selectors by the container's disable class
so disabling `ul`/`ol` removes their markers as expected, while keeping the `li`
clause (no regression) and ordered/unordered independence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: fix ci

* fix: fix ci

* fix: avoid jank when initial streaming output is non-streaming

Seed output with full input for non-streaming to prevent layout jitter.

Signed-off-by: Waiter <waitersong2012@gmail.com>

* Refactor streaming output handling in useStreaming hook

Signed-off-by: Waiter <waitersong2012@gmail.com>

* chore: update test snapshot

* test(x-markdown): fix nodeName getter for happy-dom regression

happy-dom (>= 20.10.x) returns '' from the Node.prototype.nodeName getter
for element instances. DOMPurify reads nodeName via Node.prototype, so every
element was treated as an unknown tag and stripped (keeping only text),
causing 24 Renderer streamStatus tests to fail. Restore a spec-correct
nodeName getter on Node.prototype in the jest setup. Test-env only;
real browsers and jsdom are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): guard DOMPurify against SSR (no DOM)

The streaming refactor seeds non-streaming output synchronously on first
render, so XMarkdown now renders during SSR too. DOMPurify's default export
has no `sanitize` method without a `window`, so server pre-render crashed
with "sanitize is not a function". Return null from processHtml when there
is no DOM, letting the client hydrate — same as the pre-refactor server
behavior. No new deps, no XSS exposure (server emits nothing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(x-markdown): cover SSR no-DOM guard in Renderer.processHtml

Exercise the branch where DOMPurify.sanitize is unavailable (server pre-render)
by temporarily clearing it, asserting processHtml/render return null instead of
throwing. Raises patch coverage for the SSR guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: fix outdated type name in Prompts API table (#1915)

The Prompts API documentation referenced the old type name `PromptProps`,
which has been renamed to `PromptsItemType` in the source. Update the
`items`, `onItemClick` and child item type references in both the
Chinese and English docs accordingly.

Closes #1863

* fix(x): refresh FileCard.List scroll ping state on items change (#1914)

* fix(x): refresh FileCard.List scroll ping state on items change

When Attachments uses overflow="scrollX" and items are updated from
outside (not via the internal upload flow), the scroll container's
clientWidth stays the same while only scrollWidth grows. The
ResizeObserver therefore does not fire and onScroll never happens, so
checkPing() is not called and the prev/next scroll buttons never show.

Add a useLayoutEffect that re-runs checkPing() via requestAnimationFrame
whenever the rendered list (or overflow mode) changes, covering the
controlled items-update case that ResizeObserver misses.

Closes #1911

* refactor(x): memoize checkPing with useCallback to satisfy exhaustive-deps

Address review feedback: wrap checkPing in React.useCallback (deps:
[overflow]) and add it to the useLayoutEffect dependency array so the
exhaustive-deps rule is satisfied.

* revert: drop unnecessary useCallback wrapping of checkPing

The project's biome config disables `useExhaustiveDependencies`
(see biome.json), so wrapping checkPing in useCallback to satisfy the
exhaustive-deps rule is unnecessary. Since checkPing only depends on
`overflow` (already in the effect deps), the memoization changes nothing
behaviorally. Revert to keep the code consistent with the file's style.

* ci: pinned dumi version to 2.4.28 (#1922)

* docs: cache chat provider with useRef in x-conversations demos (#1925)

The provider cache Map was created inside the component body, so it was
re-created on every render and never actually cached the provider. As a
result useXChat's requestHandlerRef pointed at a freshly-built provider
whose request had never run, making abort() throw and unable to cancel the
in-flight request when stopping a streaming response.

Persist the cache with useRef so the provider instance stays stable across
renders, aligning with the existing session-key demo. Fixes #1833.

* feat: merge

* feat: lingxi-dev

* feat: lingxi-dev

---------

Signed-off-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Div627 <chenyang_nn@163.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Div627 <54497462+Div627@users.noreply.github.com>
Co-authored-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Ryker_Feng <90562015+18062706139fcz@users.noreply.github.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
* fix: fix ci

* feat(x-markdown): add disableDefaultStyles to opt out of default tag styles

Default tag styles are applied via descendant selectors on the `.x-markdown`
container (e.g. `.x-markdown ul`, `.x-markdown li`, `.x-markdown code`), so they
leak into elements rendered by custom components (such as antd `Collapse`) that
are mounted inside the container, polluting their styles.

Add a `disableDefaultStyles` prop:
- `true` disables all built-in tag styles
- an array (e.g. `['ul', 'ol', 'li']`) disables only the listed tags

Implemented purely at the view layer: the root container gets `x-md-disable-all`
or per-tag `x-md-disable-<tag>` classes, and each default rule in index.css is
gated behind `:not(.x-md-disable-all):not(.x-md-disable-<tag>)`. The descendant
selector strategy (so nested Markdown inherits defaults) is preserved; only the
opt-out is added. Parser/Renderer core is untouched.

closes #1908

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x): coerce string|number design tokens before arithmetic

CI's antd version types `fontSizeHeading1/2` tokens as `string | number`,
breaking `token.fontSizeHeading1 + 10` (TS2365) and `token.fontSizeHeading2 * 2`
(TS2362). Wrap with `Number()` so the arithmetic is valid regardless of the
token's declared type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): gate list markers by list container disable class

`list-style` on `ul > li` / `ol > li` was gated only by `:not(.x-md-disable-li)`,
so `disableDefaultStyles={['ul']}` left the bullets/numbers in place — users had
to also pass `'li'`. Also gate these selectors by the container's disable class
so disabling `ul`/`ol` removes their markers as expected, while keeping the `li`
clause (no regression) and ordered/unordered independence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: fix ci

* fix: fix ci

* fix: avoid jank when initial streaming output is non-streaming

Seed output with full input for non-streaming to prevent layout jitter.

Signed-off-by: Waiter <waitersong2012@gmail.com>

* Refactor streaming output handling in useStreaming hook

Signed-off-by: Waiter <waitersong2012@gmail.com>

* chore: update test snapshot

* test(x-markdown): fix nodeName getter for happy-dom regression

happy-dom (>= 20.10.x) returns '' from the Node.prototype.nodeName getter
for element instances. DOMPurify reads nodeName via Node.prototype, so every
element was treated as an unknown tag and stripped (keeping only text),
causing 24 Renderer streamStatus tests to fail. Restore a spec-correct
nodeName getter on Node.prototype in the jest setup. Test-env only;
real browsers and jsdom are unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(x-markdown): guard DOMPurify against SSR (no DOM)

The streaming refactor seeds non-streaming output synchronously on first
render, so XMarkdown now renders during SSR too. DOMPurify's default export
has no `sanitize` method without a `window`, so server pre-render crashed
with "sanitize is not a function". Return null from processHtml when there
is no DOM, letting the client hydrate — same as the pre-refactor server
behavior. No new deps, no XSS exposure (server emits nothing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(x-markdown): cover SSR no-DOM guard in Renderer.processHtml

Exercise the branch where DOMPurify.sanitize is unavailable (server pre-render)
by temporarily clearing it, asserting processHtml/render return null instead of
throwing. Raises patch coverage for the SSR guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: fix outdated type name in Prompts API table (#1915)

The Prompts API documentation referenced the old type name `PromptProps`,
which has been renamed to `PromptsItemType` in the source. Update the
`items`, `onItemClick` and child item type references in both the
Chinese and English docs accordingly.

Closes #1863

* fix(x): refresh FileCard.List scroll ping state on items change (#1914)

* fix(x): refresh FileCard.List scroll ping state on items change

When Attachments uses overflow="scrollX" and items are updated from
outside (not via the internal upload flow), the scroll container's
clientWidth stays the same while only scrollWidth grows. The
ResizeObserver therefore does not fire and onScroll never happens, so
checkPing() is not called and the prev/next scroll buttons never show.

Add a useLayoutEffect that re-runs checkPing() via requestAnimationFrame
whenever the rendered list (or overflow mode) changes, covering the
controlled items-update case that ResizeObserver misses.

Closes #1911

* refactor(x): memoize checkPing with useCallback to satisfy exhaustive-deps

Address review feedback: wrap checkPing in React.useCallback (deps:
[overflow]) and add it to the useLayoutEffect dependency array so the
exhaustive-deps rule is satisfied.

* revert: drop unnecessary useCallback wrapping of checkPing

The project's biome config disables `useExhaustiveDependencies`
(see biome.json), so wrapping checkPing in useCallback to satisfy the
exhaustive-deps rule is unnecessary. Since checkPing only depends on
`overflow` (already in the effect deps), the memoization changes nothing
behaviorally. Revert to keep the code consistent with the file's style.

* fix(x-markdown): protect all newlines inside custom tags (#1896)

Custom tag inner content is treated as opaque text, but the protection
logic only escaped blank lines (`\n\n`). Single newlines followed by
block-level markdown (ordered/unordered lists, headings) were still
parsed by marked, splitting the custom tag structure (e.g. the closing
`</think>` was pulled into an `<li>`).

Now every newline inside a custom tag is protected. Placeholders use
Unicode Private Use Area sentinels instead of `__...__` so they are not
interpreted as markdown emphasis when adjacent to text.

* fix(x-markdown): split full-newline protection into a separate flag

Protecting every newline inside custom tags changed the behavior of the
existing `protectCustomTagNewlines` flag: block-level markdown (lists,
headings, quotes) that used to render inside custom tags became opaque
text, which is a breaking change for current users.

Restore `protectCustomTagNewlines` to its original semantics (only
protect blank-line paragraph breaks) and add a new opt-in flag
`protectAllCustomTagNewlines` that protects every newline. Both default
to false so existing behavior is unchanged.

* ci: pinned dumi version to 2.4.28 (#1922)

* refactor(x-markdown): clarify custom tag block markdown option

* refactor(x-markdown): align internal flag name with public option

* docs: cache chat provider with useRef in x-conversations demos (#1925)

The provider cache Map was created inside the component body, so it was
re-created on every render and never actually cached the provider. As a
result useXChat's requestHandlerRef pointed at a freshly-built provider
whose request had never run, making abort() throw and unable to cancel the
in-flight request when stopping a streaming response.

Persist the cache with useRef so the provider instance stays stable across
renders, aligning with the existing session-key demo. Fixes #1833.

* feat: merge

* feat: lingxi-dev

* feat: lingxi-dev

---------

Signed-off-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Div627 <chenyang_nn@163.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Div627 <54497462+Div627@users.noreply.github.com>
Co-authored-by: Waiter <waitersong2012@gmail.com>
Co-authored-by: Ryker_Feng <90562015+18062706139fcz@users.noreply.github.com>
Co-authored-by: ryker <2279549769@qq.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

变更总览

本 PR 为 v2.8.0 版本发布,核心在于:为 XMarkdown 组件新增自定义标签块级 Markdown 解析控制与默认样式门控系统;为 Folder 组件添加右键菜单与完整的树形编程接口(含节点查询、更新、删除、新增);优化 FileCard 的滚动 ping 刷新与 SDK 演示的 provider 缓存持久化;完成全仓版本更新与构建配置调整。

变更详情

XMarkdown Markdown 处理与样式系统

层次 / 文件 摘要
Parser 自定义标签块级 Markdown 控制
packages/x-markdown/src/XMarkdown/core/Parser.ts
ParserOptions 新增 disableCustomTagBlockMarkdown 选项,通过 Unicode PUA 占位符机制强力保护自定义标签内换行与段落边界,避免块级 Markdown 意外解析。
Renderer DOMPurify 环境修补与 SSR 防护
packages/x-markdown/src/XMarkdown/core/Renderer.ts, packages/x-markdown/tests/setup.ts
新增 createPatchedDOMPurify() 逻辑修补 happy-dom 环境的 nodeName getter 异常,在 SSR/无 DOM 场景下对 DOMPurify.sanitize 进行防护。
默认样式门控与 CSS 更新
packages/x-markdown/src/XMarkdown/interface.ts, packages/x-markdown/src/XMarkdown/index.css
引入 DefaultStyleTag 类型与 disableDefaultStyles 配置,通过 :not(.x-md-disable-*) CSS 选择器对标签样式进行条件渲染,避免样式污染自定义组件。
流式输出缓存优化
packages/x-markdown/src/XMarkdown/hooks/useStreaming.ts
新增 streamingOutput 状态分离缓存与非缓存路径,改善流式增量处理稳定性,避免首帧抖动。
XMarkdown 组件集成与 Props 传递
packages/x-markdown/src/XMarkdown/index.tsx
解构与传递 disableCustomTagBlockMarkdowndisableDefaultStyles,计算禁用样式类名并更新 Parser 配置与依赖。
XMarkdown 测试用例扩展
packages/x-markdown/src/XMarkdown/__tests__/*
新增 44-158 行测试覆盖 Parser/Renderer/主组件的自定义标签保护、块级 Markdown 禁用、默认样式门控、DOMPurify 修补与 SSR 等多路径验证。
XMarkdown 文档与技能描述
packages/x-skill/skills-*/x-markdown/reference/API.md, packages/x-skill/skills-*/x-markdown/reference/EXTENSIONS.md
更新 protectCustomTagNewlines 描述,新增 disableCustomTagBlockMarkdowndisableDefaultStyles 配置说明。
Jest 与测试环境配置
packages/x-markdown/.jest.js, packages/x-markdown/tests/setup.ts
Jest 配置新增 markedcompileModules,测试环境初始化修复 happy-dom nodeName getter 异常。

Folder 组件右键菜单与树形编程接口

层次 / 文件 摘要
DirectoryTree 右键菜单处理
packages/x/components/folder/DirectoryTree.tsx
新增 contextMenuonRightClicknodeDataMapRef 与右键拦截逻辑,支持全局与节点级菜单配置优先级,通过 Dropdown 实现菜单显示。
Folder 组件树形编程接口扩展
packages/x/components/folder/index.tsx
在 FolderProps 中新增 contextMenuonRightClick,扩展 FolderRefgetNodeupdateNodedeleteNodeaddNode 等不可变树操作方法集合。
Folder 右键菜单演示与文档
packages/x/components/folder/demo/context-menu.tsx, packages/x/components/folder/index.*.md
新增完整演示组件展示菜单与树形操作流程,在双语文档中补充 API 说明与 Ref Methods 章节。
Folder 右键菜单与树形操作测试
packages/x/components/folder/__tests__/index.test.tsx
新增 1256 行测试覆盖菜单渲染、禁用、回调、FolderRef 方法的路径定位与不可变性,及大量分支覆盖。
组件导出更新
packages/x/components/index.ts
扩展 folder 的类型导出,新增 FolderRefFolderTreeData

文件卡、SDK 演示及其他组件改进

层次 / 文件 摘要
FileCard 滚动 ping 异步刷新
packages/x/components/file-card/List.tsx, packages/x/components/file-card/__tests__/index.test.tsx
新增 useLayoutEffect 通过 requestAnimationFrame 在 overflow 非 wrap 状态下刷新 ping 状态;调整 ResizeObserver mock 并补充异步断言用例。
SDK 会话 Provider 缓存持久化
packages/x/docs/x-sdk/demos/x-conversations/async-defaultMessages.tsx, with-x-chat.tsx
DeepSeekChatProvider 缓存从局部 Map 改为 useRef 持久化,实现跨渲染复用。
其他小量改进
packages/x/components/prompts/index.*.md, packages/x/docs/x-markdown/demo/streaming/format.tsx, packages/x/components/attachments/util.ts, packages/x/typings/custom-typings.d.ts
Prompts 文档类型重命名,markdown demo 可选链优化,attachments 可空判断优化,Dumi 类型声明补充。

版本更新与构建配置

层次 / 文件 摘要
包版本号更新
package.json, packages/x-*/package.json, packages/x-skill/skills-*/SKILL.md, packages/x-skill/src/skill-meta.json
主包与各子包版本从 2.7.0 更新为 2.8.0,skill-meta.json 从 2.6.0 更新为 2.9.0,技能文档同步更新。
构建与编译配置调整
.gitignore, biome.json, packages/x/.dumi/tsconfig.json, packages/x/tsconfig.json, packages/x/package.json, packages/x/typings/custom-typings.d.ts
新增 .codefuse 忽略规则,narrowing TypeScript 编译范围,relaxing .dumi 目录编译配置,升级 dumi 至 2.4.28,补充 Dumi 类型声明。

🎯 4 (Complex) | ⏱️ ~50 minutes

相关 PR

  • ant-design/x#1909:同样为 XMarkdown 添加 disableDefaultStyles 与样式门控系统。
  • ant-design/x#1917:同步修改 useStreaming 流式输出与 Renderer SSR 防护。
  • ant-design/x#1920:同样在 Parser 中添加自定义标签块级 Markdown 保护与占位符机制。
  • ant-design/x#1925:同步优化 SDK 演示中的 provider 缓存持久化。
  • ant-design/x#1914:同样为 FileCard 添加 useLayoutEffect ping 刷新逻辑。

建议标签

enhancement, javascript, lgtm

建议审阅者

  • Div627

诗歌

🐰 版本新至 2.8,XMarkdown 更显能,
菜单绽放右键间,树形编程触手前,
样式门控护自定,流式缓存更稳贞。

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 标题过于宽泛,仅表示"合并",未能清晰传达涉及Folder菜单、样式禁用等主要变更内容。 建议使用更具体的标题,例如:'feat: add folder context menu and x-markdown customization'。
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request bumps package versions to 2.8.0 and introduces several enhancements, notably adding a right-click context menu feature and ref helper methods (getNode, updateNode, deleteNode, addNode) to the Folder component, alongside a new disableCustomTagBlockMarkdown option and a disableDefaultStyles prop in XMarkdown. Feedback on these changes highlights a few key issues in the new Folder implementation: first, addNode fails to support adding nodes to the root directory when parentPath is empty; second, using isRightClickRef to track right-click state is prone to race conditions and should be replaced by inspecting the event type directly; and third, nodeDataMapRef is never cleared when treeData updates, leading to potential memory leaks and stale keys.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +215 to +216
addNode: (parentPath: string[], node: FolderTreeData) =>
treeData ? walkTree(treeData, parentPath, 0, 'add', node) : [],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

When parentPath is empty ([]), walkTree will not match any node and will return the original treeData unchanged. This prevents users from adding new files or folders to the root directory of the tree. Handling parentPath.length === 0 as a special case to append the node directly to the root array resolves this issue.

    addNode: (parentPath: string[], node: FolderTreeData) => {
      if (!treeData) return [];
      if (parentPath.length === 0) {
        return [...treeData, node];
      }
      return walkTree(treeData, parentPath, 0, 'add', node);
    },

Comment on lines +191 to +198
// Intercept onSelect to skip selection triggered by right-click
const handleSelect: TreeProps['onSelect'] = (keys, info) => {
if (isRightClickRef.current) {
isRightClickRef.current = false;
return;
}
onSelect?.(keys, info);
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using a mutable ref (isRightClickRef) to track right-click state across asynchronous event loops is prone to race conditions. For example, if a user left-clicks a node while the context menu is open, handleSelect may run before handleContextMenuOpenChange resets the flag, causing the left-click to be ignored.

A more robust and standard approach is to inspect the triggering event type directly in handleSelect and skip selection if it is a contextmenu event. This completely eliminates the need for isRightClickRef and its associated cleanup logic.

  // Intercept onSelect to skip selection triggered by right-click
  const handleSelect: TreeProps['onSelect'] = (keys, info) => {
    if (info.event?.type === 'contextmenu') {
      return;
    }
    onSelect?.(keys, info);
  };

Comment on lines 121 to 128
return nodes.map((node) => {
const pathSegments = buildPathSegments(node, parentSegments);
const fullPath = pathSegments.join('/').replace(/^\/+/, '');
// Store original node data for context menu lookup
nodeDataMapRef.current.set(fullPath, node);
return {
...node,
key: fullPath,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Storing node data in nodeDataMapRef during render without clearing it when treeData changes leads to a memory leak and stale keys (e.g., deleted or renamed nodes will remain in the map indefinitely).

To fix this, ensure nodeDataMapRef.current.clear() is called at the beginning of the tree conversion process (e.g., inside the useMemo that computes treeDataConverted or at the root level of the recursive mapping function).

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Performance benchmark report not found.


This comment is automatically generated by the x-markdown performance CI.

@kimteayon kimteayon closed this Jun 8, 2026
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size
packages/x/dist/antdx.min.js 510.62 KB
packages/x-sdk/dist/x-sdk.min.js 55.66 KB
packages/x-markdown/dist/x-markdown.min.js 33.8 KB
packages/x-markdown/dist/plugins/latex.min.js 61.91 KB

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/ant-design/x/issues/comments/4646966984","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/ant-design/x/pull/1931?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Repository UI\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro\n> \n> **Run ID**: `8352c28c-4784-437c-80a9-b5ede4b44bd4`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between a270320be63caf99c67b386010fae14707d7f81e and c3dbf32cea3f2d079e79ebc0fe5c262ab18dc347.\n> \n> </details>\n> \n> <details>\n> <summary>⛔ Files ignored due to path filters (1)</summary>\n> \n> * `packages/x/components/bubble/__tests__/__snapshots__/demo.test.ts.snap` is excluded by `!**/*.snap`\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (61)</summary>\n> \n> * `.gitignore`\n> * `biome.json`\n> * `package.json`\n> * `packages/x-card/package.json`\n> * `packages/x-card/src/A2UI/utils.ts`\n> * `packages/x-card/src/version.ts`\n> * `packages/x-markdown/.jest.js`\n> * `packages/x-markdown/package.json`\n> * `packages/x-markdown/src/XMarkdown/__tests__/Parser.test.ts`\n> * `packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts`\n> * `packages/x-markdown/src/XMarkdown/__tests__/index.test.tsx`\n> * `packages/x-markdown/src/XMarkdown/core/Parser.ts`\n> * `packages/x-markdown/src/XMarkdown/core/Renderer.ts`\n> * `packages/x-markdown/src/XMarkdown/hooks/useStreaming.ts`\n> * `packages/x-markdown/src/XMarkdown/index.css`\n> * `packages/x-markdown/src/XMarkdown/index.tsx`\n> * `packages/x-markdown/src/XMarkdown/interface.ts`\n> * `packages/x-markdown/tests/setup.ts`\n> * `packages/x-sdk/package.json`\n> * `packages/x-skill/.claude-plugin/marketplace.json`\n> * `packages/x-skill/package.json`\n> * `packages/x-skill/skills-zh/use-x-chat/SKILL.md`\n> * `packages/x-skill/skills-zh/x-card/SKILL.md`\n> * `packages/x-skill/skills-zh/x-chat-provider/SKILL.md`\n> * `packages/x-skill/skills-zh/x-components/SKILL.md`\n> * `packages/x-skill/skills-zh/x-markdown/SKILL.md`\n> * `packages/x-skill/skills-zh/x-markdown/reference/API.md`\n> * `packages/x-skill/skills-zh/x-markdown/reference/EXTENSIONS.md`\n> * `packages/x-skill/skills-zh/x-request/SKILL.md`\n> * `packages/x-skill/skills/use-x-chat/SKILL.md`\n> * `packages/x-skill/skills/x-card/SKILL.md`\n> * `packages/x-skill/skills/x-chat-provider/SKILL.md`\n> * `packages/x-skill/skills/x-components/SKILL.md`\n> * `packages/x-skill/skills/x-markdown/SKILL.md`\n> * `packages/x-skill/skills/x-markdown/reference/API.md`\n> * `packages/x-skill/skills/x-markdown/reference/EXTENSIONS.md`\n> * `packages/x-skill/skills/x-request/SKILL.md`\n> * `packages/x-skill/src/skill-meta.json`\n> * `packages/x/.dumi/tsconfig.json`\n> * `packages/x/components/attachments/util.ts`\n> * `packages/x/components/file-card/List.tsx`\n> * `packages/x/components/file-card/__tests__/index.test.tsx`\n> * `packages/x/components/folder/DirectoryTree.tsx`\n> * `packages/x/components/folder/__tests__/index.test.tsx`\n> * `packages/x/components/folder/demo/context-menu.md`\n> * `packages/x/components/folder/demo/context-menu.tsx`\n> * `packages/x/components/folder/index.en-US.md`\n> * `packages/x/components/folder/index.tsx`\n> * `packages/x/components/folder/index.zh-CN.md`\n> * `packages/x/components/index.ts`\n> * `packages/x/components/prompts/index.en-US.md`\n> * `packages/x/components/prompts/index.zh-CN.md`\n> * `packages/x/docs/x-markdown/demo/streaming/format.tsx`\n> * `packages/x/docs/x-markdown/examples.en-US.md`\n> * `packages/x/docs/x-markdown/examples.zh-CN.md`\n> * `packages/x/docs/x-sdk/demos/chat-providers/custom-provider-width-ui.tsx`\n> * `packages/x/docs/x-sdk/demos/x-conversations/async-defaultMessages.tsx`\n> * `packages/x/docs/x-sdk/demos/x-conversations/with-x-chat.tsx`\n> * `packages/x/package.json`\n> * `packages/x/tsconfig.json`\n> * `packages/x/typings/custom-typings.d.ts`\n> \n> </details>\n> \n> ```ascii\n>  _____________________________________________\n> < You shall not pass...without a code review! >\n>  ---------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `feature`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ant-design/x&utm_content=1931)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

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.

1 participant