@tldraw/utils 5.4.0-canary.fa89ff126c46 → 5.4.0-next.038cf4b0c054
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +0 -10
- package/dist-cjs/index.js +1 -2
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/string.js +3 -21
- package/dist-cjs/lib/string.js.map +2 -2
- package/dist-esm/index.d.mts +0 -10
- package/dist-esm/index.mjs +2 -3
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/string.mjs +3 -21
- package/dist-esm/lib/string.mjs.map +2 -2
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/lib/string.test.ts +1 -58
- package/src/lib/string.ts +2 -35
package/dist-cjs/index.d.ts
CHANGED
|
@@ -795,16 +795,6 @@ export declare function isNonNull<T>(value: T): value is typeof value extends nu
|
|
|
795
795
|
*/
|
|
796
796
|
export declare function isNonNullish<T>(value: T): value is typeof value extends undefined ? never : typeof value extends null ? never : T;
|
|
797
797
|
|
|
798
|
-
/**
|
|
799
|
-
* Iterate over the grapheme clusters of a string — user-perceived characters such as emoji
|
|
800
|
-
* sequences, flags, and accented letters — instead of UTF-16 code units. Uses `Intl.Segmenter`
|
|
801
|
-
* where available and falls back to iterating by code point on browsers that lack it, where a
|
|
802
|
-
* multi-code-point cluster is yielded as its component code points rather than as one segment.
|
|
803
|
-
*
|
|
804
|
-
* @public
|
|
805
|
-
*/
|
|
806
|
-
export declare function iterateGraphemes(str: string): IterableIterator<string>;
|
|
807
|
-
|
|
808
798
|
/**
|
|
809
799
|
* A type representing a JSON array containing any valid JSON values.
|
|
810
800
|
* Arrays can contain mixed types of JSON values including nested arrays and objects.
|
package/dist-cjs/index.js
CHANGED
|
@@ -89,7 +89,6 @@ __export(index_exports, {
|
|
|
89
89
|
isNativeStructuredClone: () => import_value.isNativeStructuredClone,
|
|
90
90
|
isNonNull: () => import_value.isNonNull,
|
|
91
91
|
isNonNullish: () => import_value.isNonNullish,
|
|
92
|
-
iterateGraphemes: () => import_string.iterateGraphemes,
|
|
93
92
|
last: () => import_array.last,
|
|
94
93
|
lerp: () => import_number.lerp,
|
|
95
94
|
lns: () => import_hash.lns,
|
|
@@ -174,7 +173,7 @@ var import_version2 = require("./lib/version");
|
|
|
174
173
|
var import_warn = require("./lib/warn");
|
|
175
174
|
(0, import_version.registerTldrawLibraryVersion)(
|
|
176
175
|
"@tldraw/utils",
|
|
177
|
-
"5.4.0-
|
|
176
|
+
"5.4.0-next.038cf4b0c054",
|
|
178
177
|
"cjs"
|
|
179
178
|
);
|
|
180
179
|
//# sourceMappingURL=index.js.map
|
package/dist-cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerTldrawLibraryVersion } from './lib/version'\n\nexport { default as isEqual } from 'lodash.isequal'\nexport { default as isEqualWith } from 'lodash.isequalwith'\nexport { default as throttle } from 'lodash.throttle'\nexport { default as uniq } from 'lodash.uniq'\nexport {\n\tareArraysShallowEqual,\n\tcompact,\n\tdedupe,\n\tlast,\n\tmaxBy,\n\tmergeArraysAndReplaceDefaults,\n\tminBy,\n\tpartition,\n\trotateArray,\n} from './lib/array'\nexport { bind } from './lib/bind'\nexport { WeakCache } from './lib/cache'\nexport {\n\tassert,\n\tassertExists,\n\texhaustiveSwitchError,\n\tpromiseWithResolve,\n\tResult,\n\tsleep,\n\ttype ErrorResult,\n\ttype OkResult,\n} from './lib/control'\nexport { debounce } from './lib/debounce'\nexport { annotateError, getErrorAnnotations, type ErrorAnnotations } from './lib/error'\nexport { ExecutionQueue } from './lib/ExecutionQueue'\nexport { FileHelpers } from './lib/file'\nexport { noop, omitFromStackTrace } from './lib/function'\nexport { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'\nexport { mockUniqueId, restoreUniqueId, uniqueId } from './lib/id'\nexport { getFirstFromIterable } from './lib/iterable'\nexport { LruCache } from './lib/LruCache'\nexport type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'\nexport {\n\tDEFAULT_SUPPORT_VIDEO_TYPES,\n\tDEFAULT_SUPPORTED_IMAGE_TYPES,\n\tDEFAULT_SUPPORTED_MEDIA_TYPE_LIST,\n\tDEFAULT_SUPPORTED_MEDIA_TYPES,\n\tMediaHelpers,\n} from './lib/media/media'\nexport { PngHelpers } from './lib/media/png'\nexport { fetch, Image } from './lib/network'\nexport { invLerp, lerp, modulate, rng } from './lib/number'\nexport {\n\tareObjectsShallowEqual,\n\tfilterEntries,\n\tgetChangedKeys,\n\tgetOwnProperty,\n\tgroupBy,\n\thasOwnProperty,\n\tisEqualAllowingForFloatingPointErrors,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n\tobjectMapEntriesIterable,\n\tobjectMapFromEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tomit,\n} from './lib/object'\nexport { measureAverageDuration, measureCbDuration, measureDuration } from './lib/perf'\nexport { PerformanceTracker } from './lib/PerformanceTracker'\nexport {\n\tgetIndexAbove,\n\tgetIndexBelow,\n\tgetIndexBetween,\n\tgetIndices,\n\tgetIndicesAbove,\n\tgetIndicesBelow,\n\tgetIndicesBetween,\n\tsortByIndex,\n\tsortByMaybeIndex,\n\tvalidateIndexKey,\n\tZERO_INDEX_KEY,\n\ttype IndexKey,\n} from './lib/reordering'\nexport { retry } from './lib/retry'\nexport { sortById } from './lib/sort'\nexport {\n\tclearLocalStorage,\n\tclearSessionStorage,\n\tdeleteFromLocalStorage,\n\tdeleteFromSessionStorage,\n\tgetFromLocalStorage,\n\tgetFromSessionStorage,\n\tsetInLocalStorage,\n\tsetInSessionStorage,\n} from './lib/storage'\nexport { getFirstCharacter
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA
|
|
4
|
+
"sourcesContent": ["import { registerTldrawLibraryVersion } from './lib/version'\n\nexport { default as isEqual } from 'lodash.isequal'\nexport { default as isEqualWith } from 'lodash.isequalwith'\nexport { default as throttle } from 'lodash.throttle'\nexport { default as uniq } from 'lodash.uniq'\nexport {\n\tareArraysShallowEqual,\n\tcompact,\n\tdedupe,\n\tlast,\n\tmaxBy,\n\tmergeArraysAndReplaceDefaults,\n\tminBy,\n\tpartition,\n\trotateArray,\n} from './lib/array'\nexport { bind } from './lib/bind'\nexport { WeakCache } from './lib/cache'\nexport {\n\tassert,\n\tassertExists,\n\texhaustiveSwitchError,\n\tpromiseWithResolve,\n\tResult,\n\tsleep,\n\ttype ErrorResult,\n\ttype OkResult,\n} from './lib/control'\nexport { debounce } from './lib/debounce'\nexport { annotateError, getErrorAnnotations, type ErrorAnnotations } from './lib/error'\nexport { ExecutionQueue } from './lib/ExecutionQueue'\nexport { FileHelpers } from './lib/file'\nexport { noop, omitFromStackTrace } from './lib/function'\nexport { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'\nexport { mockUniqueId, restoreUniqueId, uniqueId } from './lib/id'\nexport { getFirstFromIterable } from './lib/iterable'\nexport { LruCache } from './lib/LruCache'\nexport type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'\nexport {\n\tDEFAULT_SUPPORT_VIDEO_TYPES,\n\tDEFAULT_SUPPORTED_IMAGE_TYPES,\n\tDEFAULT_SUPPORTED_MEDIA_TYPE_LIST,\n\tDEFAULT_SUPPORTED_MEDIA_TYPES,\n\tMediaHelpers,\n} from './lib/media/media'\nexport { PngHelpers } from './lib/media/png'\nexport { fetch, Image } from './lib/network'\nexport { invLerp, lerp, modulate, rng } from './lib/number'\nexport {\n\tareObjectsShallowEqual,\n\tfilterEntries,\n\tgetChangedKeys,\n\tgetOwnProperty,\n\tgroupBy,\n\thasOwnProperty,\n\tisEqualAllowingForFloatingPointErrors,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n\tobjectMapEntriesIterable,\n\tobjectMapFromEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tomit,\n} from './lib/object'\nexport { measureAverageDuration, measureCbDuration, measureDuration } from './lib/perf'\nexport { PerformanceTracker } from './lib/PerformanceTracker'\nexport {\n\tgetIndexAbove,\n\tgetIndexBelow,\n\tgetIndexBetween,\n\tgetIndices,\n\tgetIndicesAbove,\n\tgetIndicesBelow,\n\tgetIndicesBetween,\n\tsortByIndex,\n\tsortByMaybeIndex,\n\tvalidateIndexKey,\n\tZERO_INDEX_KEY,\n\ttype IndexKey,\n} from './lib/reordering'\nexport { retry } from './lib/retry'\nexport { sortById } from './lib/sort'\nexport {\n\tclearLocalStorage,\n\tclearSessionStorage,\n\tdeleteFromLocalStorage,\n\tdeleteFromSessionStorage,\n\tgetFromLocalStorage,\n\tgetFromSessionStorage,\n\tsetInLocalStorage,\n\tsetInSessionStorage,\n} from './lib/storage'\nexport { getFirstCharacter } from './lib/string'\nexport { stringEnum } from './lib/stringEnum'\nexport { FpsScheduler, fpsThrottle, throttleToNextFrame } from './lib/throttle'\nexport { Timers } from './lib/timers'\nexport {\n\ttype Awaitable,\n\ttype Expand,\n\ttype MakeUndefinedOptional,\n\ttype RecursivePartial,\n\ttype Required,\n} from './lib/types'\nexport { safeParseUrl } from './lib/url'\nexport {\n\tisDefined,\n\tisNativeStructuredClone,\n\tisNonNull,\n\tisNonNullish,\n\tSTRUCTURED_CLONE_OBJECT_PROTOTYPE,\n\tstructuredClone,\n} from './lib/value'\nexport { registerTldrawLibraryVersion } from './lib/version'\nexport { warnDeprecatedGetter, warnOnce } from './lib/warn'\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA6C;AAE7C,oBAAmC;AACnC,IAAAA,iBAAuC;AACvC,IAAAA,iBAAoC;AACpC,IAAAA,iBAAgC;AAChC,mBAUO;AACP,kBAAqB;AACrB,mBAA0B;AAC1B,qBASO;AACP,sBAAyB;AACzB,mBAA0E;AAC1E,4BAA+B;AAC/B,kBAA4B;AAC5B,sBAAyC;AACzC,kBAA0E;AAC1E,gBAAwD;AACxD,sBAAqC;AACrC,sBAAyB;AAEzB,mBAMO;AACP,iBAA2B;AAC3B,qBAA6B;AAC7B,oBAA6C;AAC7C,oBAeO;AACP,kBAA2E;AAC3E,gCAAmC;AACnC,wBAaO;AACP,mBAAsB;AACtB,kBAAyB;AACzB,qBASO;AACP,oBAAkC;AAClC,wBAA2B;AAC3B,sBAA+D;AAC/D,oBAAuB;AAQvB,iBAA6B;AAC7B,mBAOO;AACP,IAAAC,kBAA6C;AAC7C,kBAA+C;AAAA,IAE/C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
|
|
6
6
|
"names": ["import_lodash", "import_version"]
|
|
7
7
|
}
|
package/dist-cjs/lib/string.js
CHANGED
|
@@ -18,32 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var string_exports = {};
|
|
20
20
|
__export(string_exports, {
|
|
21
|
-
getFirstCharacter: () => getFirstCharacter
|
|
22
|
-
iterateGraphemes: () => iterateGraphemes
|
|
21
|
+
getFirstCharacter: () => getFirstCharacter
|
|
23
22
|
});
|
|
24
23
|
module.exports = __toCommonJS(string_exports);
|
|
25
24
|
let graphemeSegmenter;
|
|
26
|
-
let checkedForSegmenter = false;
|
|
27
|
-
function getGraphemeSegmenter() {
|
|
28
|
-
if (!checkedForSegmenter) {
|
|
29
|
-
checkedForSegmenter = true;
|
|
30
|
-
if (typeof Intl !== "undefined" && "Segmenter" in Intl) {
|
|
31
|
-
graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return graphemeSegmenter;
|
|
35
|
-
}
|
|
36
|
-
function* iterateGraphemes(str) {
|
|
37
|
-
const segmenter = getGraphemeSegmenter();
|
|
38
|
-
if (segmenter) {
|
|
39
|
-
for (const { segment } of segmenter.segment(str)) yield segment;
|
|
40
|
-
} else {
|
|
41
|
-
yield* str;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
25
|
function getFirstCharacter(str) {
|
|
45
26
|
if (!str) return "";
|
|
46
|
-
|
|
27
|
+
graphemeSegmenter ??= new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
28
|
+
for (const { segment } of graphemeSegmenter.segment(str)) {
|
|
47
29
|
return segment;
|
|
48
30
|
}
|
|
49
31
|
return "";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/string.ts"],
|
|
4
|
-
"sourcesContent": ["let graphemeSegmenter: Intl.Segmenter | undefined\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA
|
|
4
|
+
"sourcesContent": ["let graphemeSegmenter: Intl.Segmenter | undefined\n\n/**\n * Get the first character of a string, treating a multi-code-unit character such as an emoji as a\n * single character. Unlike `str[0]` or `str.charAt(0)`, which return one UTF-16 code unit and so\n * split an emoji into a broken half, this returns the first whole grapheme cluster. Returns an\n * empty string when the input is empty.\n *\n * @example\n * ```ts\n * getFirstCharacter('hello') // 'h'\n * getFirstCharacter('\uD83D\uDE00 hello') // '\uD83D\uDE00'\n * getFirstCharacter('') // ''\n * ```\n *\n * @public\n */\nexport function getFirstCharacter(str: string): string {\n\tif (!str) return ''\n\tgraphemeSegmenter ??= new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\tfor (const { segment } of graphemeSegmenter.segment(str)) {\n\t\treturn segment\n\t}\n\treturn ''\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAI;AAiBG,SAAS,kBAAkB,KAAqB;AACtD,MAAI,CAAC,IAAK,QAAO;AACjB,wBAAsB,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAC/E,aAAW,EAAE,QAAQ,KAAK,kBAAkB,QAAQ,GAAG,GAAG;AACzD,WAAO;AAAA,EACR;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.d.mts
CHANGED
|
@@ -795,16 +795,6 @@ export declare function isNonNull<T>(value: T): value is typeof value extends nu
|
|
|
795
795
|
*/
|
|
796
796
|
export declare function isNonNullish<T>(value: T): value is typeof value extends undefined ? never : typeof value extends null ? never : T;
|
|
797
797
|
|
|
798
|
-
/**
|
|
799
|
-
* Iterate over the grapheme clusters of a string — user-perceived characters such as emoji
|
|
800
|
-
* sequences, flags, and accented letters — instead of UTF-16 code units. Uses `Intl.Segmenter`
|
|
801
|
-
* where available and falls back to iterating by code point on browsers that lack it, where a
|
|
802
|
-
* multi-code-point cluster is yielded as its component code points rather than as one segment.
|
|
803
|
-
*
|
|
804
|
-
* @public
|
|
805
|
-
*/
|
|
806
|
-
export declare function iterateGraphemes(str: string): IterableIterator<string>;
|
|
807
|
-
|
|
808
798
|
/**
|
|
809
799
|
* A type representing a JSON array containing any valid JSON values.
|
|
810
800
|
* Arrays can contain mixed types of JSON values including nested arrays and objects.
|
package/dist-esm/index.mjs
CHANGED
|
@@ -86,7 +86,7 @@ import {
|
|
|
86
86
|
setInLocalStorage,
|
|
87
87
|
setInSessionStorage
|
|
88
88
|
} from "./lib/storage.mjs";
|
|
89
|
-
import { getFirstCharacter
|
|
89
|
+
import { getFirstCharacter } from "./lib/string.mjs";
|
|
90
90
|
import { stringEnum } from "./lib/stringEnum.mjs";
|
|
91
91
|
import { FpsScheduler, fpsThrottle, throttleToNextFrame } from "./lib/throttle.mjs";
|
|
92
92
|
import { Timers } from "./lib/timers.mjs";
|
|
@@ -103,7 +103,7 @@ import { registerTldrawLibraryVersion as registerTldrawLibraryVersion2 } from ".
|
|
|
103
103
|
import { warnDeprecatedGetter, warnOnce } from "./lib/warn.mjs";
|
|
104
104
|
registerTldrawLibraryVersion(
|
|
105
105
|
"@tldraw/utils",
|
|
106
|
-
"5.4.0-
|
|
106
|
+
"5.4.0-next.038cf4b0c054",
|
|
107
107
|
"esm"
|
|
108
108
|
);
|
|
109
109
|
export {
|
|
@@ -168,7 +168,6 @@ export {
|
|
|
168
168
|
isNativeStructuredClone,
|
|
169
169
|
isNonNull,
|
|
170
170
|
isNonNullish,
|
|
171
|
-
iterateGraphemes,
|
|
172
171
|
last,
|
|
173
172
|
lerp,
|
|
174
173
|
lns,
|
package/dist-esm/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerTldrawLibraryVersion } from './lib/version'\n\nexport { default as isEqual } from 'lodash.isequal'\nexport { default as isEqualWith } from 'lodash.isequalwith'\nexport { default as throttle } from 'lodash.throttle'\nexport { default as uniq } from 'lodash.uniq'\nexport {\n\tareArraysShallowEqual,\n\tcompact,\n\tdedupe,\n\tlast,\n\tmaxBy,\n\tmergeArraysAndReplaceDefaults,\n\tminBy,\n\tpartition,\n\trotateArray,\n} from './lib/array'\nexport { bind } from './lib/bind'\nexport { WeakCache } from './lib/cache'\nexport {\n\tassert,\n\tassertExists,\n\texhaustiveSwitchError,\n\tpromiseWithResolve,\n\tResult,\n\tsleep,\n\ttype ErrorResult,\n\ttype OkResult,\n} from './lib/control'\nexport { debounce } from './lib/debounce'\nexport { annotateError, getErrorAnnotations, type ErrorAnnotations } from './lib/error'\nexport { ExecutionQueue } from './lib/ExecutionQueue'\nexport { FileHelpers } from './lib/file'\nexport { noop, omitFromStackTrace } from './lib/function'\nexport { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'\nexport { mockUniqueId, restoreUniqueId, uniqueId } from './lib/id'\nexport { getFirstFromIterable } from './lib/iterable'\nexport { LruCache } from './lib/LruCache'\nexport type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'\nexport {\n\tDEFAULT_SUPPORT_VIDEO_TYPES,\n\tDEFAULT_SUPPORTED_IMAGE_TYPES,\n\tDEFAULT_SUPPORTED_MEDIA_TYPE_LIST,\n\tDEFAULT_SUPPORTED_MEDIA_TYPES,\n\tMediaHelpers,\n} from './lib/media/media'\nexport { PngHelpers } from './lib/media/png'\nexport { fetch, Image } from './lib/network'\nexport { invLerp, lerp, modulate, rng } from './lib/number'\nexport {\n\tareObjectsShallowEqual,\n\tfilterEntries,\n\tgetChangedKeys,\n\tgetOwnProperty,\n\tgroupBy,\n\thasOwnProperty,\n\tisEqualAllowingForFloatingPointErrors,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n\tobjectMapEntriesIterable,\n\tobjectMapFromEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tomit,\n} from './lib/object'\nexport { measureAverageDuration, measureCbDuration, measureDuration } from './lib/perf'\nexport { PerformanceTracker } from './lib/PerformanceTracker'\nexport {\n\tgetIndexAbove,\n\tgetIndexBelow,\n\tgetIndexBetween,\n\tgetIndices,\n\tgetIndicesAbove,\n\tgetIndicesBelow,\n\tgetIndicesBetween,\n\tsortByIndex,\n\tsortByMaybeIndex,\n\tvalidateIndexKey,\n\tZERO_INDEX_KEY,\n\ttype IndexKey,\n} from './lib/reordering'\nexport { retry } from './lib/retry'\nexport { sortById } from './lib/sort'\nexport {\n\tclearLocalStorage,\n\tclearSessionStorage,\n\tdeleteFromLocalStorage,\n\tdeleteFromSessionStorage,\n\tgetFromLocalStorage,\n\tgetFromSessionStorage,\n\tsetInLocalStorage,\n\tsetInSessionStorage,\n} from './lib/storage'\nexport { getFirstCharacter
|
|
5
|
-
"mappings": "AAAA,SAAS,oCAAoC;AAE7C,SAAoB,WAAXA,gBAA0B;AACnC,SAAoB,WAAXA,gBAA8B;AACvC,SAAoB,WAAXA,gBAA2B;AACpC,SAAoB,WAAXA,gBAAuB;AAChC;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGM;AACP,SAAS,gBAAgB;AACzB,SAAS,eAAe,2BAAkD;AAC1E,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAC5B,SAAS,MAAM,0BAA0B;AACzC,SAAS,kBAAkB,kBAAkB,kBAAkB,WAAW;AAC1E,SAAS,cAAc,iBAAiB,gBAAgB;AACxD,SAAS,4BAA4B;AACrC,SAAS,gBAAgB;AAEzB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,kBAAkB;AAC3B,SAAS,OAAO,aAAa;AAC7B,SAAS,SAAS,MAAM,UAAU,WAAW;AAC7C;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,wBAAwB,mBAAmB,uBAAuB;AAC3E,SAAS,0BAA0B;AACnC;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEM;AACP,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,
|
|
4
|
+
"sourcesContent": ["import { registerTldrawLibraryVersion } from './lib/version'\n\nexport { default as isEqual } from 'lodash.isequal'\nexport { default as isEqualWith } from 'lodash.isequalwith'\nexport { default as throttle } from 'lodash.throttle'\nexport { default as uniq } from 'lodash.uniq'\nexport {\n\tareArraysShallowEqual,\n\tcompact,\n\tdedupe,\n\tlast,\n\tmaxBy,\n\tmergeArraysAndReplaceDefaults,\n\tminBy,\n\tpartition,\n\trotateArray,\n} from './lib/array'\nexport { bind } from './lib/bind'\nexport { WeakCache } from './lib/cache'\nexport {\n\tassert,\n\tassertExists,\n\texhaustiveSwitchError,\n\tpromiseWithResolve,\n\tResult,\n\tsleep,\n\ttype ErrorResult,\n\ttype OkResult,\n} from './lib/control'\nexport { debounce } from './lib/debounce'\nexport { annotateError, getErrorAnnotations, type ErrorAnnotations } from './lib/error'\nexport { ExecutionQueue } from './lib/ExecutionQueue'\nexport { FileHelpers } from './lib/file'\nexport { noop, omitFromStackTrace } from './lib/function'\nexport { getHashForBuffer, getHashForObject, getHashForString, lns } from './lib/hash'\nexport { mockUniqueId, restoreUniqueId, uniqueId } from './lib/id'\nexport { getFirstFromIterable } from './lib/iterable'\nexport { LruCache } from './lib/LruCache'\nexport type { JsonArray, JsonObject, JsonPrimitive, JsonValue } from './lib/json-value'\nexport {\n\tDEFAULT_SUPPORT_VIDEO_TYPES,\n\tDEFAULT_SUPPORTED_IMAGE_TYPES,\n\tDEFAULT_SUPPORTED_MEDIA_TYPE_LIST,\n\tDEFAULT_SUPPORTED_MEDIA_TYPES,\n\tMediaHelpers,\n} from './lib/media/media'\nexport { PngHelpers } from './lib/media/png'\nexport { fetch, Image } from './lib/network'\nexport { invLerp, lerp, modulate, rng } from './lib/number'\nexport {\n\tareObjectsShallowEqual,\n\tfilterEntries,\n\tgetChangedKeys,\n\tgetOwnProperty,\n\tgroupBy,\n\thasOwnProperty,\n\tisEqualAllowingForFloatingPointErrors,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n\tobjectMapEntriesIterable,\n\tobjectMapFromEntries,\n\tobjectMapKeys,\n\tobjectMapValues,\n\tomit,\n} from './lib/object'\nexport { measureAverageDuration, measureCbDuration, measureDuration } from './lib/perf'\nexport { PerformanceTracker } from './lib/PerformanceTracker'\nexport {\n\tgetIndexAbove,\n\tgetIndexBelow,\n\tgetIndexBetween,\n\tgetIndices,\n\tgetIndicesAbove,\n\tgetIndicesBelow,\n\tgetIndicesBetween,\n\tsortByIndex,\n\tsortByMaybeIndex,\n\tvalidateIndexKey,\n\tZERO_INDEX_KEY,\n\ttype IndexKey,\n} from './lib/reordering'\nexport { retry } from './lib/retry'\nexport { sortById } from './lib/sort'\nexport {\n\tclearLocalStorage,\n\tclearSessionStorage,\n\tdeleteFromLocalStorage,\n\tdeleteFromSessionStorage,\n\tgetFromLocalStorage,\n\tgetFromSessionStorage,\n\tsetInLocalStorage,\n\tsetInSessionStorage,\n} from './lib/storage'\nexport { getFirstCharacter } from './lib/string'\nexport { stringEnum } from './lib/stringEnum'\nexport { FpsScheduler, fpsThrottle, throttleToNextFrame } from './lib/throttle'\nexport { Timers } from './lib/timers'\nexport {\n\ttype Awaitable,\n\ttype Expand,\n\ttype MakeUndefinedOptional,\n\ttype RecursivePartial,\n\ttype Required,\n} from './lib/types'\nexport { safeParseUrl } from './lib/url'\nexport {\n\tisDefined,\n\tisNativeStructuredClone,\n\tisNonNull,\n\tisNonNullish,\n\tSTRUCTURED_CLONE_OBJECT_PROTOTYPE,\n\tstructuredClone,\n} from './lib/value'\nexport { registerTldrawLibraryVersion } from './lib/version'\nexport { warnDeprecatedGetter, warnOnce } from './lib/warn'\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oCAAoC;AAE7C,SAAoB,WAAXA,gBAA0B;AACnC,SAAoB,WAAXA,gBAA8B;AACvC,SAAoB,WAAXA,gBAA2B;AACpC,SAAoB,WAAXA,gBAAuB;AAChC;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAC1B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGM;AACP,SAAS,gBAAgB;AACzB,SAAS,eAAe,2BAAkD;AAC1E,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAC5B,SAAS,MAAM,0BAA0B;AACzC,SAAS,kBAAkB,kBAAkB,kBAAkB,WAAW;AAC1E,SAAS,cAAc,iBAAiB,gBAAgB;AACxD,SAAS,4BAA4B;AACrC,SAAS,gBAAgB;AAEzB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,kBAAkB;AAC3B,SAAS,OAAO,aAAa;AAC7B,SAAS,SAAS,MAAM,UAAU,WAAW;AAC7C;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,wBAAwB,mBAAmB,uBAAuB;AAC3E,SAAS,0BAA0B;AACnC;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEM;AACP,SAAS,aAAa;AACtB,SAAS,gBAAgB;AACzB;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,yBAAyB;AAClC,SAAS,kBAAkB;AAC3B,SAAS,cAAc,aAAa,2BAA2B;AAC/D,SAAS,cAAc;AAQvB,SAAS,oBAAoB;AAC7B;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,gCAAAC,qCAAoC;AAC7C,SAAS,sBAAsB,gBAAgB;AAE/C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
|
|
6
6
|
"names": ["default", "registerTldrawLibraryVersion"]
|
|
7
7
|
}
|
package/dist-esm/lib/string.mjs
CHANGED
|
@@ -1,31 +1,13 @@
|
|
|
1
1
|
let graphemeSegmenter;
|
|
2
|
-
let checkedForSegmenter = false;
|
|
3
|
-
function getGraphemeSegmenter() {
|
|
4
|
-
if (!checkedForSegmenter) {
|
|
5
|
-
checkedForSegmenter = true;
|
|
6
|
-
if (typeof Intl !== "undefined" && "Segmenter" in Intl) {
|
|
7
|
-
graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
return graphemeSegmenter;
|
|
11
|
-
}
|
|
12
|
-
function* iterateGraphemes(str) {
|
|
13
|
-
const segmenter = getGraphemeSegmenter();
|
|
14
|
-
if (segmenter) {
|
|
15
|
-
for (const { segment } of segmenter.segment(str)) yield segment;
|
|
16
|
-
} else {
|
|
17
|
-
yield* str;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
2
|
function getFirstCharacter(str) {
|
|
21
3
|
if (!str) return "";
|
|
22
|
-
|
|
4
|
+
graphemeSegmenter ??= new Intl.Segmenter(void 0, { granularity: "grapheme" });
|
|
5
|
+
for (const { segment } of graphemeSegmenter.segment(str)) {
|
|
23
6
|
return segment;
|
|
24
7
|
}
|
|
25
8
|
return "";
|
|
26
9
|
}
|
|
27
10
|
export {
|
|
28
|
-
getFirstCharacter
|
|
29
|
-
iterateGraphemes
|
|
11
|
+
getFirstCharacter
|
|
30
12
|
};
|
|
31
13
|
//# sourceMappingURL=string.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/string.ts"],
|
|
4
|
-
"sourcesContent": ["let graphemeSegmenter: Intl.Segmenter | undefined\
|
|
5
|
-
"mappings": "AAAA,IAAI;
|
|
4
|
+
"sourcesContent": ["let graphemeSegmenter: Intl.Segmenter | undefined\n\n/**\n * Get the first character of a string, treating a multi-code-unit character such as an emoji as a\n * single character. Unlike `str[0]` or `str.charAt(0)`, which return one UTF-16 code unit and so\n * split an emoji into a broken half, this returns the first whole grapheme cluster. Returns an\n * empty string when the input is empty.\n *\n * @example\n * ```ts\n * getFirstCharacter('hello') // 'h'\n * getFirstCharacter('\uD83D\uDE00 hello') // '\uD83D\uDE00'\n * getFirstCharacter('') // ''\n * ```\n *\n * @public\n */\nexport function getFirstCharacter(str: string): string {\n\tif (!str) return ''\n\tgraphemeSegmenter ??= new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\tfor (const { segment } of graphemeSegmenter.segment(str)) {\n\t\treturn segment\n\t}\n\treturn ''\n}\n"],
|
|
5
|
+
"mappings": "AAAA,IAAI;AAiBG,SAAS,kBAAkB,KAAqB;AACtD,MAAI,CAAC,IAAK,QAAO;AACjB,wBAAsB,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAC/E,aAAW,EAAE,QAAQ,KAAK,kBAAkB,QAAQ,GAAG,GAAG;AACzD,WAAO;AAAA,EACR;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -91,7 +91,7 @@ export {
|
|
|
91
91
|
setInLocalStorage,
|
|
92
92
|
setInSessionStorage,
|
|
93
93
|
} from './lib/storage'
|
|
94
|
-
export { getFirstCharacter
|
|
94
|
+
export { getFirstCharacter } from './lib/string'
|
|
95
95
|
export { stringEnum } from './lib/stringEnum'
|
|
96
96
|
export { FpsScheduler, fpsThrottle, throttleToNextFrame } from './lib/throttle'
|
|
97
97
|
export { Timers } from './lib/timers'
|
package/src/lib/string.test.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getFirstCharacter, iterateGraphemes } from './string'
|
|
1
|
+
import { getFirstCharacter } from './string'
|
|
3
2
|
|
|
4
3
|
describe('getFirstCharacter', () => {
|
|
5
4
|
it('returns the first character of a plain string', () => {
|
|
@@ -22,59 +21,3 @@ describe('getFirstCharacter', () => {
|
|
|
22
21
|
expect(getFirstCharacter(' hi')).toBe(' ')
|
|
23
22
|
})
|
|
24
23
|
})
|
|
25
|
-
|
|
26
|
-
describe('iterateGraphemes', () => {
|
|
27
|
-
it('yields each grapheme cluster in order', () => {
|
|
28
|
-
expect([...iterateGraphemes('a😀b')]).toEqual(['a', '😀', 'b'])
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('keeps a multi-code-point cluster whole', () => {
|
|
32
|
-
expect([...iterateGraphemes('👨👩👧!')]).toEqual(['👨👩👧', '!'])
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
it('yields nothing for an empty string', () => {
|
|
36
|
-
expect([...iterateGraphemes('')]).toEqual([])
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
// On browsers without `Intl.Segmenter` (e.g. Firefox before 125) the module must not throw and must
|
|
41
|
-
// still iterate; it falls back to code-point iteration. The segmenter is probed lazily on first
|
|
42
|
-
// use, so `Intl.Segmenter` has to be absent at call time — reset the module and remove the global
|
|
43
|
-
// for the duration of each call.
|
|
44
|
-
describe('grapheme iteration without Intl.Segmenter', () => {
|
|
45
|
-
afterEach(() => {
|
|
46
|
-
vi.resetModules()
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
async function withoutSegmenter<T>(fn: (mod: typeof import('./string')) => T): Promise<T> {
|
|
50
|
-
vi.resetModules()
|
|
51
|
-
// `Intl.Segmenter` is typed read-only; take a mutable view so we can remove and restore it.
|
|
52
|
-
const mutableIntl = Intl as { Segmenter?: typeof Intl.Segmenter }
|
|
53
|
-
const original = mutableIntl.Segmenter
|
|
54
|
-
delete mutableIntl.Segmenter
|
|
55
|
-
expect('Segmenter' in Intl).toBe(false)
|
|
56
|
-
try {
|
|
57
|
-
return fn(await import('./string'))
|
|
58
|
-
} finally {
|
|
59
|
-
mutableIntl.Segmenter = original
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
it('iterateGraphemes falls back to code-point iteration', async () => {
|
|
64
|
-
await withoutSegmenter(({ iterateGraphemes }) => {
|
|
65
|
-
expect([...iterateGraphemes('ab😀')]).toEqual(['a', 'b', '😀'])
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('getFirstCharacter keeps a surrogate pair whole', async () => {
|
|
70
|
-
await withoutSegmenter(({ getFirstCharacter }) => {
|
|
71
|
-
expect(getFirstCharacter('😀 hello')).toBe('😀')
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('getFirstCharacter splits a ZWJ cluster to its first code point rather than throwing', async () => {
|
|
76
|
-
await withoutSegmenter(({ getFirstCharacter }) => {
|
|
77
|
-
expect(getFirstCharacter('👨👩👧 family')).toBe('👨')
|
|
78
|
-
})
|
|
79
|
-
})
|
|
80
|
-
})
|
package/src/lib/string.ts
CHANGED
|
@@ -1,38 +1,4 @@
|
|
|
1
1
|
let graphemeSegmenter: Intl.Segmenter | undefined
|
|
2
|
-
let checkedForSegmenter = false
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Resolve a shared grapheme `Intl.Segmenter`, or `undefined` when the runtime has no
|
|
6
|
-
* `Intl.Segmenter`. `Intl.Segmenter` is unavailable on some older browsers (notably Firefox before
|
|
7
|
-
* 125), so feature-detect it once rather than constructing it eagerly, which would throw at module
|
|
8
|
-
* load and take down the whole app.
|
|
9
|
-
*/
|
|
10
|
-
function getGraphemeSegmenter(): Intl.Segmenter | undefined {
|
|
11
|
-
if (!checkedForSegmenter) {
|
|
12
|
-
checkedForSegmenter = true
|
|
13
|
-
if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {
|
|
14
|
-
graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return graphemeSegmenter
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Iterate over the grapheme clusters of a string — user-perceived characters such as emoji
|
|
22
|
-
* sequences, flags, and accented letters — instead of UTF-16 code units. Uses `Intl.Segmenter`
|
|
23
|
-
* where available and falls back to iterating by code point on browsers that lack it, where a
|
|
24
|
-
* multi-code-point cluster is yielded as its component code points rather than as one segment.
|
|
25
|
-
*
|
|
26
|
-
* @public
|
|
27
|
-
*/
|
|
28
|
-
export function* iterateGraphemes(str: string): IterableIterator<string> {
|
|
29
|
-
const segmenter = getGraphemeSegmenter()
|
|
30
|
-
if (segmenter) {
|
|
31
|
-
for (const { segment } of segmenter.segment(str)) yield segment
|
|
32
|
-
} else {
|
|
33
|
-
yield* str
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
2
|
|
|
37
3
|
/**
|
|
38
4
|
* Get the first character of a string, treating a multi-code-unit character such as an emoji as a
|
|
@@ -51,7 +17,8 @@ export function* iterateGraphemes(str: string): IterableIterator<string> {
|
|
|
51
17
|
*/
|
|
52
18
|
export function getFirstCharacter(str: string): string {
|
|
53
19
|
if (!str) return ''
|
|
54
|
-
|
|
20
|
+
graphemeSegmenter ??= new Intl.Segmenter(undefined, { granularity: 'grapheme' })
|
|
21
|
+
for (const { segment } of graphemeSegmenter.segment(str)) {
|
|
55
22
|
return segment
|
|
56
23
|
}
|
|
57
24
|
return ''
|