Skip to content

Commit

Permalink
Merge branch 'main' into fix-composition-pasting
Browse files Browse the repository at this point in the history
  • Loading branch information
tomekzaw authored Jan 22, 2025
2 parents 9784a69 + 761e29e commit 7870627
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 16 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@expensify/react-native-live-markdown",
"version": "0.1.219",
"version": "0.1.222",
"description": "Drop-in replacement for React Native's TextInput component with Markdown formatting.",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
11 changes: 11 additions & 0 deletions src/MarkdownTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ declare global {
let initialized = false;
let workletRuntime: WorkletRuntime | undefined;

function getWorkletRuntime(): WorkletRuntime {
if (workletRuntime === undefined) {
throw new Error(
"[react-native-live-markdown] Worklet runtime hasn't been created yet. Please avoid calling `getWorkletRuntime()` in top-level scope. Instead, call `getWorkletRuntime()` directly in `runOnRuntime` arguments list.",
);
}
return workletRuntime;
}

function initializeLiveMarkdownIfNeeded() {
if (initialized) {
return;
Expand Down Expand Up @@ -132,3 +141,5 @@ const styles = StyleSheet.create({
export type {PartialMarkdownStyle as MarkdownStyle, MarkdownTextInputProps};

export default MarkdownTextInput;

export {getWorkletRuntime};
6 changes: 6 additions & 0 deletions src/MarkdownTextInput.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -826,3 +826,9 @@ const styles = StyleSheet.create({
export default MarkdownTextInput;

export type {MarkdownNativeEvent, MarkdownTextInputProps, MarkdownTextInputElement, HTMLMarkdownElement};

function getWorkletRuntime() {
throw new Error('[react-native-live-markdown] `getWorkletRuntime` is not available on web. Please make sure to use it only on native Android or iOS.');
}

export {getWorkletRuntime};
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export {default as MarkdownTextInput} from './MarkdownTextInput';
export {default as MarkdownTextInput, getWorkletRuntime} from './MarkdownTextInput';
export type {MarkdownTextInputProps, MarkdownStyle} from './MarkdownTextInput';
export type {MarkdownType, MarkdownRange} from './commonTypes';
export {default as parseExpensiMark} from './parseExpensiMark';
16 changes: 10 additions & 6 deletions src/parseExpensiMark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ function parseTreeToTextAndRanges(tree: StackItem): [string, MarkdownRange[]] {
return [text, ranges];
}

const isAndroid = Platform.OS === 'android';

function parseExpensiMark(markdown: string): MarkdownRange[] {
if (markdown.length > MAX_PARSABLE_LENGTH) {
return [];
Expand All @@ -252,13 +254,15 @@ function parseExpensiMark(markdown: string): MarkdownRange[] {
);
return [];
}
let markdownRanges = sortRanges(ranges);
if (isAndroid) {
// Blocks applying italic and strikethrough styles to emojis on Android
// TODO: Remove this condition when splitting emojis inside the inline code block will be fixed on the web
markdownRanges = splitRangesOnEmojis(markdownRanges, 'italic');
markdownRanges = splitRangesOnEmojis(markdownRanges, 'strikethrough');
}

let splittedRanges = splitRangesOnEmojis(ranges, 'italic');
splittedRanges = splitRangesOnEmojis(splittedRanges, 'strikethrough');

const sortedRanges = sortRanges(splittedRanges);
const groupedRanges = groupRanges(sortedRanges);

const groupedRanges = groupRanges(markdownRanges);
return groupedRanges;
}

Expand Down
6 changes: 5 additions & 1 deletion src/web/MarkdownTextInput.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
display: none;
}

.react-native-live-markdown-input-singleline span[data-type="text"] {
.react-native-live-markdown-input-singleline span[data-type='text'] {
vertical-align: middle;
}

.react-native-live-markdown-input-singleline > p:last-child {
padding-right: 1px !important;
}

.react-native-live-markdown-input-singleline:empty::before,
.react-native-live-markdown-input-multiline:empty::before {
pointer-events: none;
Expand Down
17 changes: 15 additions & 2 deletions src/web/utils/blockUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import type {PartialMarkdownStyle} from '../../styleUtils';
import {addInlineImagePreview} from '../inputElements/inlineImage';
import type {NodeType, TreeNode} from './treeUtils';

function addStyleToBlock(targetElement: HTMLElement, type: NodeType, markdownStyle: PartialMarkdownStyle) {
function addStyleToBlock(targetElement: HTMLElement, type: NodeType, markdownStyle: PartialMarkdownStyle, isMultiline = true) {
const node = targetElement;

switch (type) {
case 'line':
Object.assign(node.style, {
Expand All @@ -26,7 +27,13 @@ function addStyleToBlock(targetElement: HTMLElement, type: NodeType, markdownSty
node.style.textDecoration = 'line-through';
break;
case 'emoji':
Object.assign(node.style, {...markdownStyle.emoji, verticalAlign: 'middle'});
Object.assign(node.style, {
...markdownStyle.emoji,
verticalAlign: 'middle',
fontStyle: 'normal', // remove italic
textDecoration: 'none', // remove strikethrough
display: 'inline-block',
});
break;
case 'mention-here':
Object.assign(node.style, markdownStyle.mentionHere);
Expand Down Expand Up @@ -74,6 +81,12 @@ function addStyleToBlock(targetElement: HTMLElement, type: NodeType, markdownSty
position: 'relative',
});
break;
case 'text':
if (!isMultiline) {
Object.assign(node.style, {backgroundColor: targetElement.parentElement?.style.backgroundColor});
Object.assign(targetElement.parentElement?.style ?? {}, {backgroundColor: 'transparent'});
}
break;
default:
break;
}
Expand Down
12 changes: 9 additions & 3 deletions src/web/utils/parserUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function addBrElement(node: TreeNode) {
return spanNode;
}

function addTextToElement(node: TreeNode, text: string) {
function addTextToElement(node: TreeNode, text: string, isMultiline = true) {
const lines = text.split('\n');
lines.forEach((line, index) => {
if (line !== '') {
Expand All @@ -96,6 +96,12 @@ function addTextToElement(node: TreeNode, text: string) {
span.setAttribute('data-type', 'text');
span.appendChild(document.createTextNode(line));
appendNode(span, node, 'text', line.length);

const parentType = span.parentElement?.dataset.type;
if (!isMultiline && parentType && ['pre', 'code', 'mention-here', 'mention-user', 'mention-report'].includes(parentType)) {
// this is a fix to background colors being shifted downwards in a singleline input
addStyleToBlock(span, 'text', {}, false);
}
}

if (index < lines.length - 1 || (index === 0 && line === '')) {
Expand Down Expand Up @@ -208,7 +214,7 @@ function parseRangesToHTMLNodes(
span.setAttribute('data-type', range.type);

if (!disableInlineStyles) {
addStyleToBlock(span, range.type, markdownStyle);
addStyleToBlock(span, range.type, markdownStyle, isMultiline);
}

const spanNode = appendNode(span, currentParentNode, range.type, range.length);
Expand All @@ -223,7 +229,7 @@ function parseRangesToHTMLNodes(
lastRangeEndIndex = range.start;
} else {
// adding markdown tag
addTextToElement(spanNode, text.substring(range.start, endOfCurrentRange));
addTextToElement(spanNode, text.substring(range.start, endOfCurrentRange), isMultiline);
currentParentNode.element.value = (currentParentNode.element.value || '') + (spanNode.element.value || '');
lastRangeEndIndex = endOfCurrentRange;
// tag unnesting and adding text after the tag
Expand Down

0 comments on commit 7870627

Please sign in to comment.