Multiple fixes on composer highlighting
- Hide scrollbar for the faux highlight div - Use unicode-aware split for highlighting exceeded characters - Disable highlight of mentions, hashtags, etc if exceeded max characters - Sync scroll as often as possible
This commit is contained in:
parent
7019c09e5b
commit
4f41646000
4 changed files with 23 additions and 6 deletions
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -32,6 +32,7 @@
|
||||||
"react-intersection-observer": "~9.5.3",
|
"react-intersection-observer": "~9.5.3",
|
||||||
"react-quick-pinch-zoom": "~5.1.0",
|
"react-quick-pinch-zoom": "~5.1.0",
|
||||||
"react-router-dom": "6.6.2",
|
"react-router-dom": "6.6.2",
|
||||||
|
"runes2": "~1.1.3",
|
||||||
"string-length": "5.0.1",
|
"string-length": "5.0.1",
|
||||||
"swiped-events": "~1.1.9",
|
"swiped-events": "~1.1.9",
|
||||||
"toastify-js": "~1.12.0",
|
"toastify-js": "~1.12.0",
|
||||||
|
@ -6057,6 +6058,11 @@
|
||||||
"queue-microtask": "^1.2.2"
|
"queue-microtask": "^1.2.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/runes2": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/runes2/-/runes2-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-sJ/0iVFLne4f2S7cMB1OckBtC9lqkzP5a/wPnDIkbrWzgUsJ+JMQv6y7hk76U7zvbua+je5GltfpsZazUhG05w=="
|
||||||
|
},
|
||||||
"node_modules/safe-buffer": {
|
"node_modules/safe-buffer": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
"react-intersection-observer": "~9.5.3",
|
"react-intersection-observer": "~9.5.3",
|
||||||
"react-quick-pinch-zoom": "~5.1.0",
|
"react-quick-pinch-zoom": "~5.1.0",
|
||||||
"react-router-dom": "6.6.2",
|
"react-router-dom": "6.6.2",
|
||||||
|
"runes2": "~1.1.3",
|
||||||
"string-length": "5.0.1",
|
"string-length": "5.0.1",
|
||||||
"swiped-events": "~1.1.9",
|
"swiped-events": "~1.1.9",
|
||||||
"toastify-js": "~1.12.0",
|
"toastify-js": "~1.12.0",
|
||||||
|
|
|
@ -653,6 +653,11 @@
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
min-height: 5em;
|
min-height: 5em;
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
|
scrollbar-width: none;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Follow textarea styles */
|
/* Follow textarea styles */
|
||||||
@media (min-width: 40em) {
|
@media (min-width: 40em) {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import equal from 'fast-deep-equal';
|
||||||
import { forwardRef } from 'preact/compat';
|
import { forwardRef } from 'preact/compat';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
import { useEffect, useMemo, useRef, useState } from 'preact/hooks';
|
||||||
import { useHotkeys } from 'react-hotkeys-hook';
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
|
import { substring } from 'runes2';
|
||||||
import stringLength from 'string-length';
|
import stringLength from 'string-length';
|
||||||
import { uid } from 'uid/single';
|
import { uid } from 'uid/single';
|
||||||
import { useDebouncedCallback, useThrottledCallback } from 'use-debounce';
|
import { useDebouncedCallback, useThrottledCallback } from 'use-debounce';
|
||||||
|
@ -131,16 +132,20 @@ function highlightText(text, { maxCharacters = Infinity }) {
|
||||||
const { composerCharacterCount } = states;
|
const { composerCharacterCount } = states;
|
||||||
let leftoverHTML = '';
|
let leftoverHTML = '';
|
||||||
if (composerCharacterCount > maxCharacters) {
|
if (composerCharacterCount > maxCharacters) {
|
||||||
const leftoverCount = composerCharacterCount - maxCharacters;
|
// NOTE: runes2 substring considers surrogate pairs
|
||||||
|
// const leftoverCount = composerCharacterCount - maxCharacters;
|
||||||
// Highlight exceeded characters
|
// Highlight exceeded characters
|
||||||
leftoverHTML =
|
leftoverHTML =
|
||||||
'<mark class="compose-highlight-exceeded">' +
|
'<mark class="compose-highlight-exceeded">' +
|
||||||
html.slice(-leftoverCount) +
|
// html.slice(-leftoverCount) +
|
||||||
|
substring(html, maxCharacters) +
|
||||||
'</mark>';
|
'</mark>';
|
||||||
html = html.slice(0, -leftoverCount);
|
// html = html.slice(0, -leftoverCount);
|
||||||
|
html = substring(html, 0, maxCharacters);
|
||||||
|
return html + leftoverHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
html = html
|
return html
|
||||||
.replace(urlRegexObj, '$2<mark class="compose-highlight-url">$3</mark>') // URLs
|
.replace(urlRegexObj, '$2<mark class="compose-highlight-url">$3</mark>') // URLs
|
||||||
.replace(MENTION_RE, '$1<mark class="compose-highlight-mention">$2</mark>') // Mentions
|
.replace(MENTION_RE, '$1<mark class="compose-highlight-mention">$2</mark>') // Mentions
|
||||||
.replace(HASHTAG_RE, '$1<mark class="compose-highlight-hashtag">$2</mark>') // Hashtags
|
.replace(HASHTAG_RE, '$1<mark class="compose-highlight-hashtag">$2</mark>') // Hashtags
|
||||||
|
@ -148,8 +153,6 @@ function highlightText(text, { maxCharacters = Infinity }) {
|
||||||
SCAN_RE,
|
SCAN_RE,
|
||||||
'$1<mark class="compose-highlight-emoji-shortcode">$2</mark>',
|
'$1<mark class="compose-highlight-emoji-shortcode">$2</mark>',
|
||||||
); // Emoji shortcodes
|
); // Emoji shortcodes
|
||||||
|
|
||||||
return html + leftoverHTML;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Compose({
|
function Compose({
|
||||||
|
@ -1538,6 +1541,7 @@ const Textarea = forwardRef((props, ref) => {
|
||||||
target.setRangeText('', pos, selectionStart);
|
target.setRangeText('', pos, selectionStart);
|
||||||
}
|
}
|
||||||
autoResizeTextarea(target);
|
autoResizeTextarea(target);
|
||||||
|
target.dispatchEvent(new Event('input'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -1545,6 +1549,7 @@ const Textarea = forwardRef((props, ref) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
composeHighlightRef.current.scrollTop = target.scrollTop;
|
||||||
}}
|
}}
|
||||||
onInput={(e) => {
|
onInput={(e) => {
|
||||||
const { target } = e;
|
const { target } = e;
|
||||||
|
|
Loading…
Add table
Reference in a new issue