diff --git a/globals.d.ts b/globals.d.ts index ce8c8ebc1e..29d519d53d 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -27,11 +27,11 @@ namespace JSX { 'mask-calendar-widget': React.DetailedHTMLProps, HTMLElement>; 'mask-page-inspector': React.DetailedHTMLProps, HTMLElement>; 'mask-decrypted-post': React.DetailedHTMLProps< - React.HTMLAttributes & { props: string }, + React.HTMLAttributes & { 'props-id': string }, HTMLElement >; 'mask-post-inspector': React.DetailedHTMLProps< - React.HTMLAttributes & { props: string }, + React.HTMLAttributes & { 'props-id': string }, HTMLElement >; } diff --git a/src/components/Posts/PostBody.tsx b/src/components/Posts/PostBody.tsx index 1a17ad8874..4a1221cc74 100644 --- a/src/components/Posts/PostBody.tsx +++ b/src/components/Posts/PostBody.tsx @@ -1,9 +1,10 @@ 'use client'; import { Select, t, Trans } from '@lingui/macro'; -import { compact } from 'lodash-es'; +import { EMPTY_LIST } from '@masknet/shared-base'; +import { compact, noop, uniqueId } from 'lodash-es'; import { useRouter } from 'next/navigation.js'; -import { forwardRef, useMemo, useState } from 'react'; +import { forwardRef, useLayoutEffect, useMemo, useState } from 'react'; import { useInView } from 'react-cool-inview'; import { useAsync } from 'react-use'; @@ -19,7 +20,6 @@ import { Quote } from '@/components/Posts/Quote.js'; import { IS_APPLE, IS_SAFARI } from '@/constants/bowser.js'; import { STATUS } from '@/constants/enum.js'; import { env } from '@/constants/env.js'; -import { EMPTY_LIST } from '@/constants/index.js'; import { classNames } from '@/helpers/classNames.js'; import { formatUrl } from '@/helpers/formatUrl.js'; import { getEncryptedPayloadFromImageAttachment, getEncryptedPayloadFromText } from '@/helpers/getEncryptedPayload.js'; @@ -27,6 +27,7 @@ import { getPostUrl } from '@/helpers/getPostUrl.js'; import { isValidUrl } from '@/helpers/isValidUrl.js'; import { trimify } from '@/helpers/trimify.js'; import { useIsProfileMuted } from '@/hooks/useIsProfileMuted.js'; +import { propsMap } from '@/mask/custom-elements/props-pool.js'; import type { Post } from '@/providers/types/SocialMedia.js'; interface PostBodyProps { @@ -65,6 +66,7 @@ export const PostBody = forwardRef(function PostB }, }); + const [propsId, setPropsId] = useState(uniqueId); const { value: payloads } = useAsync(async () => { // decode the image upon post viewing, to reduce unnecessary load of images if (!postViewed) return; @@ -80,6 +82,24 @@ export const PostBody = forwardRef(function PostB const muted = useIsProfileMuted(author, isDetail); + useLayoutEffect(() => { + setPropsId(() => uniqueId()); + }, [payloads]); + + useLayoutEffect(() => { + if (!postViewed) return noop; + propsMap.set(propsId, { + post, + payloads: + payloads?.payloadFromImageAttachment || payloads?.payloadFromText + ? compact([payloads.payloadFromImageAttachment, payloads.payloadFromText]) + : undefined, + }); + return () => { + propsMap.delete(propsId); + }; + }, [post, payloads, propsId, postViewed]); + const payloadFromImageAttachment = payloads?.payloadFromImageAttachment; const payloadImageUrl = payloadFromImageAttachment?.[2]; const attachments = metadata.content?.attachments ?? EMPTY_LIST; @@ -203,16 +223,9 @@ export const PostBody = forwardRef(function PostB {postViewed ? ( payloads?.payloadFromImageAttachment || payloads?.payloadFromText ? ( - + ) : ( - + ) ) : null} diff --git a/src/mask/custom-elements/WidgetWithProps.tsx b/src/mask/custom-elements/WidgetWithProps.tsx index 1eee83ce98..482cdb1e2a 100644 --- a/src/mask/custom-elements/WidgetWithProps.tsx +++ b/src/mask/custom-elements/WidgetWithProps.tsx @@ -1,18 +1,15 @@ import { createRoot } from 'react-dom/client'; -import { parseJSON } from '@/helpers/parseJSON.js'; +import { propsMap } from '@/mask/custom-elements/props-pool.js'; import { Widget } from '@/mask/custom-elements/Widget.js'; export class WidgetWithProps extends Widget { - get props() { - const raw = this.getAttribute('props'); - if (!raw) return; - - return parseJSON(decodeURIComponent(raw)); - } - override connectedCallback() { this.root = createRoot(this); - this.root.render(); + + const propsId = this.getAttribute('props-id'); + const props = propsId ? (propsMap.get(propsId) as T) : undefined; + + this.root.render(); } } diff --git a/src/mask/custom-elements/props-pool.ts b/src/mask/custom-elements/props-pool.ts new file mode 100644 index 0000000000..0130670a9b --- /dev/null +++ b/src/mask/custom-elements/props-pool.ts @@ -0,0 +1 @@ +export const propsMap = new Map();