diff --git a/src/MarkdownTextInput.tsx b/src/MarkdownTextInput.tsx index 823c6640..3eb2ea26 100644 --- a/src/MarkdownTextInput.tsx +++ b/src/MarkdownTextInput.tsx @@ -6,12 +6,13 @@ import type {MarkdownStyle} from './MarkdownTextInputDecoratorViewNativeComponen import NativeLiveMarkdownModule from './NativeLiveMarkdownModule'; import {mergeMarkdownStyleWithDefault} from './styleUtils'; import type {PartialMarkdownStyle} from './styleUtils'; +import type {InlineImagesInputProps} from './commonTypes'; if (NativeLiveMarkdownModule) { NativeLiveMarkdownModule.install(); } -interface MarkdownTextInputProps extends TextInputProps { +interface MarkdownTextInputProps extends TextInputProps, InlineImagesInputProps { markdownStyle?: PartialMarkdownStyle; } diff --git a/src/MarkdownTextInput.web.tsx b/src/MarkdownTextInput.web.tsx index ebcab17a..b6419c95 100644 --- a/src/MarkdownTextInput.web.tsx +++ b/src/MarkdownTextInput.web.tsx @@ -23,12 +23,13 @@ import type {MarkdownStyle} from './MarkdownTextInputDecoratorViewNativeComponen import {getElementHeight, getPlaceholderValue, isEventComposing, normalizeValue, parseInnerHTMLToText} from './web/utils/inputUtils'; import {parseToReactDOMStyle, processMarkdownStyle} from './web/utils/webStyleUtils'; import {forceRefreshAllImages} from './web/inputElements/inlineImage'; +import type {InlineImagesInputProps} from './commonTypes'; require('../parser/react-native-live-markdown-parser.js'); const useClientEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect; -interface MarkdownTextInputProps extends TextInputProps { +interface MarkdownTextInputProps extends TextInputProps, InlineImagesInputProps { markdownStyle?: MarkdownStyle; onClick?: (e: MouseEvent) => void; dir?: string; @@ -101,6 +102,8 @@ const MarkdownTextInput = React.forwardRef( id, inputMode, onTouchStart, + addAuthTokenToImageURLCallback, + imagePreviewAuthRequiredURLs, }, ref, ) => { @@ -154,7 +157,10 @@ const MarkdownTextInput = React.forwardRef( if (text === null) { return {text: divRef.current.value, cursorPosition: null}; } - const parsedText = updateInputStructure(target, text, cursorPosition, multiline, customMarkdownStyles, false, shouldForceDOMUpdate, shouldScrollIntoView); + const parsedText = updateInputStructure(target, text, cursorPosition, multiline, customMarkdownStyles, false, shouldForceDOMUpdate, shouldScrollIntoView, { + addAuthTokenToImageURLCallback, + imagePreviewAuthRequiredURLs, + }); divRef.current.value = parsedText.text; if (history.current && shouldAddToHistory) { @@ -163,7 +169,7 @@ const MarkdownTextInput = React.forwardRef( return parsedText; }, - [multiline], + [addAuthTokenToImageURLCallback, imagePreviewAuthRequiredURLs, multiline], ); const processedMarkdownStyle = useMemo(() => { diff --git a/src/commonTypes.ts b/src/commonTypes.ts index 441e8d0d..73edbf39 100644 --- a/src/commonTypes.ts +++ b/src/commonTypes.ts @@ -21,4 +21,9 @@ interface MarkdownRange { depth?: number; } -export type {MarkdownType, MarkdownRange}; +type InlineImagesInputProps = { + addAuthTokenToImageURLCallback?: (url: string) => string; + imagePreviewAuthRequiredURLs?: string[]; +}; + +export type {MarkdownType, MarkdownRange, InlineImagesInputProps}; diff --git a/src/web/inputElements/inlineImage.ts b/src/web/inputElements/inlineImage.ts index 77bcaeba..d894e557 100644 --- a/src/web/inputElements/inlineImage.ts +++ b/src/web/inputElements/inlineImage.ts @@ -1,5 +1,5 @@ import type {HTMLMarkdownElement, MarkdownTextInputElement} from '../../MarkdownTextInput.web'; -import type {MarkdownRange} from '../../commonTypes'; +import type {InlineImagesInputProps, MarkdownRange} from '../../commonTypes'; import {parseStringWithUnitToNumber} from '../../styleUtils'; import type {PartialMarkdownStyle} from '../../styleUtils'; import type {TreeNode} from '../utils/treeUtils'; @@ -141,11 +141,22 @@ function updateImageTreeNode(targetNode: TreeNode, newElement: HTMLMarkdownEleme } /** The main function that adds inline image preview to the node */ -function addInlineImagePreview(currentInput: MarkdownTextInputElement, targetNode: TreeNode, text: string, ranges: MarkdownRange[], markdownStyle: PartialMarkdownStyle) { +function addInlineImagePreview( + currentInput: MarkdownTextInputElement, + targetNode: TreeNode, + text: string, + ranges: MarkdownRange[], + markdownStyle: PartialMarkdownStyle, + inlineImagesProps: InlineImagesInputProps, +) { + const {addAuthTokenToImageURLCallback, imagePreviewAuthRequiredURLs} = inlineImagesProps; const linkRange = ranges.find((r) => r.type === 'link'); let imageHref = ''; if (linkRange) { imageHref = text.substring(linkRange.start, linkRange.start + linkRange.length); + if (addAuthTokenToImageURLCallback && imagePreviewAuthRequiredURLs && imagePreviewAuthRequiredURLs.find((url) => imageHref.startsWith(url))) { + imageHref = addAuthTokenToImageURLCallback(imageHref); + } } const imageMarginTop = parseStringWithUnitToNumber(`${markdownStyle.inlineImage?.marginTop}`); diff --git a/src/web/utils/blockUtils.ts b/src/web/utils/blockUtils.ts index 01ff2283..e9837569 100644 --- a/src/web/utils/blockUtils.ts +++ b/src/web/utils/blockUtils.ts @@ -1,5 +1,5 @@ import type {MarkdownTextInputElement} from '../../MarkdownTextInput.web'; -import type {MarkdownRange} from '../../commonTypes'; +import type {InlineImagesInputProps, MarkdownRange} from '../../commonTypes'; import type {PartialMarkdownStyle} from '../../styleUtils'; import {addInlineImagePreview} from '../inputElements/inlineImage'; import type {NodeType, TreeNode} from './treeUtils'; @@ -98,10 +98,11 @@ function extendBlockStructure( ranges: MarkdownRange[], text: string, markdownStyle: PartialMarkdownStyle, + inlineImagesProps: InlineImagesInputProps, ) { switch (currentRange.type) { case 'inline-image': - return addInlineImagePreview(currentInput, targetNode, text, ranges, markdownStyle); + return addInlineImagePreview(currentInput, targetNode, text, ranges, markdownStyle, inlineImagesProps); default: break; } diff --git a/src/web/utils/parserUtils.ts b/src/web/utils/parserUtils.ts index f1212295..4f0c5793 100644 --- a/src/web/utils/parserUtils.ts +++ b/src/web/utils/parserUtils.ts @@ -4,7 +4,7 @@ import type {NodeType, TreeNode} from './treeUtils'; import type {PartialMarkdownStyle} from '../../styleUtils'; import {getCurrentCursorPosition, moveCursorToEnd, setCursorPosition} from './cursorUtils'; import {addStyleToBlock, extendBlockStructure, getFirstBlockMarkdownRange, isBlockMarkdownType} from './blockUtils'; -import type {MarkdownRange} from '../../commonTypes'; +import type {InlineImagesInputProps, MarkdownRange} from '../../commonTypes'; import {getAnimationCurrentTimes, updateAnimationsTime} from './animationUtils'; type Paragraph = { @@ -151,6 +151,7 @@ function parseRangesToHTMLNodes( markdownStyle: PartialMarkdownStyle = {}, disableInlineStyles = false, currentInput: MarkdownTextInputElement | null = null, + inlineImagesProps: InlineImagesInputProps = {}, ) { const rootElement: HTMLMarkdownElement = document.createElement('span') as HTMLMarkdownElement; const textLength = text.length; @@ -224,7 +225,7 @@ function parseRangesToHTMLNodes( const spanNode = appendNode(span, currentParentNode, range.type, range.length); if (isMultiline && !disableInlineStyles && currentInput) { - currentParentNode = extendBlockStructure(currentInput, currentParentNode, range, lineMarkdownRanges, text, markdownStyle); + currentParentNode = extendBlockStructure(currentInput, currentParentNode, range, lineMarkdownRanges, text, markdownStyle, inlineImagesProps); } if (lineMarkdownRanges.length > 0 && nextRangeStartIndex < endOfCurrentRange && range.type !== 'syntax') { @@ -279,6 +280,7 @@ function updateInputStructure( alwaysMoveCursorToTheEnd = false, shouldForceDOMUpdate = false, shouldScrollIntoView = false, + inlineImagesProps: InlineImagesInputProps = {}, ) { const targetElement = target; @@ -297,7 +299,7 @@ function updateInputStructure( // We don't want to parse text with single '\n', because contentEditable represents it as invisible
if (text) { - const {dom, tree} = parseRangesToHTMLNodes(text, markdownRanges, isMultiline, markdownStyle, false, targetElement); + const {dom, tree} = parseRangesToHTMLNodes(text, markdownRanges, isMultiline, markdownStyle, false, targetElement, inlineImagesProps); if (shouldForceDOMUpdate || targetElement.innerHTML !== dom.innerHTML) { const animationTimes = getAnimationCurrentTimes(targetElement);