import { RichTextContentSegmentString, RichTextContentStringColorEnum, RichTextContentStringStyle, } from 'expo-schema'; import { EditorState } from 'lexical'; import { uniqueId } from 'lodash'; export const removeNoBreakingSpace = (value: string) => { return value.replaceAll(' ', ' '); }; export const isNoBreakingSpace = (value: string) => { return value === ' '; }; export const removeNoBreakingSpaceFromArray = (items: string[]) => { return items.filter((item) => !isNoBreakingSpace(item)); }; export const isItalic = (style: string) => { return style === 'italic' || false; }; export const isUnderline = (style: string) => { return style === 'underline' || false; }; export const isStrikeThrough = (style: string) => { return style === 'line-through' || false; }; export const isBold = (style: string) => { return style === 'bold' || false; }; export const localStyle: RichTextContentStringStyle = { bold: false, underline: false, italics: false, strikethrough: false, codeStyle: false, textColor: RichTextContentStringColorEnum.Default, backgroundColor: RichTextContentStringColorEnum.Default, }; export const collectSegmentStyles = (item: HTMLElement) => { const style = window.getComputedStyle(item); localStyle.textColor = RichTextContentStringColorEnum.Default; localStyle.backgroundColor = RichTextContentStringColorEnum.Default; localStyle.italics = isItalic(style.fontStyle); localStyle.underline = isUnderline(style.textDecorationLine); localStyle.strikethrough = isStrikeThrough(style.textDecorationLine); localStyle.bold = isStrikeThrough(style.fontWeight); localStyle.bold = isStrikeThrough(style.fontWeight); return localStyle; }; export const collectSegmentsFromNewLine = ( item: HTMLElement, segmentValues: string[], sampleSegment: RichTextContentSegmentString ) => { const localStyleInner = collectSegmentStyles(item); const segmentLocalStringsTemp: RichTextContentSegmentString[] = []; for (const segValue of segmentValues) { const newItem: RichTextContentSegmentString = { ...sampleSegment, id: 'new', value: segValue, style: localStyleInner, // TODO: update order accordingly }; segmentLocalStringsTemp.push(newItem); } return segmentLocalStringsTemp; }; export const collectRemovedSegmentsIds = ( segments: RichTextContentSegmentString[], oldSegmentsIds: string[] ): string[] => { let ids = segments.map((segment) => !oldSegmentsIds.includes(segment.id) && segment.id); ids = ids.filter((id) => !id === false); return ids as string[]; }; export const getRandomId = (): string => { const random = Math.random(); return random.toString().substring(2, 8); }; export const getSelectedElements = () => { const currentSelection = window.getSelection(); if (currentSelection && currentSelection.rangeCount > 0) { const startElement = currentSelection.getRangeAt(0).startContainer.parentNode; const endingElement = currentSelection.getRangeAt(0).endContainer.parentNode; return { startElement, endingElement }; } else { return null; } }; export const isDeepEqual = (first: any, second: any) => { return JSON.stringify(first) === JSON.stringify(second); }; export const applyTopActionStyles = ({ string, isBold: isStringBold, isItalic: isStringItalic, isCode, isUnderLine, isStrikeThrough: isStringStrikeThrough, }: ApplyTopActionStylesProps) => { const localString: RichTextContentStringStyle = { ...string.style }; localString.bold = isStringBold; localString.italics = isStringItalic; localString.codeStyle = isCode; localString.underline = isUnderLine; localString.strikethrough = isStringStrikeThrough; return localString; }; type RichTextContentSegmentStringWithOutId = Omit; export const emptyLine: RichTextContentSegmentStringWithOutId = { value: '', onNewLine: true, style: localStyle, order: 1, // just added to ignore ts error, not actual order }; export const parseLexicalContentToLocal = ( editorState: EditorState ): RichTextContentSegmentString[] => { const editorStateParsed = JSON.parse(JSON.stringify(editorState)); const parsed: RichTextContentSegmentString[] = []; let order = 0; for (const children of editorStateParsed.root.children) { for (const subChild of children.children) { parsed.push({ value: subChild.text || '', style: localStyle, id: uniqueId(), onNewLine: subChild.type === 'text' ? false : true, order, }); order += 1; } } return parsed; }; export const lexicalTextChild = { detail: 0, format: 0, mode: 'normal', style: '', text: '', type: 'text', version: 1, }; export const getLexicalRootByChildren = (children: any) => { return { root: { children: [ { children, direction: 'ltr', format: '', indent: 0, type: 'paragraph', version: 1, }, ], direction: 'ltr', format: '', indent: 0, type: 'root', version: 1, }, }; }; export enum LexicalChildrenTypes { Text = 'text', LineBreak = 'linebreak', } interface ApplyTopActionStylesProps { string: RichTextContentSegmentString; isBold: boolean; isItalic: boolean; isCode: boolean; isUnderLine: boolean; isStrikeThrough: boolean; }