Browser Typing Tool
For Browser environment Lipi Lekhika includes a premade plugin for low-latency realtime typing.
Only supported for textarea and input elements.
-
Import the relevant functions from the package
import {createTypingContext,clearTypingContextOnKeyDown,handleTypingBeforeInputEvent} from 'lipilekhika/typing'; -
Create a typing context with the desired typing script and custom options. Create a new context for each typing script and element combination.
const ctx = createTypingContext('Telugu'); -
Call
handleTypingBeforeInputEventand pass theonbeforeinputevent and the typing_context. The callback is optional and will be called with the updated value of the input element.handleTypingBeforeInputEvent(ctx, event, callback, options?); -
Add UI and I/O-Related Context Cleanup events.
onblurhandles focus of the input element andonkeydownhandles keydown events (e.g. Arrow Keys, Esc, Etc).ctx.clearContext(); // onblur// onkeydownclearTypingContextOnKeyDown(event, ctx);
Runtime Configuration
Section titled “Runtime Configuration”After creating a typing context, you can dynamically update typing options:
ctx.updateUseNativeNumerals(boolean)- Enable/disable native numerals (e.g., १० instead of 10)ctx.updateIncludeInherentVowel(boolean)- Enable/disable inherent vowel inclusion (schwa deletion)ctx.getUseNativeNumerals()- Get current native numerals settingctx.getIncludeInherentVowel()- Get current inherent vowel settingctx.getNormalizedScript()- Get current normalized script name
Implementation Example
Section titled “Implementation Example”You can view all examples in live environment here
const ctx = useMemo(() => createTypingContext(script), [script]); <textarea value={text} onChange={(e) => setText(e.target.value)} onBeforeInput={(e) => handleTypingBeforeInputEvent(ctx, e, (newValue) => setText(newValue))} onBlur={() => ctx.clearContext()} onKeyDown={(e) => clearTypingContextOnKeyDown(e, ctx)} />const ctx = computed(() => createTypingContext(script.value));<input v-model="text" @beforeinput="(e) => handleTypingBeforeInputEvent(ctx, e, (newValue) => (text = newValue))" @blur="() => ctx.clearContext()" @keydown="(e) => clearTypingContextOnKeyDown(e, ctx)"></input>In Vue you can eagerly await using
watchEffect(() => { ctx.value.ready;});Svelte
Section titled “Svelte”const ctx = $derived(createTypingContext(script));<textarea bind:value={text} onbeforeinput={(e) => handleTypingBeforeInputEvent(ctx, e, (newValue) => (text = newValue))} onblur={() => ctx.clearContext()} onkeydown={(e) => clearTypingContextOnKeyDown(e, ctx)}></textarea>In Svelte you can eagerly await using
$effect(() => { ctx.ready;});const ctx = createMemo(() => createTypingContext(script()));<textarea value={text()} onInput={(e) => setText(e.currentTarget.value)} onBeforeInput={(e) => handleTypingBeforeInputEvent(ctx(), e, (newValue) => setText(newValue))} onBlur={() => ctx().clearContext()} onKeyDown={(e) => clearTypingContextOnKeyDown(e, ctx())}></textarea>In Solid you can eagerly await using
createEffect(() => { ctx().ready;});Browser UMD and ESM Usage
Section titled “Browser UMD and ESM Usage”In Vanilla JS approach you will have to bind the events manually yourself.
- UMD - Code Example, Demo Page
- ESM - Code Example, Demo Page
Rich Text Typing
Section titled “Rich Text Typing”Transliteration and even Rich text typing is usually built around real <textarea> and <input> elements. Wiring it directly to contenteditable is usually impractical: the DOM is not one simple string, and selection, IME, and paste are harder to keep consistent.
Rich editors typically use a mirror (or underlay) instead: a read-only layer shows colors, styling and other rich elements. All typing—including handleTypingBeforeInputEvent—targets that textarea.
So if the Rich Text editing library you are using provides a interface to underlyiing textarea element then you should be able to integrate Lipi Lekhika typing. For example in crata-md svelte library a textarea element is exposed for use.
<MarkdownEditor {carta} bind:value={content} mode="tabs" scroll="async" placeholder="Write markdown…" selectedTab="write" textarea={{ onbeforeinput: (e: Event) => handleTypingBeforeInputEvent(ctx, e, (v) => (content = v), typing_enabled), onblur: () => ctx.clearContext(), onkeydown: (e: KeyboardEvent) => clearTypingContextOnKeyDown(e, ctx) }}/>Minimal Example
Section titled “Minimal Example”- It demonstartes a mininal example of a shadow textarea element to enable rich text typing
- Demo Link
- Source Code