From 9ee5a53d8c0b3bbf750f241dfbd6fa06cfd67c6c Mon Sep 17 00:00:00 2001 From: tsukistar Date: Thu, 10 Jul 2025 22:31:26 +0800 Subject: [PATCH 1/5] refactor(theme-default): refactor mediumZoom as in getCustomMDXComponent --- .../layout/DocLayout/docComponents/img.tsx | 36 +++++++++++++++++++ .../DocLayout/docComponents/index.module.scss | 5 +++ .../layout/DocLayout/docComponents/index.tsx | 3 +- 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx b/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx index 0e547192b..12eca4743 100644 --- a/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx +++ b/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx @@ -1,6 +1,42 @@ import { normalizeImagePath } from '@rspress/runtime'; +import mediumZoom from 'medium-zoom'; +import type React from 'react'; import type { ComponentProps } from 'react'; +import { useCallback, useEffect, useRef } from 'react'; export const Img = (props: ComponentProps<'img'>) => { return ; }; + +export const ImgZoom = ({ + ref: refProp, + ...props +}: ComponentProps<'img'> & { ref?: React.Ref }) => { + const imgRef = useRef(null); + const combinedRef = useCallback( + (node: HTMLImageElement) => { + if (refProp) { + if (typeof refProp === 'function') { + refProp(node); + } else { + refProp.current = node; + } + } + imgRef.current = node; + }, + [refProp], + ); + + useEffect(() => { + if (!imgRef.current) return; + const zoom = mediumZoom(imgRef.current, { + background: 'var(--rp-c-bg)', + }); + + return () => { + zoom.detach(); + }; + }, []); + + return ; +}; diff --git a/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss b/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss index 2e0c9ba85..0a2bd2d07 100644 --- a/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss +++ b/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss @@ -63,6 +63,11 @@ } } +.medium-zoom-overlay, +.medium-zoom-image--opened { + z-index: 999; +} + :global(.header-anchor) { color: var(--rp-c-brand); } diff --git a/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx b/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx index 82f8bcf23..dde0fa516 100644 --- a/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx +++ b/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx @@ -1,7 +1,7 @@ import { A } from './a'; import { Code } from './code'; import { Hr } from './hr'; -import { Img } from './img'; +import { Img, ImgZoom } from './img'; import { Li, Ol, Ul } from './list'; import { Blockquote, P, Strong } from './paragraph'; import { PreWithCodeButtonGroup } from './pre'; @@ -31,5 +31,6 @@ export function getCustomMDXComponent() { code: Code, pre: PreWithCodeButtonGroup, img: Img, + imgZoom: ImgZoom, }; } From 9b6b107173576c65e244388c629f546a6861fdf1 Mon Sep 17 00:00:00 2001 From: tsukistar Date: Thu, 10 Jul 2025 22:57:58 +0800 Subject: [PATCH 2/5] fix(theme-default): add dependency "medium-zoom" in package.json --- packages/theme-default/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/theme-default/package.json b/packages/theme-default/package.json index 4af25e1c7..d9b891144 100644 --- a/packages/theme-default/package.json +++ b/packages/theme-default/package.json @@ -47,6 +47,7 @@ "github-slugger": "^2.0.0", "hast-util-to-jsx-runtime": "^2.3.6", "lodash-es": "^4.17.21", + "medium-zoom": "1.1.0", "nprogress": "^0.2.0", "react": "^19.1.0", "react-dom": "^19.1.0", From 6b72fd4919c82700c680b2360173cb7be565a012 Mon Sep 17 00:00:00 2001 From: tsukistar Date: Thu, 10 Jul 2025 23:07:41 +0800 Subject: [PATCH 3/5] fix(theme-default): update the pnpm-lock.yaml --- pnpm-lock.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bd7b5765..71f42aa6b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1660,6 +1660,9 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 + medium-zoom: + specifier: 1.1.0 + version: 1.1.0 nprogress: specifier: ^0.2.0 version: 0.2.0 From 070b4c9fb101cc5b59e69b38a073e9997a79851b Mon Sep 17 00:00:00 2001 From: tsukistar Date: Tue, 15 Jul 2025 20:16:15 +0800 Subject: [PATCH 4/5] refactor(theme-default)!: replace 'medium-zoom' with 'react-medium-image-zoom' and refactor configuration - Replace 'medium-zoom' library with 'react-medium-image-zoom' - Refactor 'mediumZoom' configuration to use process.env for conditional component selection - Update Img/ImgZoom component mapping logic --- packages/core/src/node/PluginDriver.ts | 9 ---- packages/core/src/node/initRsbuild.ts | 8 ++++ packages/shared/package.json | 1 + packages/shared/src/types/index.ts | 6 +-- packages/theme-default/package.json | 2 +- .../layout/DocLayout/docComponents/img.tsx | 42 ++++--------------- .../layout/DocLayout/docComponents/index.tsx | 3 +- pnpm-lock.yaml | 20 +++++++-- 8 files changed, 40 insertions(+), 51 deletions(-) diff --git a/packages/core/src/node/PluginDriver.ts b/packages/core/src/node/PluginDriver.ts index ec07a2cd0..1e007a3f6 100644 --- a/packages/core/src/node/PluginDriver.ts +++ b/packages/core/src/node/PluginDriver.ts @@ -46,19 +46,10 @@ export class PluginDriver { const enableLastUpdated = themeConfig?.lastUpdated || themeConfig?.locales?.some(locale => locale.lastUpdated); - const mediumZoomConfig = config?.mediumZoom ?? true; if (enableLastUpdated) { const { pluginLastUpdated } = await import('./last-updated/index'); this.addPlugin(pluginLastUpdated()); } - if (mediumZoomConfig) { - const { pluginMediumZoom } = await import('./medium-zoom/index'); - this.addPlugin( - pluginMediumZoom( - typeof mediumZoomConfig === 'object' ? mediumZoomConfig : undefined, - ), - ); - } (config.plugins || []).forEach(plugin => { this.addPlugin(plugin); diff --git a/packages/core/src/node/initRsbuild.ts b/packages/core/src/node/initRsbuild.ts index 8b5b014f5..93299cb1b 100644 --- a/packages/core/src/node/initRsbuild.ts +++ b/packages/core/src/node/initRsbuild.ts @@ -226,6 +226,14 @@ async function createInternalBuildConfig( 'process.env.RSPRESS_SOCIAL_ICONS': JSON.stringify( getSocialIcons(config.themeConfig?.socialLinks), ), + 'process.env.MEDIUM_ZOOM': + typeof config.mediumZoom === 'object' + ? config.mediumZoom.isZoom + : !!config.mediumZoom, + 'process.env.MEDIUM_ZOOM_OPTIONS': + typeof config.mediumZoom === 'object' + ? JSON.stringify(config.mediumZoom.options) + : '', }, }, performance: { diff --git a/packages/shared/package.json b/packages/shared/package.json index 96162d686..72adf62ca 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -41,6 +41,7 @@ "@shikijs/rehype": "^3.4.2", "gray-matter": "4.0.3", "lodash-es": "^4.17.21", + "react-medium-image-zoom": "^5.2.14", "unified": "^11.0.5" }, "devDependencies": { diff --git a/packages/shared/src/types/index.ts b/packages/shared/src/types/index.ts index 4b5c43663..af9d1e527 100644 --- a/packages/shared/src/types/index.ts +++ b/packages/shared/src/types/index.ts @@ -1,7 +1,7 @@ import type { RsbuildConfig, RsbuildPlugin } from '@rsbuild/core'; import type { loadConfig } from '@rsbuild/core'; import type { RehypeShikiOptions } from '@shikijs/rehype'; -import type { ZoomOptions } from 'medium-zoom'; +import type { UncontrolledProps } from 'react-medium-image-zoom'; import type { PluggableList } from 'unified'; import type { AdditionalPage, RspressPlugin } from './Plugin'; import type { @@ -162,8 +162,8 @@ export interface UserConfig { mediumZoom?: | boolean | { - selector?: string; - options?: ZoomOptions; + isZoom: boolean; + options?: UncontrolledProps; }; /** * Add some extra builder plugins diff --git a/packages/theme-default/package.json b/packages/theme-default/package.json index 0c578723a..99a351a2e 100644 --- a/packages/theme-default/package.json +++ b/packages/theme-default/package.json @@ -47,10 +47,10 @@ "github-slugger": "^2.0.0", "hast-util-to-jsx-runtime": "^2.3.6", "lodash-es": "^4.17.21", - "medium-zoom": "1.1.0", "nprogress": "^0.2.0", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-medium-image-zoom": "^5.2.14", "shiki": "^3.4.2" }, "devDependencies": { diff --git a/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx b/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx index 12eca4743..8bbbb8f51 100644 --- a/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx +++ b/packages/theme-default/src/layout/DocLayout/docComponents/img.tsx @@ -1,42 +1,18 @@ import { normalizeImagePath } from '@rspress/runtime'; -import mediumZoom from 'medium-zoom'; -import type React from 'react'; +import Zoom from 'react-medium-image-zoom'; +import 'react-medium-image-zoom/dist/styles.css'; import type { ComponentProps } from 'react'; -import { useCallback, useEffect, useRef } from 'react'; export const Img = (props: ComponentProps<'img'>) => { return ; }; -export const ImgZoom = ({ - ref: refProp, - ...props -}: ComponentProps<'img'> & { ref?: React.Ref }) => { - const imgRef = useRef(null); - const combinedRef = useCallback( - (node: HTMLImageElement) => { - if (refProp) { - if (typeof refProp === 'function') { - refProp(node); - } else { - refProp.current = node; - } - } - imgRef.current = node; - }, - [refProp], - ); - - useEffect(() => { - if (!imgRef.current) return; - const zoom = mediumZoom(imgRef.current, { - background: 'var(--rp-c-bg)', - }); +const ImgZoomProps = JSON.parse(process.env.MEDIUM_ZOOM_OPTIONS || ''); - return () => { - zoom.detach(); - }; - }, []); - - return ; +export const ImgZoom = (props: ComponentProps<'img'>) => { + return ( + + + + ); }; diff --git a/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx b/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx index dde0fa516..3e79cb381 100644 --- a/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx +++ b/packages/theme-default/src/layout/DocLayout/docComponents/index.tsx @@ -30,7 +30,6 @@ export function getCustomMDXComponent() { a: A, code: Code, pre: PreWithCodeButtonGroup, - img: Img, - imgZoom: ImgZoom, + img: process.env.MEDIUM_ZOOM ? ImgZoom : Img, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b4819d3b7..8d852652c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1542,6 +1542,9 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 + react-medium-image-zoom: + specifier: ^5.2.14 + version: 5.2.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0) unified: specifier: ^11.0.5 version: 11.0.5 @@ -1609,9 +1612,6 @@ importers: lodash-es: specifier: ^4.17.21 version: 4.17.21 - medium-zoom: - specifier: 1.1.0 - version: 1.1.0 nprogress: specifier: ^0.2.0 version: 0.2.0 @@ -1621,6 +1621,9 @@ importers: react-dom: specifier: ^19.1.0 version: 19.1.0(react@19.1.0) + react-medium-image-zoom: + specifier: ^5.2.14 + version: 5.2.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0) shiki: specifier: ^3.4.2 version: 3.4.2 @@ -5710,6 +5713,12 @@ packages: '@types/react': '>=18' react: '>=18' + react-medium-image-zoom@5.2.14: + resolution: {integrity: sha512-nfTVYcAUnBzXQpPDcZL+cG/e6UceYUIG+zDcnemL7jtAqbJjVVkA85RgneGtJeni12dTyiRPZVM6Szkmwd/o8w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -11738,6 +11747,11 @@ snapshots: transitivePeerDependencies: - supports-color + react-medium-image-zoom@5.2.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + react-refresh@0.17.0: {} react-router-dom@6.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): From 5b5d6baa0fbba09eeaacbdded32dc287a37949d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=88=E8=90=BD=E6=98=9F=E6=B2=B3Tsukistar?= Date: Tue, 15 Jul 2025 20:22:30 +0800 Subject: [PATCH 5/5] Update index.module.scss --- .../src/layout/DocLayout/docComponents/index.module.scss | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss b/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss index 0a2bd2d07..2e0c9ba85 100644 --- a/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss +++ b/packages/theme-default/src/layout/DocLayout/docComponents/index.module.scss @@ -63,11 +63,6 @@ } } -.medium-zoom-overlay, -.medium-zoom-image--opened { - z-index: 999; -} - :global(.header-anchor) { color: var(--rp-c-brand); }