diff --git a/native/markdown/markdown-context-provider.react.js b/native/markdown/markdown-context-provider.react.js --- a/native/markdown/markdown-context-provider.react.js +++ b/native/markdown/markdown-context-provider.react.js @@ -16,9 +16,16 @@ [key: string]: boolean, }>({}); + const [spoilerRevealed, setSpoilerRevealed] = React.useState<{ + [key: string]: { + [key: number]: boolean, + }, + }>({}); + const clearMarkdownContextData = React.useCallback(() => { setLinkModalActive({}); setLinkPressActive({}); + setSpoilerRevealed({}); }, []); const contextValue = React.useMemo( @@ -27,6 +34,8 @@ linkModalActive, setLinkPressActive, linkPressActive, + setSpoilerRevealed, + spoilerRevealed, clearMarkdownContextData, }), [ @@ -34,6 +43,8 @@ linkModalActive, setLinkPressActive, linkPressActive, + setSpoilerRevealed, + spoilerRevealed, clearMarkdownContextData, ], ); diff --git a/native/markdown/markdown-context.js b/native/markdown/markdown-context.js --- a/native/markdown/markdown-context.js +++ b/native/markdown/markdown-context.js @@ -9,6 +9,8 @@ +linkModalActive: { [key: string]: boolean }, +setLinkPressActive: SetState<{ [key: string]: boolean }>, +linkPressActive: { [key: string]: boolean }, + +setSpoilerRevealed: SetState<{ [key: string]: { [key: number]: boolean } }>, + +spoilerRevealed: { [key: string]: { [key: number]: boolean } }, +clearMarkdownContextData: () => void, }; diff --git a/native/markdown/markdown-spoiler.react.js b/native/markdown/markdown-spoiler.react.js --- a/native/markdown/markdown-spoiler.react.js +++ b/native/markdown/markdown-spoiler.react.js @@ -1,36 +1,77 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { Text } from 'react-native'; import type { ReactElement } from 'lib/shared/markdown'; +import { MessageContext } from '../chat/message-context.react'; import { useStyles } from '../themes/colors'; +import { MarkdownContext } from './markdown-context'; type MarkdownSpoilerProps = { + +spoilerIdentifier: string | number | void, +text: ReactElement, +children?: React.Node, }; function MarkdownSpoiler(props: MarkdownSpoilerProps): React.Node { - const [isRevealed, setIsRevealed] = React.useState(false); + const markdownContext = React.useContext(MarkdownContext); + invariant(markdownContext, 'MarkdownContext should be set'); + + const messageContext = React.useContext(MessageContext); + invariant(messageContext, 'MessageContext should be set'); + const styles = useStyles(unboundStyles); - const { text } = props; + + const { text, spoilerIdentifier } = props; + const { spoilerRevealed, setSpoilerRevealed } = markdownContext; + const { messageKey } = messageContext; + + const parsedSpoilerIdentifier = spoilerIdentifier + ? parseInt(spoilerIdentifier) + : -1; + + const isRevealed = + spoilerRevealed[messageKey]?.[parsedSpoilerIdentifier] ?? false; + + const styleBasedOnSpoilerState = React.useMemo(() => { + if (isRevealed) { + return null; + } + return styles.spoilerHidden; + }, [isRevealed, styles.spoilerHidden]); const onSpoilerClick = React.useCallback(() => { - setIsRevealed(true); - }, []); + if (isRevealed) { + return; + } + + if (parsedSpoilerIdentifier !== -1) { + setSpoilerRevealed({ + ...spoilerRevealed, + [messageKey]: { + ...spoilerRevealed[messageKey], + [parsedSpoilerIdentifier]: true, + }, + }); + } + }, [ + isRevealed, + spoilerRevealed, + setSpoilerRevealed, + messageKey, + parsedSpoilerIdentifier, + ]); const memoizedSpoiler = React.useMemo(() => { return ( - + {text} ); - }, [onSpoilerClick, isRevealed, styles.spoilerHidden, text]); + }, [onSpoilerClick, styleBasedOnSpoilerState, text]); return memoizedSpoiler; } diff --git a/native/markdown/rules.react.js b/native/markdown/rules.react.js --- a/native/markdown/rules.react.js +++ b/native/markdown/rules.react.js @@ -200,7 +200,11 @@ output: SharedMarkdown.Output, state: SharedMarkdown.State, ) => ( - + ), }, inlineCode: {