diff --git a/src/components/universal/Markdown/renderers/image.tsx b/src/components/universal/Markdown/renderers/image.tsx index 88ecb85c2..4e30e7b1f 100644 --- a/src/components/universal/Markdown/renderers/image.tsx +++ b/src/components/universal/Markdown/renderers/image.tsx @@ -1,3 +1,4 @@ +import { sanitizeUrl } from 'markdown-to-jsx' import { reaction } from 'mobx' import { observer } from 'mobx-react-lite' import type { FC } from 'react' @@ -107,10 +108,11 @@ export const MImage: FC< > > = (props) => { const { src, alt } = props + const sanitizedUrl = sanitizeUrl(src!) const isClient = useIsClient() return !isClient ? ( - {alt} + {alt} ) : ( - <_Image src={src!} alt={alt} /> + <_Image src={sanitizedUrl!} alt={alt} /> ) } diff --git a/src/components/widgets/Toc/index.tsx b/src/components/widgets/Toc/index.tsx index afdaf356b..499240e0c 100644 --- a/src/components/widgets/Toc/index.tsx +++ b/src/components/widgets/Toc/index.tsx @@ -4,10 +4,10 @@ import type { FC } from 'react' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import { TransitionGroup } from 'react-transition-group' +import { RightLeftTransitionView } from '~/components/universal/Transition/right-left' import { CustomEventTypes } from '~/types/events' import { eventBus } from '~/utils/event-emitter' -import { RightLeftTransitionView } from '../../universal/Transition/right-left' import styles from './index.module.css' import { TocItem } from './item' @@ -17,10 +17,15 @@ export type TocProps = { useAsWeight?: boolean } +type Headings = { + depth: number + index: number + title: string +}[] export const Toc: FC = memo( ({ headings: $headings, useAsWeight }) => { const containerRef = useRef(null) - const headings = useMemo(() => { + const headings: Headings = useMemo(() => { return Array.from($headings).map((el) => { const depth = +el.tagName.slice(1) const title = el.id || el.textContent || '' @@ -69,6 +74,17 @@ export const Toc: FC = memo( }, 350) }, []) + const rootDepth = useMemo( + () => + headings?.length + ? (headings.reduce( + (d: number, cur) => Math.min(d, cur.depth), + headings[0]?.depth || 0, + ) as any as number) + : 0, + [headings], + ) + return (
= memo( > {headings && - headings.map((heading, i) => { + headings.map((heading) => { return ( - - Math.min(d, cur.depth), - headings[0].depth, - ) as any as number - } - /> - + ) })} @@ -112,3 +116,47 @@ export const Toc: FC = memo( ) }, ) +const MemoedItem = memo<{ + isActive: boolean + heading: Headings[0] + rootDepth: number + onClick: (i: number) => void +}>( + (props) => { + const { heading, isActive, onClick, rootDepth } = props + + return ( + + + + ) + }, + (a, b) => { + // FUCK react transition group alway inject onExited props into Child element, but this props alway change, so ignore it. + + return ( + a.heading === b.heading && + a.isActive === b.isActive && + a.onClick === b.onClick && + a.rootDepth === b.rootDepth + ) + }, +) + +MemoedItem.displayName = 'MemoedItem'