snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-23 16:12:52 +05:00
commit a774ac673a
4541 changed files with 770499 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
let graphemeSegmenter: Intl.Segmenter | undefined
let checkedForSegmenter = false
/**
* Resolve a shared grapheme `Intl.Segmenter`, or `undefined` when the runtime has no
* `Intl.Segmenter`. `Intl.Segmenter` is unavailable on some older browsers (notably Firefox before
* 125), so feature-detect it once rather than constructing it eagerly, which would throw at module
* load and take down the whole app.
*/
function getGraphemeSegmenter(): Intl.Segmenter | undefined {
if (!checkedForSegmenter) {
checkedForSegmenter = true
if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {
graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' })
}
}
return graphemeSegmenter
}
/**
* Iterate over the grapheme clusters of a string — user-perceived characters such as emoji
* sequences, flags, and accented letters — instead of UTF-16 code units. Uses `Intl.Segmenter`
* where available and falls back to iterating by code point on browsers that lack it, where a
* multi-code-point cluster is yielded as its component code points rather than as one segment.
*
* @public
*/
export function* iterateGraphemes(str: string): IterableIterator<string> {
const segmenter = getGraphemeSegmenter()
if (segmenter) {
for (const { segment } of segmenter.segment(str)) yield segment
} else {
yield* str
}
}
/**
* Get the first character of a string, treating a multi-code-unit character such as an emoji as a
* single character. Unlike `str[0]` or `str.charAt(0)`, which return one UTF-16 code unit and so
* split an emoji into a broken half, this returns the first whole grapheme cluster. Returns an
* empty string when the input is empty.
*
* @example
* ```ts
* getFirstCharacter('hello') // 'h'
* getFirstCharacter('😀 hello') // '😀'
* getFirstCharacter('') // ''
* ```
*
* @public
*/
export function getFirstCharacter(str: string): string {
if (!str) return ''
for (const segment of iterateGraphemes(str)) {
return segment
}
return ''
}