Conversation
* 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>
|
Caution Review failedPull request was closed or merged during review 📝 Walkthrough变更总览本 PR 为 v2.8.0 版本发布,核心在于:为 XMarkdown 组件新增自定义标签块级 Markdown 解析控制与默认样式门控系统;为 Folder 组件添加右键菜单与完整的树形编程接口(含节点查询、更新、删除、新增);优化 FileCard 的滚动 ping 刷新与 SDK 演示的 provider 缓存持久化;完成全仓版本更新与构建配置调整。 变更详情XMarkdown Markdown 处理与样式系统
Folder 组件右键菜单与树形编程接口
文件卡、SDK 演示及其他组件改进
版本更新与构建配置
🎯 4 (Complex) | ⏱️ ~50 minutes 相关 PR
建议标签
建议审阅者
诗歌
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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.
| addNode: (parentPath: string[], node: FolderTreeData) => | ||
| treeData ? walkTree(treeData, parentPath, 0, 'add', node) : [], |
There was a problem hiding this comment.
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);
},
| // 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); | ||
| }; |
There was a problem hiding this comment.
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);
};
| 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, |
There was a problem hiding this comment.
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).
|
This comment is automatically generated by the x-markdown performance CI. |
size-limit report 📦
|
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
中文版模板 / Chinese template
🤔 This is a ...
🔗 Related Issues
💡 Background and Solution
📝 Change Log
Summary by CodeRabbit
发布说明
New Features
disableCustomTagBlockMarkdown选项,禁用自定义标签内的块级 Markdown 解析,保留行内解析disableDefaultStyles配置,支持全局或按标签选择性禁用内置默认样式Improvements
Chores