chore: feature merge main#1928
Conversation
…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>
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>
`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>
…sable-default-styles
…sable-default-styles
…ult-styles feat(x-markdown): add disableDefaultStyles to opt out of default tag styles
Seed output with full input for non-streaming to prevent layout jitter. Signed-off-by: Waiter <waitersong2012@gmail.com>
Signed-off-by: Waiter <waitersong2012@gmail.com>
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>
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>
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>
fix(x-markdown): avoid jank when initial streaming output is non-streaming
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 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.
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.
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.
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.
…g-newline fix(x-markdown): protect all newlines inside custom tags (#1896)
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 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 |
Bundle ReportBundle size has no change ✅ |
There was a problem hiding this comment.
Code Review
This pull request introduces a new option disableCustomTagBlockMarkdown to disable block-level Markdown parsing inside custom tags while keeping inline Markdown parsing intact. It also refactors the newline placeholder system to use Unicode Private Use Area characters to prevent them from being interpreted as Markdown syntax. The reviewer suggests optimizing the blank-line preservation logic by mapping consecutive newlines to a single placeholder instead of executing nested regex replacements for each individual newline character.
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.
| const protectedInner = innerContent.replace(/\n{2,}/g, (newlines) => | ||
| protectNewlines(newlines), | ||
| ); |
There was a problem hiding this comment.
When protecting blank-line paragraph breaks (\n\n or more), calling protectNewlines(newlines) performs a nested regex replacement for each individual newline character and creates multiple placeholders in the map.
Instead, we can map the entire sequence of newlines to a single placeholder. This avoids the nested regex replacement and reduces the overhead of the placeholders map, improving both performance and code simplicity.
| const protectedInner = innerContent.replace(/\n{2,}/g, (newlines) => | |
| protectNewlines(newlines), | |
| ); | |
| const protectedInner = innerContent.replace(/\n{2,}/g, (newlines) => { | |
| const ph = `${PLACEHOLDER_PREFIX}${placeholderIndex++}${PLACEHOLDER_SUFFIX}`; | |
| placeholders.set(ph, newlines); | |
| return ph; | |
| }); |
|
This comment is automatically generated by the x-markdown performance CI. |
Deploying ant-design-x with
|
| Latest commit: |
cbfbb9b
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://f1c3fea4.ant-design-x.pages.dev |
| Branch Preview URL: | https://feature-merge-main.ant-design-x.pages.dev |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## feature #1928 +/- ##
========================================
Coverage 97.08% 97.09%
========================================
Files 158 158
Lines 5703 5711 +8
Branches 1694 1665 -29
========================================
+ Hits 5537 5545 +8
Misses 164 164
Partials 2 2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
size-limit report 📦
|
* feat: Added right-click functionality for the Folder component (#1919) * 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 * chore: merge main to feature (#1923) * 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> * chore: merge mian to feature (#1924) * 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> * feat: merge * feat: lingxi-dev * feat: lingxi-dev * chore: feature merge main (#1927) * 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> * chore: feature merge main (#1928) * 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> --------- 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> Co-authored-by: ryker <2279549769@qq.com>
* feat: Added right-click functionality for the Folder component (#1919) * 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 * chore: merge main to feature (#1923) * 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> * chore: merge mian to feature (#1924) * 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> * feat: merge * feat: lingxi-dev * feat: lingxi-dev * chore: feature merge main (#1927) * 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> * chore: feature merge main (#1928) * 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> --------- 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> Co-authored-by: ryker <2279549769@qq.com>
* feat: Added right-click functionality for the Folder component (#1919) * 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 * chore: merge main to feature (#1923) * 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> * chore: merge mian to feature (#1924) * 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> * chore: feature merge main (#1927) * 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> * chore: feature merge main (#1928) * 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> --------- 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> Co-authored-by: ryker <2279549769@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.
* chore: main merge feature (#1929)
* feat: Added right-click functionality for the Folder component (#1919)
* 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
* chore: merge main to feature (#1923)
* 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>
* chore: merge mian to feature (#1924)
* 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>
* feat: merge
* feat: lingxi-dev
* feat: lingxi-dev
* chore: feature merge main (#1927)
* 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>
* chore: feature merge main (#1928)
* 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>
---------
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>
Co-authored-by: ryker <2279549769@qq.com>
* chore: main feature mian (#1932)
* feat: Added right-click functionality for the Folder component (#1919)
* 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
* chore: merge main to feature (#1923)
* 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>
* chore: merge mian to feature (#1924)
* 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>
* feat: merge
* feat: lingxi-dev
* feat: lingxi-dev
* chore: feature merge main (#1927)
* 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>
* chore: feature merge main (#1928)
* 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>
---------
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>
Co-authored-by: ryker <2279549769@qq.com>
* chore: Fix/sync feature with main (#1933)
* feat: Added right-click functionality for the Folder component (#1919)
* 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
* chore: merge main to feature (#1923)
* fix: fix ci
* feat: folder
* feat: folder feat
* feat: folder feat…
中文版模板 / Chinese template
🤔 This is a ...
🔗 Related Issues
💡 Background and Solution
📝 Change Log