It's time for Intl.Segmenter

Remove runes2
This commit is contained in:
Lim Chee Aun 2024-03-04 19:38:46 +08:00
parent e0c2570875
commit 531147cbc3
4 changed files with 49 additions and 37 deletions

49
package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@formatjs/intl-localematcher": "~0.5.4", "@formatjs/intl-localematcher": "~0.5.4",
"@formatjs/intl-segmenter": "~11.5.5",
"@formkit/auto-animate": "~0.8.1", "@formkit/auto-animate": "~0.8.1",
"@github/text-expander-element": "~2.6.1", "@github/text-expander-element": "~2.6.1",
"@iconify-icons/mingcute": "~1.2.9", "@iconify-icons/mingcute": "~1.2.9",
@ -33,8 +34,7 @@
"react-intersection-observer": "~9.8.1", "react-intersection-observer": "~9.8.1",
"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.4", "string-length": "6.0.0",
"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",
"uid": "~2.0.2", "uid": "~2.0.2",
@ -2924,6 +2924,15 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@formatjs/ecma402-abstract": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.18.2.tgz",
"integrity": "sha512-+QoPW4csYALsQIl8GbN14igZzDbuwzcpWrku9nyMXlaqAlwRBgl5V+p0vWMGFqHOw37czNXaP/lEk4wbLgcmtA==",
"dependencies": {
"@formatjs/intl-localematcher": "0.5.4",
"tslib": "^2.4.0"
}
},
"node_modules/@formatjs/intl-localematcher": { "node_modules/@formatjs/intl-localematcher": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz", "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.4.tgz",
@ -2932,6 +2941,16 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/@formatjs/intl-segmenter": {
"version": "11.5.5",
"resolved": "https://registry.npmjs.org/@formatjs/intl-segmenter/-/intl-segmenter-11.5.5.tgz",
"integrity": "sha512-mMbJKFGzwYJBcwfL9EfqFje75Ce5WPar5rSi7wWvFtBPFY2Zi1cWIss7FSm2MNNM9l1BycBAsBQuXFt+Hd+0tQ==",
"dependencies": {
"@formatjs/ecma402-abstract": "1.18.2",
"@formatjs/intl-localematcher": "0.5.4",
"tslib": "^2.4.0"
}
},
"node_modules/@formkit/auto-animate": { "node_modules/@formkit/auto-animate": {
"version": "0.8.1", "version": "0.8.1",
"resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-0.8.1.tgz", "resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-0.8.1.tgz",
@ -3967,15 +3986,6 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/char-regex": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/char-regex/-/char-regex-2.0.1.tgz",
"integrity": "sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==",
"license": "MIT",
"engines": {
"node": ">=12.20"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "1.9.3", "version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -7116,11 +7126,6 @@
"queue-microtask": "^1.2.2" "queue-microtask": "^1.2.2"
} }
}, },
"node_modules/runes2": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/runes2/-/runes2-1.1.4.tgz",
"integrity": "sha512-LNPnEDPOOU4ehF71m5JoQyzT2yxwD6ZreFJ7MxZUAoMKNMY1XrAo60H1CUoX5ncSm0rIuKlqn9JZNRrRkNou2g=="
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -7262,16 +7267,14 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/string-length": { "node_modules/string-length": {
"version": "5.0.1", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-5.0.1.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-6.0.0.tgz",
"integrity": "sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==", "integrity": "sha512-1U361pxZHEQ+FeSjzqRpV+cu2vTzYeWeafXFLykiFlv4Vc0n3njgU8HrMbyik5uwm77naWMuVG8fhEF+Ovb1Kg==",
"license": "MIT",
"dependencies": { "dependencies": {
"char-regex": "^2.0.0", "strip-ansi": "^7.1.0"
"strip-ansi": "^7.0.1"
}, },
"engines": { "engines": {
"node": ">=12.20" "node": ">=16"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"

View file

@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@formatjs/intl-localematcher": "~0.5.4", "@formatjs/intl-localematcher": "~0.5.4",
"@formatjs/intl-segmenter": "~11.5.5",
"@formkit/auto-animate": "~0.8.1", "@formkit/auto-animate": "~0.8.1",
"@github/text-expander-element": "~2.6.1", "@github/text-expander-element": "~2.6.1",
"@iconify-icons/mingcute": "~1.2.9", "@iconify-icons/mingcute": "~1.2.9",
@ -35,8 +36,7 @@
"react-intersection-observer": "~9.8.1", "react-intersection-observer": "~9.8.1",
"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.4", "string-length": "6.0.0",
"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",
"uid": "~2.0.2", "uid": "~2.0.2",

View file

@ -6,7 +6,6 @@ import { deepEqual } from 'fast-equals';
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,6 +130,7 @@ const SCAN_RE = new RegExp(
'g', 'g',
); );
const segmenter = new Intl.Segmenter();
function highlightText(text, { maxCharacters = Infinity }) { function highlightText(text, { maxCharacters = Infinity }) {
// Accept text string, return formatted HTML string // Accept text string, return formatted HTML string
// Escape all HTML special characters // Escape all HTML special characters
@ -143,19 +143,25 @@ function highlightText(text, { maxCharacters = Infinity }) {
// Exceeded characters limit // Exceeded characters limit
const { composerCharacterCount } = states; const { composerCharacterCount } = states;
let leftoverHTML = '';
if (composerCharacterCount > maxCharacters) { if (composerCharacterCount > maxCharacters) {
// NOTE: runes2 substring considers surrogate pairs
// const leftoverCount = composerCharacterCount - maxCharacters;
// Highlight exceeded characters // Highlight exceeded characters
leftoverHTML = let withinLimitHTML = '',
exceedLimitHTML = '';
const htmlSegments = segmenter.segment(html);
for (const { segment, index } of htmlSegments) {
if (index < maxCharacters) {
withinLimitHTML += segment;
} else {
exceedLimitHTML += segment;
}
}
if (exceedLimitHTML) {
exceedLimitHTML =
'<mark class="compose-highlight-exceeded">' + '<mark class="compose-highlight-exceeded">' +
// html.slice(-leftoverCount) + exceedLimitHTML +
substring(html, maxCharacters) +
'</mark>'; '</mark>';
// html = html.slice(0, -leftoverCount); }
html = substring(html, 0, maxCharacters); return withinLimitHTML + exceedLimitHTML;
return html + leftoverHTML;
} }
return html return html

View file

@ -2,6 +2,9 @@ import './index.css';
import './cloak-mode.css'; import './cloak-mode.css';
// Polyfill needed for Firefox < 122
// https://bugzilla.mozilla.org/show_bug.cgi?id=1423593
import '@formatjs/intl-segmenter/polyfill';
import { render } from 'preact'; import { render } from 'preact';
import { HashRouter } from 'react-router-dom'; import { HashRouter } from 'react-router-dom';