Fix invisible bidi characters copied with handles on web (#11066)

This commit is contained in:
Abdelrahman Youssef
2026-07-16 01:56:34 +03:00
committed by GitHub
parent 4705b7f408
commit 83a791d7c8
5 changed files with 53 additions and 2 deletions
+33
View File
@@ -0,0 +1,33 @@
import {describe, expect, it, jest} from '@jest/globals'
/*
* bidi.ts reads IS_WEB at call time, so a getter lets each test pick the
* platform. The mock-prefixed name is required by jest's factory scope rule.
*/
let mockIsWeb = false
jest.mock('#/env', () => ({
get IS_WEB() {
return mockIsWeb
},
}))
import {forceLTR} from '../bidi'
const LEFT_TO_RIGHT_EMBEDDING = '\u202A'
const POP_DIRECTIONAL_FORMATTING = '\u202C'
describe('forceLTR', () => {
it('wraps the string in directional formatting characters on native', () => {
mockIsWeb = false
expect(forceLTR('@alice.bsky.social')).toBe(
LEFT_TO_RIGHT_EMBEDDING +
'@alice.bsky.social' +
POP_DIRECTIONAL_FORMATTING,
)
})
it('returns the string unchanged on web so copied text stays clean (#8451)', () => {
mockIsWeb = true
expect(forceLTR('@alice.bsky.social')).toBe('@alice.bsky.social')
})
})
+9
View File
@@ -1,10 +1,19 @@
import {IS_WEB} from '#/env'
const LEFT_TO_RIGHT_EMBEDDING = '\u202A'
const POP_DIRECTIONAL_FORMATTING = '\u202C'
/*
* Force LTR directionality in a string.
* https://www.unicode.org/reports/tr9/#Directional_Formatting_Characters
*
* On web, direction is isolated with CSS instead (direction: ltr + unicode-bidi:
* isolate on the surrounding Text), so these invisible control characters are not
* injected. Injecting them leaks the characters into the rendered text, where
* they end up in copy-paste and break handle lookups in other apps and tools
* (#8451). Native has no equivalent CSS, so the manual wrapping is kept there.
*/
export function forceLTR(str: string) {
if (IS_WEB) return str
return LEFT_TO_RIGHT_EMBEDDING + str + POP_DIRECTIONAL_FORMATTING
}