mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at tmp-rm-bitdrift 124 lines 3.3 kB view raw
1import React, {Children} from 'react' 2import {TextProps as RNTextProps} from 'react-native' 3import {StyleProp, TextStyle} from 'react-native' 4import {UITextView} from 'react-native-uitextview' 5import createEmojiRegex from 'emoji-regex' 6 7import {isNative} from '#/platform/detection' 8import {isIOS} from '#/platform/detection' 9import {Alf, applyFonts, atoms, flatten} from '#/alf' 10 11/** 12 * Util to calculate lineHeight from a text size atom and a leading atom 13 * 14 * Example: 15 * `leading(atoms.text_md, atoms.leading_normal)` // => 24 16 */ 17export function leading< 18 Size extends {fontSize?: number}, 19 Leading extends {lineHeight?: number}, 20>(textSize: Size, leading: Leading) { 21 const size = textSize?.fontSize || atoms.text_md.fontSize 22 const lineHeight = leading?.lineHeight || atoms.leading_normal.lineHeight 23 return Math.round(size * lineHeight) 24} 25 26/** 27 * Ensures that `lineHeight` defaults to a relative value of `1`, or applies 28 * other relative leading atoms. 29 * 30 * If the `lineHeight` value is > 2, we assume it's an absolute value and 31 * returns it as-is. 32 */ 33export function normalizeTextStyles( 34 styles: StyleProp<TextStyle>, 35 { 36 fontScale, 37 fontFamily, 38 }: { 39 fontScale: number 40 fontFamily: Alf['fonts']['family'] 41 } & Pick<Alf, 'flags'>, 42) { 43 const s = flatten(styles) 44 // should always be defined on these components 45 s.fontSize = (s.fontSize || atoms.text_md.fontSize) * fontScale 46 47 if (s?.lineHeight) { 48 if (s.lineHeight !== 0 && s.lineHeight <= 2) { 49 s.lineHeight = Math.round(s.fontSize * s.lineHeight) 50 } 51 } else if (!isNative) { 52 s.lineHeight = s.fontSize 53 } 54 55 applyFonts(s, fontFamily) 56 57 return s 58} 59 60export type StringChild = string | (string | null)[] 61export type TextProps = RNTextProps & { 62 /** 63 * Lets the user select text, to use the native copy and paste functionality. 64 */ 65 selectable?: boolean 66 /** 67 * Provides `data-*` attributes to the underlying `UITextView` component on 68 * web only. 69 */ 70 dataSet?: Record<string, string | number | undefined> 71 /** 72 * Appears as a small tooltip on web hover. 73 */ 74 title?: string 75 /** 76 * Whether the children could possibly contain emoji. 77 */ 78 emoji?: boolean 79} 80 81const EMOJI = createEmojiRegex() 82 83export function childHasEmoji(children: React.ReactNode) { 84 let hasEmoji = false 85 Children.forEach(children, child => { 86 if (typeof child === 'string' && createEmojiRegex().test(child)) { 87 hasEmoji = true 88 } 89 }) 90 return hasEmoji 91} 92 93export function renderChildrenWithEmoji( 94 children: React.ReactNode, 95 props: Omit<TextProps, 'children'> = {}, 96 emoji: boolean, 97) { 98 if (!isIOS || !emoji) { 99 return children 100 } 101 return Children.map(children, child => { 102 if (typeof child !== 'string') return child 103 104 const emojis = child.match(EMOJI) 105 106 if (emojis === null) { 107 return child 108 } 109 110 return child.split(EMOJI).map((stringPart, index) => [ 111 stringPart, 112 emojis[index] ? ( 113 <UITextView {...props} style={[props?.style, {fontFamily: 'System'}]}> 114 {emojis[index]} 115 </UITextView> 116 ) : null, 117 ]) 118 }) 119} 120 121const SINGLE_EMOJI_RE = /^[\p{Emoji_Presentation}\p{Extended_Pictographic}]+$/u 122export function isOnlyEmoji(text: string) { 123 return text.length <= 15 && SINGLE_EMOJI_RE.test(text) 124}