@tldraw/utils 5.4.0-canary.b8ec00e16e3a → 5.4.0-canary.bb69ad90a32d
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 +12 -2
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/id.js.map +2 -2
- package/dist-cjs/lib/string.js +21 -3
- package/dist-cjs/lib/string.js.map +2 -2
- package/dist-cjs/lib/version.js.map +1 -1
- package/dist-esm/index.d.mts +12 -2
- package/dist-esm/index.mjs +3 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/id.mjs.map +2 -2
- package/dist-esm/lib/string.mjs +21 -3
- package/dist-esm/lib/string.mjs.map +2 -2
- package/dist-esm/lib/version.mjs.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/lib/id.ts +1 -1
- package/src/lib/string.test.ts +58 -1
- package/src/lib/string.ts +35 -2
- package/src/lib/version.ts +2 -2
package/dist-cjs/index.d.ts
CHANGED
|
@@ -795,6 +795,16 @@ 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
|
+
|
|
798
808
|
/**
|
|
799
809
|
* A type representing a JSON array containing any valid JSON values.
|
|
800
810
|
* Arrays can contain mixed types of JSON values including nested arrays and objects.
|
|
@@ -1921,8 +1931,8 @@ export declare class Timers {
|
|
|
1921
1931
|
forContext(contextId: string): {
|
|
1922
1932
|
dispose: () => void;
|
|
1923
1933
|
requestAnimationFrame: (callback: FrameRequestCallback) => number;
|
|
1924
|
-
setInterval: (handler: TimerHandler, timeout?: number
|
|
1925
|
-
setTimeout: (handler: TimerHandler, timeout?: number
|
|
1934
|
+
setInterval: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
|
|
1935
|
+
setTimeout: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
|
|
1926
1936
|
};
|
|
1927
1937
|
}
|
|
1928
1938
|
|
package/dist-cjs/index.js
CHANGED
|
@@ -89,6 +89,7 @@ __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,
|
|
92
93
|
last: () => import_array.last,
|
|
93
94
|
lerp: () => import_number.lerp,
|
|
94
95
|
lns: () => import_hash.lns,
|
|
@@ -173,7 +174,7 @@ var import_version2 = require("./lib/version");
|
|
|
173
174
|
var import_warn = require("./lib/warn");
|
|
174
175
|
(0, import_version.registerTldrawLibraryVersion)(
|
|
175
176
|
"@tldraw/utils",
|
|
176
|
-
"5.4.0-canary.
|
|
177
|
+
"5.4.0-canary.bb69ad90a32d",
|
|
177
178
|
"cjs"
|
|
178
179
|
);
|
|
179
180
|
//# 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 } 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,
|
|
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, iterateGraphemes } 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;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,oBAAoD;AACpD,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/id.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/id.ts"],
|
|
4
|
-
"sourcesContent": ["/*!\n * MIT License: https://github.com/ai/nanoid/blob/main/LICENSE\n * Modified code originally from <https://github.com/ai/nanoid>\n * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n *\n * `nanoid` is currently only distributed as an ES module. Some tools (jest, playwright) don't\n * properly support ESM-only code yet, and tldraw itself is distributed as both an ES module and a\n * CommonJS module. By including nanoid here, we can make sure it works well in every environment\n * where tldraw is used. We can also remove some unused features like custom alphabets.\n */\n\n// all environments that tldraw runs in (browser, workers, recent node versions) have global\n// `crypto`\nconst crypto = globalThis.crypto\n\n// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compression.\n// Same as in non-secure/index.js\nconst urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n\n// It is best to make fewer, larger requests to the crypto module to\n// avoid system call overhead. So, random numbers are generated in a\n// pool. The pool is a Buffer that is larger than the initial random\n// request size by this multiplier. The pool is enlarged if subsequent\n// requests exceed the maximum buffer size.\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool: Uint8Array
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,MAAM,SAAS,WAAW;AAK1B,MAAM,cAAc;AAOpB,MAAM,uBAAuB;AAC7B,IAAI,
|
|
4
|
+
"sourcesContent": ["/*!\n * MIT License: https://github.com/ai/nanoid/blob/main/LICENSE\n * Modified code originally from <https://github.com/ai/nanoid>\n * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n *\n * `nanoid` is currently only distributed as an ES module. Some tools (jest, playwright) don't\n * properly support ESM-only code yet, and tldraw itself is distributed as both an ES module and a\n * CommonJS module. By including nanoid here, we can make sure it works well in every environment\n * where tldraw is used. We can also remove some unused features like custom alphabets.\n */\n\n// all environments that tldraw runs in (browser, workers, recent node versions) have global\n// `crypto`\nconst crypto = globalThis.crypto\n\n// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compression.\n// Same as in non-secure/index.js\nconst urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n\n// It is best to make fewer, larger requests to the crypto module to\n// avoid system call overhead. So, random numbers are generated in a\n// pool. The pool is a Buffer that is larger than the initial random\n// request size by this multiplier. The pool is enlarged if subsequent\n// requests exceed the maximum buffer size.\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool: Uint8Array<ArrayBuffer>, poolOffset: number\n\nfunction fillPool(bytes: number) {\n\tif (!pool || pool.length < bytes) {\n\t\tpool = new Uint8Array(bytes * POOL_SIZE_MULTIPLIER)\n\t\tcrypto.getRandomValues(pool)\n\t\tpoolOffset = 0\n\t} else if (poolOffset + bytes > pool.length) {\n\t\tcrypto.getRandomValues(pool)\n\t\tpoolOffset = 0\n\t}\n\tpoolOffset += bytes\n}\n\nfunction nanoid(size = 21) {\n\t// `-=` convert `size` to number to prevent `valueOf` abusing\n\tfillPool((size -= 0))\n\tlet id = ''\n\t// We are reading directly from the random pool to avoid creating new array\n\tfor (let i = poolOffset - size; i < poolOffset; i++) {\n\t\t// It is incorrect to use bytes exceeding the alphabet size.\n\t\t// The following mask reduces the random byte in the 0-255 value\n\t\t// range to the 0-63 value range. Therefore, adding hacks, such\n\t\t// as empty string fallback or magic numbers, is unnecessary because\n\t\t// the bitmask trims bytes down to the alphabet size.\n\t\tid += urlAlphabet[pool[i] & 63]\n\t}\n\treturn id\n}\n\nlet impl = nanoid\n/**\n * Mock the unique ID generator with a custom implementation for testing.\n *\n * Replaces the internal ID generation function with a custom one. This is useful\n * for testing scenarios where you need predictable or deterministic IDs.\n *\n * @param fn - The mock function that should return a string ID. Takes optional size parameter.\n * @example\n * ```ts\n * // Mock with predictable IDs for testing\n * mockUniqueId((size = 21) => 'test-id-' + size)\n * console.log(uniqueId()) // 'test-id-21'\n * console.log(uniqueId(10)) // 'test-id-10'\n *\n * // Restore original implementation when done\n * restoreUniqueId()\n * ```\n * @internal\n */\nexport function mockUniqueId(fn: (size?: number) => string) {\n\timpl = fn\n}\n\n/**\n * Restore the original unique ID generator after mocking.\n *\n * Resets the ID generation function back to the original nanoid implementation.\n * This should be called after testing to restore normal ID generation behavior.\n *\n * @example\n * ```ts\n * // After mocking for tests\n * mockUniqueId(() => 'mock-id')\n *\n * // Restore original behavior\n * restoreUniqueId()\n * console.log(uniqueId()) // Now generates real random IDs again\n * ```\n * @internal\n */\nexport function restoreUniqueId() {\n\timpl = nanoid\n}\n\n/**\n * Generate a unique ID using a modified nanoid algorithm.\n *\n * Generates a cryptographically secure random string ID using URL-safe characters.\n * The default size is 21 characters, which provides a good balance of uniqueness\n * and brevity. Uses the global crypto API for secure random number generation.\n *\n * @param size - Optional length of the generated ID (defaults to 21 characters)\n * @returns A unique string identifier\n * @example\n * ```ts\n * // Generate default 21-character ID\n * const id = uniqueId()\n * console.log(id) // 'V1StGXR8_Z5jdHi6B-myT'\n *\n * // Generate shorter ID\n * const shortId = uniqueId(10)\n * console.log(shortId) // 'V1StGXR8_Z'\n *\n * // Generate longer ID\n * const longId = uniqueId(32)\n * console.log(longId) // 'V1StGXR8_Z5jdHi6B-myTVKahvjdx...'\n * ```\n * @public\n */\nexport function uniqueId(size?: number): string {\n\treturn impl(size)\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,MAAM,SAAS,WAAW;AAK1B,MAAM,cAAc;AAOpB,MAAM,uBAAuB;AAC7B,IAAI,MAA+B;AAEnC,SAAS,SAAS,OAAe;AAChC,MAAI,CAAC,QAAQ,KAAK,SAAS,OAAO;AACjC,WAAO,IAAI,WAAW,QAAQ,oBAAoB;AAClD,WAAO,gBAAgB,IAAI;AAC3B,iBAAa;AAAA,EACd,WAAW,aAAa,QAAQ,KAAK,QAAQ;AAC5C,WAAO,gBAAgB,IAAI;AAC3B,iBAAa;AAAA,EACd;AACA,gBAAc;AACf;AAEA,SAAS,OAAO,OAAO,IAAI;AAE1B,WAAU,QAAQ,CAAE;AACpB,MAAI,KAAK;AAET,WAAS,IAAI,aAAa,MAAM,IAAI,YAAY,KAAK;AAMpD,UAAM,YAAY,KAAK,CAAC,IAAI,EAAE;AAAA,EAC/B;AACA,SAAO;AACR;AAEA,IAAI,OAAO;AAoBJ,SAAS,aAAa,IAA+B;AAC3D,SAAO;AACR;AAmBO,SAAS,kBAAkB;AACjC,SAAO;AACR;AA2BO,SAAS,SAAS,MAAuB;AAC/C,SAAO,KAAK,IAAI;AACjB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-cjs/lib/string.js
CHANGED
|
@@ -18,14 +18,32 @@ 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
|
|
21
|
+
getFirstCharacter: () => getFirstCharacter,
|
|
22
|
+
iterateGraphemes: () => iterateGraphemes
|
|
22
23
|
});
|
|
23
24
|
module.exports = __toCommonJS(string_exports);
|
|
24
25
|
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
|
+
}
|
|
25
44
|
function getFirstCharacter(str) {
|
|
26
45
|
if (!str) return "";
|
|
27
|
-
|
|
28
|
-
for (const { segment } of graphemeSegmenter.segment(str)) {
|
|
46
|
+
for (const segment of iterateGraphemes(str)) {
|
|
29
47
|
return segment;
|
|
30
48
|
}
|
|
31
49
|
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\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\
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAI;
|
|
4
|
+
"sourcesContent": ["let graphemeSegmenter: Intl.Segmenter | undefined\nlet checkedForSegmenter = false\n\n/**\n * Resolve a shared grapheme `Intl.Segmenter`, or `undefined` when the runtime has no\n * `Intl.Segmenter`. `Intl.Segmenter` is unavailable on some older browsers (notably Firefox before\n * 125), so feature-detect it once rather than constructing it eagerly, which would throw at module\n * load and take down the whole app.\n */\nfunction getGraphemeSegmenter(): Intl.Segmenter | undefined {\n\tif (!checkedForSegmenter) {\n\t\tcheckedForSegmenter = true\n\t\tif (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n\t\t\tgraphemeSegmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\t\t}\n\t}\n\treturn graphemeSegmenter\n}\n\n/**\n * Iterate over the grapheme clusters of a string \u2014 user-perceived characters such as emoji\n * sequences, flags, and accented letters \u2014 instead of UTF-16 code units. Uses `Intl.Segmenter`\n * where available and falls back to iterating by code point on browsers that lack it, where a\n * multi-code-point cluster is yielded as its component code points rather than as one segment.\n *\n * @public\n */\nexport function* iterateGraphemes(str: string): IterableIterator<string> {\n\tconst segmenter = getGraphemeSegmenter()\n\tif (segmenter) {\n\t\tfor (const { segment } of segmenter.segment(str)) yield segment\n\t} else {\n\t\tyield* str\n\t}\n}\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\tfor (const segment of iterateGraphemes(str)) {\n\t\treturn segment\n\t}\n\treturn ''\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAI;AACJ,IAAI,sBAAsB;AAQ1B,SAAS,uBAAmD;AAC3D,MAAI,CAAC,qBAAqB;AACzB,0BAAsB;AACtB,QAAI,OAAO,SAAS,eAAe,eAAe,MAAM;AACvD,0BAAoB,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAAA,IAC9E;AAAA,EACD;AACA,SAAO;AACR;AAUO,UAAU,iBAAiB,KAAuC;AACxE,QAAM,YAAY,qBAAqB;AACvC,MAAI,WAAW;AACd,eAAW,EAAE,QAAQ,KAAK,UAAU,QAAQ,GAAG,EAAG,OAAM;AAAA,EACzD,OAAO;AACN,WAAO;AAAA,EACR;AACD;AAiBO,SAAS,kBAAkB,KAAqB;AACtD,MAAI,CAAC,IAAK,QAAO;AACjB,aAAW,WAAW,iBAAiB,GAAG,GAAG;AAC5C,WAAO;AAAA,EACR;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/version.ts"],
|
|
4
|
-
"sourcesContent": ["interface TldrawLibraryVersion {\n\tname: string\n\tversion: string\n\tmodules: string\n}\n\ninterface TldrawLibraryVersionInfo {\n\tversions: TldrawLibraryVersion[]\n\tdidWarn: boolean\n\tscheduledNotice: number | NodeJS.Timeout | null\n}\n\nconst TLDRAW_LIBRARY_VERSION_KEY = '__TLDRAW_LIBRARY_VERSIONS__' as const\n\n// eslint-disable-next-line @typescript-eslint/
|
|
4
|
+
"sourcesContent": ["interface TldrawLibraryVersion {\n\tname: string\n\tversion: string\n\tmodules: string\n}\n\ninterface TldrawLibraryVersionInfo {\n\tversions: TldrawLibraryVersion[]\n\tdidWarn: boolean\n\tscheduledNotice: number | NodeJS.Timeout | null\n}\n\nconst TLDRAW_LIBRARY_VERSION_KEY = '__TLDRAW_LIBRARY_VERSIONS__' as const\n\n// eslint-disable-next-line @typescript-eslint/no-namespace, no-shadow-restricted-names\ndeclare namespace globalThis {\n\texport const __TLDRAW_LIBRARY_VERSIONS__: TldrawLibraryVersionInfo\n}\n\nfunction getLibraryVersions(): TldrawLibraryVersionInfo {\n\tif (globalThis[TLDRAW_LIBRARY_VERSION_KEY]) {\n\t\treturn globalThis[TLDRAW_LIBRARY_VERSION_KEY]\n\t}\n\n\tconst info: TldrawLibraryVersionInfo = {\n\t\tversions: [],\n\t\tdidWarn: false,\n\t\tscheduledNotice: null,\n\t}\n\n\tObject.defineProperty(globalThis, TLDRAW_LIBRARY_VERSION_KEY, {\n\t\tvalue: info,\n\t\twritable: false,\n\t\tconfigurable: false,\n\t\tenumerable: false,\n\t})\n\n\treturn info\n}\n\n/**\n * Clears all registered library versions and resets warning state.\n * This function is intended for testing purposes only to reset the global version tracking state.\n * @returns void\n * @example\n * ```ts\n * // In a test setup\n * beforeEach(() => {\n * clearRegisteredVersionsForTests()\n * })\n *\n * // Now version tracking starts fresh for each test\n * registerTldrawLibraryVersion('@tldraw/editor', '2.0.0', 'esm')\n * ```\n * @internal\n */\nexport function clearRegisteredVersionsForTests() {\n\tconst info = getLibraryVersions()\n\tinfo.versions = []\n\tinfo.didWarn = false\n\tif (info.scheduledNotice) {\n\t\tclearTimeout(info.scheduledNotice)\n\t\tinfo.scheduledNotice = null\n\t}\n}\n\n/**\n * Registers a tldraw library version for conflict detection.\n * This function tracks different tldraw library versions to warn about potential conflicts\n * when multiple versions are loaded simultaneously.\n * @param name - The name of the tldraw library package (e.g., '\\@tldraw/editor').\n * @param version - The semantic version string (e.g., '2.0.0').\n * @param modules - The module system being used ('esm' or 'cjs').\n * @returns void\n * @example\n * ```ts\n * // Register a library version during package initialization\n * registerTldrawLibraryVersion('@tldraw/editor', '2.0.0', 'esm')\n * registerTldrawLibraryVersion('@tldraw/tldraw', '2.0.0', 'esm')\n *\n * // If conflicting versions are detected, warnings will be logged:\n * registerTldrawLibraryVersion('@tldraw/editor', '1.9.0', 'cjs')\n * // Console warning about version mismatch will appear\n * ```\n * @internal\n */\nexport function registerTldrawLibraryVersion(name?: string, version?: string, modules?: string) {\n\tif (!name || !version || !modules) {\n\t\tif ((globalThis as any).TLDRAW_LIBRARY_IS_BUILD) {\n\t\t\tthrow new Error('Missing name/version/module system in built version of tldraw library')\n\t\t}\n\t\treturn\n\t}\n\n\tconst info = getLibraryVersions()\n\n\t// In Next.js dev mode, Fast Refresh re-executes module-level code which causes\n\t// the same library to register multiple times, producing a false positive warning.\n\t// We skip exact duplicates only in Next.js dev to avoid hiding genuine issues.\n\tif (isNextjsDev()) {\n\t\tconst isDuplicate = info.versions.some(\n\t\t\t(v) => v.name === name && v.version === version && v.modules === modules\n\t\t)\n\t\tif (isDuplicate) return\n\t}\n\n\tinfo.versions.push({ name, version, modules })\n\n\tif (!info.scheduledNotice) {\n\t\ttry {\n\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\tinfo.scheduledNotice = setTimeout(() => {\n\t\t\t\tinfo.scheduledNotice = null\n\t\t\t\tcheckLibraryVersions(info)\n\t\t\t}, 100)\n\t\t} catch {\n\t\t\t// some environments (e.g. cloudflare workers) don't support setTimeout immediately, only in a handler.\n\t\t\t// in this case, we'll just check immediately.\n\t\t\tcheckLibraryVersions(info)\n\t\t}\n\t}\n}\n\nfunction checkLibraryVersions(info: TldrawLibraryVersionInfo) {\n\tif (!info.versions.length) return\n\tif (info.didWarn) return\n\n\tconst sorted = info.versions.sort((a, b) => compareVersions(a.version, b.version))\n\tconst latestVersion = sorted[sorted.length - 1].version\n\n\tconst matchingVersions = new Set<string>()\n\tconst nonMatchingVersions = new Map<string, Set<string>>()\n\tfor (const lib of sorted) {\n\t\tif (nonMatchingVersions.has(lib.name)) {\n\t\t\tmatchingVersions.delete(lib.name)\n\t\t\tentry(nonMatchingVersions, lib.name, new Set()).add(lib.version)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (lib.version === latestVersion) {\n\t\t\tmatchingVersions.add(lib.name)\n\t\t} else {\n\t\t\tmatchingVersions.delete(lib.name)\n\t\t\tentry(nonMatchingVersions, lib.name, new Set()).add(lib.version)\n\t\t}\n\t}\n\n\tif (nonMatchingVersions.size > 0) {\n\t\tconst message = [\n\t\t\t`${format('[tldraw]', ['bold', 'bgRed', 'textWhite'])} ${format('You have multiple versions of tldraw libraries installed. This can lead to bugs and unexpected behavior.', ['textRed', 'bold'])}`,\n\t\t\t'',\n\t\t\t`The latest version you have installed is ${format(`v${latestVersion}`, ['bold', 'textBlue'])}. The following libraries are on the latest version:`,\n\t\t\t...Array.from(matchingVersions, (name) => ` \u2022 \u2705 ${format(name, ['bold'])}`),\n\t\t\t'',\n\t\t\t`The following libraries are not on the latest version, or have multiple versions installed:`,\n\t\t\t...Array.from(nonMatchingVersions, ([name, versions]) => {\n\t\t\t\tconst sortedVersions = Array.from(versions)\n\t\t\t\t\t.sort(compareVersions)\n\t\t\t\t\t.map((v) => format(`v${v}`, v === latestVersion ? ['textGreen'] : ['textRed']))\n\t\t\t\treturn ` \u2022 \u274C ${format(name, ['bold'])} (${sortedVersions.join(', ')})`\n\t\t\t}),\n\t\t]\n\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(message.join('\\n'))\n\t\tinfo.didWarn = true\n\t\treturn\n\t}\n\n\t// at this point, we know that everything has the same version. there may still be duplicates though!\n\tconst potentialDuplicates = new Map<string, { version: string; modules: string[] }>()\n\tfor (const lib of sorted) {\n\t\tentry(potentialDuplicates, lib.name, { version: lib.version, modules: [] }).modules.push(\n\t\t\tlib.modules\n\t\t)\n\t}\n\n\tconst duplicates = new Map<string, { version: string; modules: string[] }>()\n\tfor (const [name, lib] of potentialDuplicates) {\n\t\tif (lib.modules.length > 1) duplicates.set(name, lib)\n\t}\n\n\tif (duplicates.size > 0) {\n\t\tconst message = [\n\t\t\t`${format('[tldraw]', ['bold', 'bgRed', 'textWhite'])} ${format('You have multiple instances of some tldraw libraries active. This can lead to bugs and unexpected behavior. ', ['textRed', 'bold'])}`,\n\t\t\t'',\n\t\t\t'This usually means that your bundler is misconfigured, and is importing the same library multiple times - usually once as an ES Module, and once as a CommonJS module.',\n\t\t\t'',\n\t\t\t'The following libraries have been imported multiple times:',\n\t\t\t...Array.from(duplicates, ([name, lib]) => {\n\t\t\t\tconst modules = lib.modules\n\t\t\t\t\t.map((m, i) => (m === 'esm' ? ` ${i + 1}. ES Modules` : ` ${i + 1}. CommonJS`))\n\t\t\t\t\t.join('\\n')\n\t\t\t\treturn ` \u2022 \u274C ${format(name, ['bold'])} v${lib.version}: \\n${modules}`\n\t\t\t}),\n\t\t\t'',\n\t\t\t'You should configure your bundler to only import one version of each library.',\n\t\t]\n\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(message.join('\\n'))\n\t\tinfo.didWarn = true\n\t\treturn\n\t}\n}\n\nfunction compareVersions(a: string, b: string) {\n\tconst aMatch = a.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(\\w+))?$/)\n\tconst bMatch = b.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(\\w+))?$/)\n\n\tif (!aMatch || !bMatch) return a.localeCompare(b)\n\tif (aMatch[1] !== bMatch[1]) return Number(aMatch[1]) - Number(bMatch[1])\n\tif (aMatch[2] !== bMatch[2]) return Number(aMatch[2]) - Number(bMatch[2])\n\tif (aMatch[3] !== bMatch[3]) return Number(aMatch[3]) - Number(bMatch[3])\n\tif (aMatch[4] && bMatch[4]) return aMatch[4].localeCompare(bMatch[4])\n\tif (aMatch[4]) return 1\n\tif (bMatch[4]) return -1\n\treturn 0\n}\n\nconst formats = {\n\tbold: '1',\n\ttextBlue: '94',\n\ttextRed: '31',\n\ttextGreen: '32',\n\tbgRed: '41',\n\ttextWhite: '97',\n} as const\nfunction format(value: string, formatters: (keyof typeof formats)[] = []) {\n\treturn `\\x1B[${formatters.map((f) => formats[f]).join(';')}m${value}\\x1B[m`\n}\n\nfunction isNextjsDev(): boolean {\n\ttry {\n\t\treturn process.env.NODE_ENV === 'development' && '__NEXT_DATA__' in globalThis\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction entry<K, V>(map: Map<K, V>, key: K, defaultValue: V): V {\n\tif (map.has(key)) {\n\t\treturn map.get(key)!\n\t}\n\tmap.set(key, defaultValue)\n\treturn defaultValue\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/index.d.mts
CHANGED
|
@@ -795,6 +795,16 @@ 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
|
+
|
|
798
808
|
/**
|
|
799
809
|
* A type representing a JSON array containing any valid JSON values.
|
|
800
810
|
* Arrays can contain mixed types of JSON values including nested arrays and objects.
|
|
@@ -1921,8 +1931,8 @@ export declare class Timers {
|
|
|
1921
1931
|
forContext(contextId: string): {
|
|
1922
1932
|
dispose: () => void;
|
|
1923
1933
|
requestAnimationFrame: (callback: FrameRequestCallback) => number;
|
|
1924
|
-
setInterval: (handler: TimerHandler, timeout?: number
|
|
1925
|
-
setTimeout: (handler: TimerHandler, timeout?: number
|
|
1934
|
+
setInterval: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
|
|
1935
|
+
setTimeout: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
|
|
1926
1936
|
};
|
|
1927
1937
|
}
|
|
1928
1938
|
|
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 } from "./lib/string.mjs";
|
|
89
|
+
import { getFirstCharacter, iterateGraphemes } 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-canary.
|
|
106
|
+
"5.4.0-canary.bb69ad90a32d",
|
|
107
107
|
"esm"
|
|
108
108
|
);
|
|
109
109
|
export {
|
|
@@ -168,6 +168,7 @@ export {
|
|
|
168
168
|
isNativeStructuredClone,
|
|
169
169
|
isNonNull,
|
|
170
170
|
isNonNullish,
|
|
171
|
+
iterateGraphemes,
|
|
171
172
|
last,
|
|
172
173
|
lerp,
|
|
173
174
|
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 } 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,
|
|
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, iterateGraphemes } 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,mBAAmB,wBAAwB;AACpD,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/id.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/id.ts"],
|
|
4
|
-
"sourcesContent": ["/*!\n * MIT License: https://github.com/ai/nanoid/blob/main/LICENSE\n * Modified code originally from <https://github.com/ai/nanoid>\n * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n *\n * `nanoid` is currently only distributed as an ES module. Some tools (jest, playwright) don't\n * properly support ESM-only code yet, and tldraw itself is distributed as both an ES module and a\n * CommonJS module. By including nanoid here, we can make sure it works well in every environment\n * where tldraw is used. We can also remove some unused features like custom alphabets.\n */\n\n// all environments that tldraw runs in (browser, workers, recent node versions) have global\n// `crypto`\nconst crypto = globalThis.crypto\n\n// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compression.\n// Same as in non-secure/index.js\nconst urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n\n// It is best to make fewer, larger requests to the crypto module to\n// avoid system call overhead. So, random numbers are generated in a\n// pool. The pool is a Buffer that is larger than the initial random\n// request size by this multiplier. The pool is enlarged if subsequent\n// requests exceed the maximum buffer size.\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool: Uint8Array
|
|
5
|
-
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,MAAM,SAAS,WAAW;AAK1B,MAAM,cAAc;AAOpB,MAAM,uBAAuB;AAC7B,IAAI,
|
|
4
|
+
"sourcesContent": ["/*!\n * MIT License: https://github.com/ai/nanoid/blob/main/LICENSE\n * Modified code originally from <https://github.com/ai/nanoid>\n * Copyright 2017 Andrey Sitnik <andrey@sitnik.ru>\n *\n * `nanoid` is currently only distributed as an ES module. Some tools (jest, playwright) don't\n * properly support ESM-only code yet, and tldraw itself is distributed as both an ES module and a\n * CommonJS module. By including nanoid here, we can make sure it works well in every environment\n * where tldraw is used. We can also remove some unused features like custom alphabets.\n */\n\n// all environments that tldraw runs in (browser, workers, recent node versions) have global\n// `crypto`\nconst crypto = globalThis.crypto\n\n// This alphabet uses `A-Za-z0-9_-` symbols.\n// The order of characters is optimized for better gzip and brotli compression.\n// Same as in non-secure/index.js\nconst urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n\n// It is best to make fewer, larger requests to the crypto module to\n// avoid system call overhead. So, random numbers are generated in a\n// pool. The pool is a Buffer that is larger than the initial random\n// request size by this multiplier. The pool is enlarged if subsequent\n// requests exceed the maximum buffer size.\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool: Uint8Array<ArrayBuffer>, poolOffset: number\n\nfunction fillPool(bytes: number) {\n\tif (!pool || pool.length < bytes) {\n\t\tpool = new Uint8Array(bytes * POOL_SIZE_MULTIPLIER)\n\t\tcrypto.getRandomValues(pool)\n\t\tpoolOffset = 0\n\t} else if (poolOffset + bytes > pool.length) {\n\t\tcrypto.getRandomValues(pool)\n\t\tpoolOffset = 0\n\t}\n\tpoolOffset += bytes\n}\n\nfunction nanoid(size = 21) {\n\t// `-=` convert `size` to number to prevent `valueOf` abusing\n\tfillPool((size -= 0))\n\tlet id = ''\n\t// We are reading directly from the random pool to avoid creating new array\n\tfor (let i = poolOffset - size; i < poolOffset; i++) {\n\t\t// It is incorrect to use bytes exceeding the alphabet size.\n\t\t// The following mask reduces the random byte in the 0-255 value\n\t\t// range to the 0-63 value range. Therefore, adding hacks, such\n\t\t// as empty string fallback or magic numbers, is unnecessary because\n\t\t// the bitmask trims bytes down to the alphabet size.\n\t\tid += urlAlphabet[pool[i] & 63]\n\t}\n\treturn id\n}\n\nlet impl = nanoid\n/**\n * Mock the unique ID generator with a custom implementation for testing.\n *\n * Replaces the internal ID generation function with a custom one. This is useful\n * for testing scenarios where you need predictable or deterministic IDs.\n *\n * @param fn - The mock function that should return a string ID. Takes optional size parameter.\n * @example\n * ```ts\n * // Mock with predictable IDs for testing\n * mockUniqueId((size = 21) => 'test-id-' + size)\n * console.log(uniqueId()) // 'test-id-21'\n * console.log(uniqueId(10)) // 'test-id-10'\n *\n * // Restore original implementation when done\n * restoreUniqueId()\n * ```\n * @internal\n */\nexport function mockUniqueId(fn: (size?: number) => string) {\n\timpl = fn\n}\n\n/**\n * Restore the original unique ID generator after mocking.\n *\n * Resets the ID generation function back to the original nanoid implementation.\n * This should be called after testing to restore normal ID generation behavior.\n *\n * @example\n * ```ts\n * // After mocking for tests\n * mockUniqueId(() => 'mock-id')\n *\n * // Restore original behavior\n * restoreUniqueId()\n * console.log(uniqueId()) // Now generates real random IDs again\n * ```\n * @internal\n */\nexport function restoreUniqueId() {\n\timpl = nanoid\n}\n\n/**\n * Generate a unique ID using a modified nanoid algorithm.\n *\n * Generates a cryptographically secure random string ID using URL-safe characters.\n * The default size is 21 characters, which provides a good balance of uniqueness\n * and brevity. Uses the global crypto API for secure random number generation.\n *\n * @param size - Optional length of the generated ID (defaults to 21 characters)\n * @returns A unique string identifier\n * @example\n * ```ts\n * // Generate default 21-character ID\n * const id = uniqueId()\n * console.log(id) // 'V1StGXR8_Z5jdHi6B-myT'\n *\n * // Generate shorter ID\n * const shortId = uniqueId(10)\n * console.log(shortId) // 'V1StGXR8_Z'\n *\n * // Generate longer ID\n * const longId = uniqueId(32)\n * console.log(longId) // 'V1StGXR8_Z5jdHi6B-myTVKahvjdx...'\n * ```\n * @public\n */\nexport function uniqueId(size?: number): string {\n\treturn impl(size)\n}\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaA,MAAM,SAAS,WAAW;AAK1B,MAAM,cAAc;AAOpB,MAAM,uBAAuB;AAC7B,IAAI,MAA+B;AAEnC,SAAS,SAAS,OAAe;AAChC,MAAI,CAAC,QAAQ,KAAK,SAAS,OAAO;AACjC,WAAO,IAAI,WAAW,QAAQ,oBAAoB;AAClD,WAAO,gBAAgB,IAAI;AAC3B,iBAAa;AAAA,EACd,WAAW,aAAa,QAAQ,KAAK,QAAQ;AAC5C,WAAO,gBAAgB,IAAI;AAC3B,iBAAa;AAAA,EACd;AACA,gBAAc;AACf;AAEA,SAAS,OAAO,OAAO,IAAI;AAE1B,WAAU,QAAQ,CAAE;AACpB,MAAI,KAAK;AAET,WAAS,IAAI,aAAa,MAAM,IAAI,YAAY,KAAK;AAMpD,UAAM,YAAY,KAAK,CAAC,IAAI,EAAE;AAAA,EAC/B;AACA,SAAO;AACR;AAEA,IAAI,OAAO;AAoBJ,SAAS,aAAa,IAA+B;AAC3D,SAAO;AACR;AAmBO,SAAS,kBAAkB;AACjC,SAAO;AACR;AA2BO,SAAS,SAAS,MAAuB;AAC/C,SAAO,KAAK,IAAI;AACjB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/lib/string.mjs
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
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
|
+
}
|
|
2
20
|
function getFirstCharacter(str) {
|
|
3
21
|
if (!str) return "";
|
|
4
|
-
|
|
5
|
-
for (const { segment } of graphemeSegmenter.segment(str)) {
|
|
22
|
+
for (const segment of iterateGraphemes(str)) {
|
|
6
23
|
return segment;
|
|
7
24
|
}
|
|
8
25
|
return "";
|
|
9
26
|
}
|
|
10
27
|
export {
|
|
11
|
-
getFirstCharacter
|
|
28
|
+
getFirstCharacter,
|
|
29
|
+
iterateGraphemes
|
|
12
30
|
};
|
|
13
31
|
//# 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\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\
|
|
5
|
-
"mappings": "AAAA,IAAI;
|
|
4
|
+
"sourcesContent": ["let graphemeSegmenter: Intl.Segmenter | undefined\nlet checkedForSegmenter = false\n\n/**\n * Resolve a shared grapheme `Intl.Segmenter`, or `undefined` when the runtime has no\n * `Intl.Segmenter`. `Intl.Segmenter` is unavailable on some older browsers (notably Firefox before\n * 125), so feature-detect it once rather than constructing it eagerly, which would throw at module\n * load and take down the whole app.\n */\nfunction getGraphemeSegmenter(): Intl.Segmenter | undefined {\n\tif (!checkedForSegmenter) {\n\t\tcheckedForSegmenter = true\n\t\tif (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n\t\t\tgraphemeSegmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })\n\t\t}\n\t}\n\treturn graphemeSegmenter\n}\n\n/**\n * Iterate over the grapheme clusters of a string \u2014 user-perceived characters such as emoji\n * sequences, flags, and accented letters \u2014 instead of UTF-16 code units. Uses `Intl.Segmenter`\n * where available and falls back to iterating by code point on browsers that lack it, where a\n * multi-code-point cluster is yielded as its component code points rather than as one segment.\n *\n * @public\n */\nexport function* iterateGraphemes(str: string): IterableIterator<string> {\n\tconst segmenter = getGraphemeSegmenter()\n\tif (segmenter) {\n\t\tfor (const { segment } of segmenter.segment(str)) yield segment\n\t} else {\n\t\tyield* str\n\t}\n}\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\tfor (const segment of iterateGraphemes(str)) {\n\t\treturn segment\n\t}\n\treturn ''\n}\n"],
|
|
5
|
+
"mappings": "AAAA,IAAI;AACJ,IAAI,sBAAsB;AAQ1B,SAAS,uBAAmD;AAC3D,MAAI,CAAC,qBAAqB;AACzB,0BAAsB;AACtB,QAAI,OAAO,SAAS,eAAe,eAAe,MAAM;AACvD,0BAAoB,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,WAAW,CAAC;AAAA,IAC9E;AAAA,EACD;AACA,SAAO;AACR;AAUO,UAAU,iBAAiB,KAAuC;AACxE,QAAM,YAAY,qBAAqB;AACvC,MAAI,WAAW;AACd,eAAW,EAAE,QAAQ,KAAK,UAAU,QAAQ,GAAG,EAAG,OAAM;AAAA,EACzD,OAAO;AACN,WAAO;AAAA,EACR;AACD;AAiBO,SAAS,kBAAkB,KAAqB;AACtD,MAAI,CAAC,IAAK,QAAO;AACjB,aAAW,WAAW,iBAAiB,GAAG,GAAG;AAC5C,WAAO;AAAA,EACR;AACA,SAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/version.ts"],
|
|
4
|
-
"sourcesContent": ["interface TldrawLibraryVersion {\n\tname: string\n\tversion: string\n\tmodules: string\n}\n\ninterface TldrawLibraryVersionInfo {\n\tversions: TldrawLibraryVersion[]\n\tdidWarn: boolean\n\tscheduledNotice: number | NodeJS.Timeout | null\n}\n\nconst TLDRAW_LIBRARY_VERSION_KEY = '__TLDRAW_LIBRARY_VERSIONS__' as const\n\n// eslint-disable-next-line @typescript-eslint/
|
|
4
|
+
"sourcesContent": ["interface TldrawLibraryVersion {\n\tname: string\n\tversion: string\n\tmodules: string\n}\n\ninterface TldrawLibraryVersionInfo {\n\tversions: TldrawLibraryVersion[]\n\tdidWarn: boolean\n\tscheduledNotice: number | NodeJS.Timeout | null\n}\n\nconst TLDRAW_LIBRARY_VERSION_KEY = '__TLDRAW_LIBRARY_VERSIONS__' as const\n\n// eslint-disable-next-line @typescript-eslint/no-namespace, no-shadow-restricted-names\ndeclare namespace globalThis {\n\texport const __TLDRAW_LIBRARY_VERSIONS__: TldrawLibraryVersionInfo\n}\n\nfunction getLibraryVersions(): TldrawLibraryVersionInfo {\n\tif (globalThis[TLDRAW_LIBRARY_VERSION_KEY]) {\n\t\treturn globalThis[TLDRAW_LIBRARY_VERSION_KEY]\n\t}\n\n\tconst info: TldrawLibraryVersionInfo = {\n\t\tversions: [],\n\t\tdidWarn: false,\n\t\tscheduledNotice: null,\n\t}\n\n\tObject.defineProperty(globalThis, TLDRAW_LIBRARY_VERSION_KEY, {\n\t\tvalue: info,\n\t\twritable: false,\n\t\tconfigurable: false,\n\t\tenumerable: false,\n\t})\n\n\treturn info\n}\n\n/**\n * Clears all registered library versions and resets warning state.\n * This function is intended for testing purposes only to reset the global version tracking state.\n * @returns void\n * @example\n * ```ts\n * // In a test setup\n * beforeEach(() => {\n * clearRegisteredVersionsForTests()\n * })\n *\n * // Now version tracking starts fresh for each test\n * registerTldrawLibraryVersion('@tldraw/editor', '2.0.0', 'esm')\n * ```\n * @internal\n */\nexport function clearRegisteredVersionsForTests() {\n\tconst info = getLibraryVersions()\n\tinfo.versions = []\n\tinfo.didWarn = false\n\tif (info.scheduledNotice) {\n\t\tclearTimeout(info.scheduledNotice)\n\t\tinfo.scheduledNotice = null\n\t}\n}\n\n/**\n * Registers a tldraw library version for conflict detection.\n * This function tracks different tldraw library versions to warn about potential conflicts\n * when multiple versions are loaded simultaneously.\n * @param name - The name of the tldraw library package (e.g., '\\@tldraw/editor').\n * @param version - The semantic version string (e.g., '2.0.0').\n * @param modules - The module system being used ('esm' or 'cjs').\n * @returns void\n * @example\n * ```ts\n * // Register a library version during package initialization\n * registerTldrawLibraryVersion('@tldraw/editor', '2.0.0', 'esm')\n * registerTldrawLibraryVersion('@tldraw/tldraw', '2.0.0', 'esm')\n *\n * // If conflicting versions are detected, warnings will be logged:\n * registerTldrawLibraryVersion('@tldraw/editor', '1.9.0', 'cjs')\n * // Console warning about version mismatch will appear\n * ```\n * @internal\n */\nexport function registerTldrawLibraryVersion(name?: string, version?: string, modules?: string) {\n\tif (!name || !version || !modules) {\n\t\tif ((globalThis as any).TLDRAW_LIBRARY_IS_BUILD) {\n\t\t\tthrow new Error('Missing name/version/module system in built version of tldraw library')\n\t\t}\n\t\treturn\n\t}\n\n\tconst info = getLibraryVersions()\n\n\t// In Next.js dev mode, Fast Refresh re-executes module-level code which causes\n\t// the same library to register multiple times, producing a false positive warning.\n\t// We skip exact duplicates only in Next.js dev to avoid hiding genuine issues.\n\tif (isNextjsDev()) {\n\t\tconst isDuplicate = info.versions.some(\n\t\t\t(v) => v.name === name && v.version === version && v.modules === modules\n\t\t)\n\t\tif (isDuplicate) return\n\t}\n\n\tinfo.versions.push({ name, version, modules })\n\n\tif (!info.scheduledNotice) {\n\t\ttry {\n\t\t\t// eslint-disable-next-line no-restricted-globals\n\t\t\tinfo.scheduledNotice = setTimeout(() => {\n\t\t\t\tinfo.scheduledNotice = null\n\t\t\t\tcheckLibraryVersions(info)\n\t\t\t}, 100)\n\t\t} catch {\n\t\t\t// some environments (e.g. cloudflare workers) don't support setTimeout immediately, only in a handler.\n\t\t\t// in this case, we'll just check immediately.\n\t\t\tcheckLibraryVersions(info)\n\t\t}\n\t}\n}\n\nfunction checkLibraryVersions(info: TldrawLibraryVersionInfo) {\n\tif (!info.versions.length) return\n\tif (info.didWarn) return\n\n\tconst sorted = info.versions.sort((a, b) => compareVersions(a.version, b.version))\n\tconst latestVersion = sorted[sorted.length - 1].version\n\n\tconst matchingVersions = new Set<string>()\n\tconst nonMatchingVersions = new Map<string, Set<string>>()\n\tfor (const lib of sorted) {\n\t\tif (nonMatchingVersions.has(lib.name)) {\n\t\t\tmatchingVersions.delete(lib.name)\n\t\t\tentry(nonMatchingVersions, lib.name, new Set()).add(lib.version)\n\t\t\tcontinue\n\t\t}\n\n\t\tif (lib.version === latestVersion) {\n\t\t\tmatchingVersions.add(lib.name)\n\t\t} else {\n\t\t\tmatchingVersions.delete(lib.name)\n\t\t\tentry(nonMatchingVersions, lib.name, new Set()).add(lib.version)\n\t\t}\n\t}\n\n\tif (nonMatchingVersions.size > 0) {\n\t\tconst message = [\n\t\t\t`${format('[tldraw]', ['bold', 'bgRed', 'textWhite'])} ${format('You have multiple versions of tldraw libraries installed. This can lead to bugs and unexpected behavior.', ['textRed', 'bold'])}`,\n\t\t\t'',\n\t\t\t`The latest version you have installed is ${format(`v${latestVersion}`, ['bold', 'textBlue'])}. The following libraries are on the latest version:`,\n\t\t\t...Array.from(matchingVersions, (name) => ` \u2022 \u2705 ${format(name, ['bold'])}`),\n\t\t\t'',\n\t\t\t`The following libraries are not on the latest version, or have multiple versions installed:`,\n\t\t\t...Array.from(nonMatchingVersions, ([name, versions]) => {\n\t\t\t\tconst sortedVersions = Array.from(versions)\n\t\t\t\t\t.sort(compareVersions)\n\t\t\t\t\t.map((v) => format(`v${v}`, v === latestVersion ? ['textGreen'] : ['textRed']))\n\t\t\t\treturn ` \u2022 \u274C ${format(name, ['bold'])} (${sortedVersions.join(', ')})`\n\t\t\t}),\n\t\t]\n\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(message.join('\\n'))\n\t\tinfo.didWarn = true\n\t\treturn\n\t}\n\n\t// at this point, we know that everything has the same version. there may still be duplicates though!\n\tconst potentialDuplicates = new Map<string, { version: string; modules: string[] }>()\n\tfor (const lib of sorted) {\n\t\tentry(potentialDuplicates, lib.name, { version: lib.version, modules: [] }).modules.push(\n\t\t\tlib.modules\n\t\t)\n\t}\n\n\tconst duplicates = new Map<string, { version: string; modules: string[] }>()\n\tfor (const [name, lib] of potentialDuplicates) {\n\t\tif (lib.modules.length > 1) duplicates.set(name, lib)\n\t}\n\n\tif (duplicates.size > 0) {\n\t\tconst message = [\n\t\t\t`${format('[tldraw]', ['bold', 'bgRed', 'textWhite'])} ${format('You have multiple instances of some tldraw libraries active. This can lead to bugs and unexpected behavior. ', ['textRed', 'bold'])}`,\n\t\t\t'',\n\t\t\t'This usually means that your bundler is misconfigured, and is importing the same library multiple times - usually once as an ES Module, and once as a CommonJS module.',\n\t\t\t'',\n\t\t\t'The following libraries have been imported multiple times:',\n\t\t\t...Array.from(duplicates, ([name, lib]) => {\n\t\t\t\tconst modules = lib.modules\n\t\t\t\t\t.map((m, i) => (m === 'esm' ? ` ${i + 1}. ES Modules` : ` ${i + 1}. CommonJS`))\n\t\t\t\t\t.join('\\n')\n\t\t\t\treturn ` \u2022 \u274C ${format(name, ['bold'])} v${lib.version}: \\n${modules}`\n\t\t\t}),\n\t\t\t'',\n\t\t\t'You should configure your bundler to only import one version of each library.',\n\t\t]\n\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.log(message.join('\\n'))\n\t\tinfo.didWarn = true\n\t\treturn\n\t}\n}\n\nfunction compareVersions(a: string, b: string) {\n\tconst aMatch = a.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(\\w+))?$/)\n\tconst bMatch = b.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(\\w+))?$/)\n\n\tif (!aMatch || !bMatch) return a.localeCompare(b)\n\tif (aMatch[1] !== bMatch[1]) return Number(aMatch[1]) - Number(bMatch[1])\n\tif (aMatch[2] !== bMatch[2]) return Number(aMatch[2]) - Number(bMatch[2])\n\tif (aMatch[3] !== bMatch[3]) return Number(aMatch[3]) - Number(bMatch[3])\n\tif (aMatch[4] && bMatch[4]) return aMatch[4].localeCompare(bMatch[4])\n\tif (aMatch[4]) return 1\n\tif (bMatch[4]) return -1\n\treturn 0\n}\n\nconst formats = {\n\tbold: '1',\n\ttextBlue: '94',\n\ttextRed: '31',\n\ttextGreen: '32',\n\tbgRed: '41',\n\ttextWhite: '97',\n} as const\nfunction format(value: string, formatters: (keyof typeof formats)[] = []) {\n\treturn `\\x1B[${formatters.map((f) => formats[f]).join(';')}m${value}\\x1B[m`\n}\n\nfunction isNextjsDev(): boolean {\n\ttry {\n\t\treturn process.env.NODE_ENV === 'development' && '__NEXT_DATA__' in globalThis\n\t} catch {\n\t\treturn false\n\t}\n}\n\nfunction entry<K, V>(map: Map<K, V>, key: K, defaultValue: V): V {\n\tif (map.has(key)) {\n\t\treturn map.get(key)!\n\t}\n\tmap.set(key, defaultValue)\n\treturn defaultValue\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
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 } from './lib/string'
|
|
94
|
+
export { getFirstCharacter, iterateGraphemes } 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/id.ts
CHANGED
|
@@ -24,7 +24,7 @@ const urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwy
|
|
|
24
24
|
// request size by this multiplier. The pool is enlarged if subsequent
|
|
25
25
|
// requests exceed the maximum buffer size.
|
|
26
26
|
const POOL_SIZE_MULTIPLIER = 128
|
|
27
|
-
let pool: Uint8Array
|
|
27
|
+
let pool: Uint8Array<ArrayBuffer>, poolOffset: number
|
|
28
28
|
|
|
29
29
|
function fillPool(bytes: number) {
|
|
30
30
|
if (!pool || pool.length < bytes) {
|
package/src/lib/string.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
import { getFirstCharacter, iterateGraphemes } from './string'
|
|
2
3
|
|
|
3
4
|
describe('getFirstCharacter', () => {
|
|
4
5
|
it('returns the first character of a plain string', () => {
|
|
@@ -21,3 +22,59 @@ describe('getFirstCharacter', () => {
|
|
|
21
22
|
expect(getFirstCharacter(' hi')).toBe(' ')
|
|
22
23
|
})
|
|
23
24
|
})
|
|
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,4 +1,38 @@
|
|
|
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
|
+
}
|
|
2
36
|
|
|
3
37
|
/**
|
|
4
38
|
* Get the first character of a string, treating a multi-code-unit character such as an emoji as a
|
|
@@ -17,8 +51,7 @@ let graphemeSegmenter: Intl.Segmenter | undefined
|
|
|
17
51
|
*/
|
|
18
52
|
export function getFirstCharacter(str: string): string {
|
|
19
53
|
if (!str) return ''
|
|
20
|
-
|
|
21
|
-
for (const { segment } of graphemeSegmenter.segment(str)) {
|
|
54
|
+
for (const segment of iterateGraphemes(str)) {
|
|
22
55
|
return segment
|
|
23
56
|
}
|
|
24
57
|
return ''
|
package/src/lib/version.ts
CHANGED
|
@@ -12,8 +12,8 @@ interface TldrawLibraryVersionInfo {
|
|
|
12
12
|
|
|
13
13
|
const TLDRAW_LIBRARY_VERSION_KEY = '__TLDRAW_LIBRARY_VERSIONS__' as const
|
|
14
14
|
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/
|
|
16
|
-
declare
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace, no-shadow-restricted-names
|
|
16
|
+
declare namespace globalThis {
|
|
17
17
|
export const __TLDRAW_LIBRARY_VERSIONS__: TldrawLibraryVersionInfo
|
|
18
18
|
}
|
|
19
19
|
|