@siyabasa/singlish 1.0.0
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/LICENSE +111 -0
- package/README.md +117 -0
- package/dist/index.cjs +95 -0
- package/dist/index.d.cts +247 -0
- package/dist/index.d.ts +247 -0
- package/dist/index.js +95 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Remeinium Open Source License (ROSL)
|
|
2
|
+
|
|
3
|
+
**Version 1.0 — February 2026**
|
|
4
|
+
|
|
5
|
+
## 1. Background
|
|
6
|
+
|
|
7
|
+
This Remeinium Open Source License (“License”) governs the use of software source code, documentation, and related build artifacts released by **Remeinium Corp** (“Remeinium”) through **Remeinium Siyabasa Labs**, including but not limited to the **@siyabasa/singlish** library.
|
|
8
|
+
|
|
9
|
+
By downloading, accessing, using, modifying, or distributing the Software, you agree to the terms of this License.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 2. License Grant
|
|
14
|
+
|
|
15
|
+
Remeinium grants you a **worldwide, royalty-free, non-exclusive, perpetual license** to:
|
|
16
|
+
|
|
17
|
+
* Use the Software for **research, educational, and commercial purposes**
|
|
18
|
+
* Reproduce and distribute the Software, in original or modified form
|
|
19
|
+
* Fine-tune, adapt, or integrate the Software into applications, systems, or services
|
|
20
|
+
* Distribute binaries or compiled versions of the Software without restriction
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 3. Attribution Requirements
|
|
25
|
+
|
|
26
|
+
If you distribute the Software or use it in a public or commercial product, you must provide reasonable attribution:
|
|
27
|
+
|
|
28
|
+
> “This product uses software developed by Remeinium Siyabasa Labs / Remeinium Corp.”
|
|
29
|
+
|
|
30
|
+
Attribution may be provided in documentation, an “About” page, or similar materials.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 4. Restrictions
|
|
35
|
+
|
|
36
|
+
You may **not**:
|
|
37
|
+
|
|
38
|
+
* Misrepresent the Software or derivatives as being authored by anyone other than Remeinium
|
|
39
|
+
* Use Remeinium trademarks, logos, or branding without explicit permission
|
|
40
|
+
* Falsely imply endorsement by Remeinium
|
|
41
|
+
|
|
42
|
+
This License **does not** restrict commercial use, resale, or deployment of applications built using the Software.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 5. Ownership
|
|
47
|
+
|
|
48
|
+
Remeinium retains ownership of the original Software and source code.
|
|
49
|
+
You retain ownership of:
|
|
50
|
+
|
|
51
|
+
* Your applications, services, or research
|
|
52
|
+
* Your modified versions of the Software
|
|
53
|
+
* The output generated by the Software
|
|
54
|
+
|
|
55
|
+
No rights are granted to Remeinium over your downstream work.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## 6. Responsible Use
|
|
60
|
+
|
|
61
|
+
The Software is provided as a general-purpose language technology tool.
|
|
62
|
+
You are solely responsible for ensuring compliance with applicable laws, regulations, and ethical norms in your use of the Software.
|
|
63
|
+
|
|
64
|
+
Remeinium Siyabasa Labs encourages responsible, non-harmful use aligned with human well-being and the advancement of language technology.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 7. Disclaimer of Warranty
|
|
69
|
+
|
|
70
|
+
THE SOFTWARE IS PROVIDED **“AS IS”**, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 8. Limitation of Liability
|
|
75
|
+
|
|
76
|
+
TO THE MAXIMUM EXTENT PERMITTED BY LAW, REMEINIUM SHALL NOT BE LIABLE FOR ANY DAMAGES ARISING FROM THE USE, MISUSE, OR INABILITY TO USE THE SOFTWARE, INCLUDING INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 9. Termination
|
|
81
|
+
|
|
82
|
+
This License terminates automatically if you violate its terms.
|
|
83
|
+
Upon termination, you must cease use and distribution of the Software.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 10. Governing Law
|
|
88
|
+
|
|
89
|
+
This License shall be governed by the laws of **Sri Lanka**, without regard to conflict-of-law principles.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 11. Entire Agreement
|
|
94
|
+
|
|
95
|
+
This License constitutes the entire agreement concerning the Software and supersedes any prior statements or understandings.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 12. Attribution of Origin
|
|
100
|
+
|
|
101
|
+
**@siyabasa/singlish** is released by **Remeinium Siyabasa Labs** in service of advancing Sinhala language technology and open human knowledge.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 13. Contact Us
|
|
106
|
+
|
|
107
|
+
If you have questions, concerns, or requests regarding this License, you may contact us at:
|
|
108
|
+
|
|
109
|
+
Email: support@remeinium.com
|
|
110
|
+
Organization: Remeinium Corp.
|
|
111
|
+
Web: https://labs.remeinium.com/siyabasa
|
package/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# @siyabasa/singlish
|
|
2
|
+
|
|
3
|
+
A deterministic, high-performance transliteration engine for Singlish (Romanized Sinhala) with phonetic precision and zero-latency IME support. Built for the modern web by **Remeinium Siyabasa Labs**.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@siyabasa/singlish)
|
|
6
|
+
[](https://bundlephobia.com/package/@siyabasa/singlish)
|
|
7
|
+
[](https://github.com/remeinium/singlish/blob/main/LICENSE)
|
|
8
|
+
|
|
9
|
+
## Design Philosophy
|
|
10
|
+
|
|
11
|
+
The Singlish Input Method Editor (IME) landscape has long been fragmented by ad-hoc regex replacements and non-standard transliteration schemes. **@siyabasa/singlish** introduces a rigourous, computer-science first approach to Sinhala transliteration:
|
|
12
|
+
|
|
13
|
+
- **Deterministic Phoneme Tokenization**: Unlike simple string replacement, our engine tokenizes Roman input into phonetic units before rendering, ensuring 100% accuracy for complex conjuncts (*yansaya*, *rakaransaya*) and vowel modifiers.
|
|
14
|
+
- **Zero-Latency Architecture**: Optimized for the critical rendering path. The core conversion engine operates in O(n) time complexity using a prefix-trie based lookahead parser.
|
|
15
|
+
- **Universal Runtime**: Isomorphic design that runs seamlessly on the Edge, Node.js, and in the Browser.
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
The engine uses a two-stage compilation process:
|
|
20
|
+
1. **Lexical Analysis**: Input text is scanned and tokenized into phonemes using a greedy matching algorithm against a compiled trie of 400+ phoneme patterns.
|
|
21
|
+
2. **Contextual Rendering**: A state-machine renderer processes the token stream to handle inherent vowels, *hal-kirima*, and context-dependent glyph shaping (e.g., standard *ra* vs *rakaransaya* forms).
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install @siyabasa/singlish
|
|
27
|
+
# or
|
|
28
|
+
yarn add @siyabasa/singlish
|
|
29
|
+
# or
|
|
30
|
+
pnpm add @siyabasa/singlish
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Core Transliteration
|
|
36
|
+
|
|
37
|
+
The core API is stateless and synchronous, designed for high-throughput server-side rendering or bulk text processing.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { convertSinglishToSinhala } from '@siyabasa/singlish';
|
|
41
|
+
|
|
42
|
+
const output = convertSinglishToSinhala('aayuboowan');
|
|
43
|
+
// Output: "ආයුබෝවන්"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### React IME Hook
|
|
47
|
+
|
|
48
|
+
For building rich text editors or chat interfaces, use the `useSinglishConverter` hook. It manages cursor position, input history, and IME state automatically.
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { useSinglishConverter } from '@siyabasa/singlish';
|
|
52
|
+
|
|
53
|
+
export function Editor() {
|
|
54
|
+
const { inputProps, enabled, toggle } = useSinglishConverter({ enabled: true });
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div className="flex flex-col gap-2">
|
|
58
|
+
<div className="flex justify-between items-center">
|
|
59
|
+
<span className="text-sm font-medium">Input Method</span>
|
|
60
|
+
<button
|
|
61
|
+
onClick={toggle}
|
|
62
|
+
className="px-3 py-1 text-xs rounded-full bg-gray-100 hover:bg-gray-200 transition-colors"
|
|
63
|
+
>
|
|
64
|
+
{enabled ? '🇱🇰 Siyabasa IME' : '🇺🇸 English'}
|
|
65
|
+
</button>
|
|
66
|
+
</div>
|
|
67
|
+
<textarea
|
|
68
|
+
{...inputProps}
|
|
69
|
+
className="w-full h-32 p-3 border rounded-lg focus:ring-2 focus:ring-blue-500 outline-none"
|
|
70
|
+
placeholder="Type in Singlish (e.g., 'kohomada')..."
|
|
71
|
+
/>
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Auto-Attach (Zero Config)
|
|
78
|
+
|
|
79
|
+
For legacy applications or rapid prototyping, the Auto-Attach module uses a `MutationObserver` to automatically hydrate all input fields in the DOM with Singlish capabilities.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { createAutoAttach, createUIToggle } from '@siyabasa/singlish';
|
|
83
|
+
|
|
84
|
+
// Automatically attaches to all input[type="text"] and textarea elements
|
|
85
|
+
const autoAttach = createAutoAttach({
|
|
86
|
+
exclude: '[data-no-ime]' // Optional exclusion selector
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Mounts a floating toggle widget
|
|
90
|
+
const toggle = createUIToggle({
|
|
91
|
+
position: 'bottom-right',
|
|
92
|
+
theme: 'auto'
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
toggle.mount();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API Reference
|
|
99
|
+
|
|
100
|
+
### `convertSinglishToSinhala(text: string, options?: ConversionOptions): string`
|
|
101
|
+
Pure function to transpile Singlish text to Sinhala Unicode.
|
|
102
|
+
|
|
103
|
+
### `convertWithMetadata(text: string): ConversionResult`
|
|
104
|
+
Extended version of the core converter that provides tokenization details and conversion metrics.
|
|
105
|
+
|
|
106
|
+
### `useSinglishConverter(options?: HookOptions)`
|
|
107
|
+
React hook that returns spreadable input props (`value`, `onChange`, `onKeyDown`, etc.) for seamless IME integration.
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
ROSL 1.0 © [Remeinium Siyabasa Labs](https://labs.remeinium.com)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
<div align="center">
|
|
116
|
+
<p>Built with ❤️ for the Sri Lankan Developer Community</p>
|
|
117
|
+
</div>
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";var J=Object.defineProperty;var we=Object.getOwnPropertyDescriptor;var De=Object.getOwnPropertyNames;var Pe=Object.prototype.hasOwnProperty;var Ke=(t,e,n)=>e in t?J(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var Ue=(t,e)=>{for(var n in e)J(t,n,{get:e[n],enumerable:!0})},Be=(t,e,n,u)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of De(e))!Pe.call(t,o)&&o!==n&&J(t,o,{get:()=>e[o],enumerable:!(u=we(e,o))||u.enumerable});return t};var Fe=t=>Be(J({},"__esModule",{value:!0}),t);var de=(t,e,n)=>Ke(t,typeof e!="symbol"?e+"":e,n);var st={};Ue(st,{CONSONANTS:()=>ye,HAL_CHAR:()=>ve,SPECIAL:()=>Re,SinglishIME:()=>D,VOWELS:()=>be,VOWEL_MODIFIERS_MAP:()=>Le,ZWJ_CHAR:()=>Oe,containsSinhala:()=>_e,convertLastWord:()=>Se,convertSinglishToSinhala:()=>H,convertWithMetadata:()=>me,createAutoAttach:()=>Ve,createUIToggle:()=>ke,isSinhalaChar:()=>Q,resolveBuffer:()=>oe,segmentText:()=>Te,useSinglishConverter:()=>xe});module.exports=Fe(st);var ze=[["zdha","SANYAKA_DHA"],["chh","ASPIRATED_CH"],["thh","ASPIRATED_TH"],["dhh","ASPIRATED_DH"],["zga","SANYAKA_GA"],["zja","SANYAKA_JA"],["zda","SANYAKA_DA"],["zqa","SANYAKA_DHA"],["zka","SANYAKA_KA"],["zha","SANYAKA_HA"],["aa","V_AA"],["Aa","V_AE_LONG"],["AA","V_AE_LONG"],["ai","V_AI"],["au","V_AU"],["ou","V_AU"],["ii","V_II"],["uu","V_UU"],["ee","V_EE"],["oo","V_OO"],["Ru","V_RU_LONG"],["Lu","SPECIAL_LU"],["kh","KH"],["gh","GH"],["ch","CH"],["ph","PH"],["bh","BH"],["th","TH"],["dh","DH"],["Sh","RETROFLEX_S"],["sh","SH"],["ng","N_G"],["Th","RETROFLEX_TH"],["Dh","RETROFLEX_DH"],["Ba","SANYAKA_BA"],["a","V_A"],["A","V_AE"],["i","V_I"],["u","V_U"],["U","V_UU"],["e","V_E"],["E","V_EE"],["o","V_O"],["O","V_OO"],["R","V_RU"],["k","K"],["g","G"],["j","J"],["t","RETROFLEX_T"],["d","RETROFLEX_D"],["T","RETROFLEX_TH_SINGLE"],["D","RETROFLEX_DH_SINGLE"],["n","N"],["N","RETROFLEX_N"],["p","P"],["b","B_LOWER"],["B","SANYAKA_B"],["m","M"],["y","Y"],["r","R_CONS"],["l","L_CONS"],["L","RETROFLEX_L"],["v","V_CONS"],["w","V_CONS"],["s","S_CONS"],["S","RETROFLEX_S"],["h","H_CONS"],["f","F"],["q","DH"],["x","ANUSVARA"],["X","MAHAPRANAANUSVARA"],["H","VISARGA"],[" "," "],[`
|
|
2
|
+
`,`
|
|
3
|
+
`],[" "," "],[":",":"],[";",";"],[".","."],["-","-"],[",",","],["/","/"],["?","?"],["!","!"],["(","("],[")",")"],["[","["],["]","]"],['"','"'],["'","'"],["0","0"],["1","1"],["2","2"],["3","3"],["4","4"],["5","5"],["6","6"],["7","7"],["8","8"],["9","9"]],W={K:"\u0D9A",KH:"\u0D9B",G:"\u0D9C",GH:"\u0D9D",CH:"\u0DA0",ASPIRATED_CH:"\u0DA1",J:"\u0DA2",RETROFLEX_T:"\u0DA7",RETROFLEX_TH:"\u0DA8",RETROFLEX_TH_SINGLE:"\u0DA8",RETROFLEX_D:"\u0DA9",RETROFLEX_DH:"\u0DAA",RETROFLEX_DH_SINGLE:"\u0DAA",RETROFLEX_N:"\u0DAB",TH:"\u0DAD",ASPIRATED_TH:"\u0DAE",DH:"\u0DAF",ASPIRATED_DH:"\u0DB0",N:"\u0DB1",P:"\u0DB4",PH:"\u0DB5",B_LOWER:"\u0DB6",BH:"\u0DB7",M:"\u0DB8",Y:"\u0DBA",R_CONS:"\u0DBB",L_CONS:"\u0DBD",RETROFLEX_L:"\u0DC5",V_CONS:"\u0DC0",SH:"\u0DC1",RETROFLEX_S:"\u0DC2",S_CONS:"\u0DC3",H_CONS:"\u0DC4",F:"\u0DC6"},pe=new Set(Object.keys(W)),Ae={SANYAKA_GA:"\u0D9F",SANYAKA_JA:"\u0DA6",SANYAKA_DA:"\u0DAC",SANYAKA_DHA:"\u0DB3",SANYAKA_KA:"\u0DA4",SANYAKA_HA:"\u0DA5",SANYAKA_B:"\u0DB9",SANYAKA_BA:"\u0DB9"},We=new Set(Object.keys(Ae)),re={V_A:"\u0D85",V_AA:"\u0D86",V_AE:"\u0D87",V_AE_LONG:"\u0D88",V_I:"\u0D89",V_II:"\u0D8A",V_U:"\u0D8B",V_UU:"\u0D8C",V_RU:"\u0D8D",V_RU_LONG:"\u0D8E",V_E:"\u0D91",V_EE:"\u0D92",V_AI:"\u0D93",V_O:"\u0D94",V_OO:"\u0D95",V_AU:"\u0D96"},Y={V_AA:"\u0DCF",V_AE:"\u0DD0",V_AE_LONG:"\u0DD1",V_I:"\u0DD2",V_II:"\u0DD3",V_U:"\u0DD4",V_UU:"\u0DD6",V_E:"\u0DD9",V_EE:"\u0DDA",V_AI:"\u0DDB",V_O:"\u0DDC",V_OO:"\u0DDD",V_AU:"\u0DDE"},Ye=new Set(Object.keys(re)),Ee=new Set(Object.keys(Y)),te={ANUSVARA:"\u0D82",MAHAPRANAANUSVARA:"\u0D9E",VISARGA:"\u0D83",SPECIAL_LU:"\u0DC5\u0DD4"},ne="N_G";function B(t){return pe.has(t)}function Z(t){return We.has(t)}function Ge(t){return Ye.has(t)}function q(t){return t==="V_A"}function $(t){return Ee.has(t)}function Xe(t){return t===void 0?!0:[" ",".",",","!","?",";",":",`
|
|
4
|
+
`," ","-","/","(",")","[","]",'"',"'"].includes(t)}function je(t){return t==="Y"||t==="R_CONS"}function Je(t){let e=[],n=0;for(;n<t.length;){let u=!1;for(let[o,s]of ze)if(t.substring(n,n+o.length)===o){e.push(s),n+=o.length,u=!0;break}u||(e.push(t[n]),n++)}return e}function Ze(t){let e=[],n=0;for(;n<t.length;){let u=t[n],o=t[n+1];if(te[u]!==void 0){e.push(te[u]),n++;continue}if(u===ne){let s=W.N,i=W.G;o!==void 0&&$(o)?(e.push(s+"\u0DCA"),e.push(i),e.push(Y[o]),n+=2):o!==void 0&&q(o)?(e.push(s+"\u0DCA"),e.push(i),n+=2):(o!==void 0&&B(o),e.push(s+"\u0DCA"),e.push(i+"\u0DCA"),n++);continue}if(Ge(u)&&!B(u)){e.push(re[u]),n++;continue}if(Z(u)){let s=Ae[u];u==="SANYAKA_B"?o!==void 0&&$(o)?(e.push(s),e.push(Y[o]),n+=2):o!==void 0&&q(o)?(e.push(s),n+=2):(o!==void 0&&(B(o)||Z(o)),e.push(s+"\u0DCA"),n++):(e.push(s),n++);continue}if(B(u)){let s=W[u];if(o!==void 0&&je(o)){let i=t[n+2],g=W[o];if(o==="R_CONS"&&i==="V_U"){e.push(s+"\u0DD8"),n+=3;continue}if(o==="R_CONS"&&i==="V_UU"){e.push(s+"\u0DF2"),n+=3;continue}if(i!==void 0&&$(i)){e.push(s+"\u0DCA\u200D"+g),e.push(Y[i]),n+=3;continue}else if(i!==void 0&&q(i)){e.push(s+"\u0DCA\u200D"+g),n+=3;continue}else if(i!==void 0&&(B(i)||Z(i)||i===ne)){e.push(s+"\u0DCA\u200D"+g+"\u0DCA"),n+=2;continue}else{e.push(s+"\u0DCA\u200D"+g+"\u0DCA"),n+=2;continue}}if(o!==void 0&&$(o)){e.push(s),e.push(Y[o]),n+=2;continue}if(o!==void 0&&q(o)){e.push(s),n+=2;continue}if(o!==void 0&&(B(o)||Z(o)||o===ne)){e.push(s+"\u0DCA"),n++;continue}if(Xe(o)||o===void 0){e.push(s+"\u0DCA"),n++;continue}if(o!==void 0&&te[o]!==void 0){e.push(s),n++;continue}e.push(s),n++;continue}e.push(u),n++}return e.join("")}function H(t,e){if(!t)return t;let n=Je(t);return Ze(n)}function Se(t,e){if(!t)return t;let n=-1;for(let s=t.length-1;s>=0;s--)if(t[s]===" "||t[s]===`
|
|
5
|
+
`){n=s;break}if(n===-1)return H(t,e);let u=t.substring(0,n+1),o=t.substring(n+1);return o?u+H(o,e):t}function me(t,e){let n=t,u=H(t,e),o=0;for(let s=0;s<Math.min(n.length,u.length);s++)n[s]!==u[s]&&o++;return{text:u,original:n,conversions:o}}function Q(t){let e=t.charCodeAt(0);return e>=3456&&e<=3583}function _e(t){for(let e of t)if(Q(e))return!0;return!1}function Te(t){let e=[],n="",u=null;for(let o of t){let s=Q(o);u===null&&(u=s),s===u?n+=o:(n&&e.push({text:n,isSinhala:u}),n=o,u=s)}return n&&u!==null&&e.push({text:n,isSinhala:u}),e}var be=re,Le=Ee,ye=pe,Re={x:"\u0D82",H:"\u0D83"},ve="\u0DCA",Oe="\u200D";var c=require("react");function Ne(){return{children:new Map,isTerminal:!1}}var qe=["zdha","chh","thh","dhh","zga","zja","zda","zqa","zka","zha","aa","Aa","AA","ai","au","ou","ii","uu","ee","oo","Ru","Lu","kh","gh","ch","ph","bh","th","dh","Sh","sh","ng","Th","Dh","Ba","a","A","i","u","U","e","E","o","O","R","k","g","j","t","d","T","D","n","N","p","b","B","m","y","r","l","L","v","w","s","S","h","f","q","x","X","H"],se=$e(qe);function $e(t){let e=Ne();for(let n of t){let u=e;for(let o of n){let s=u.children.get(o);s||(s=Ne(),u.children.set(o,s)),u=s}u.isTerminal=!0}return e}function Ce(t){if(t.length===0)return!0;let e=se;for(let n of t){let u=e.children.get(n);if(!u)return!1;e=u}return e.children.size>0}function Qe(t){if(t.length===0)return!0;let e=se;for(let n of t){let u=e.children.get(n);if(!u)return!1;e=u}return!0}function et(t,e){let n=se,u=0;for(let o=e;o<t.length;o++){let s=n.children.get(t[o]);if(!s)break;n=s,n.isTerminal&&(u=o-e+1)}return u}var He=new Set(["k","kh","g","gh","ch","chh","j","t","Th","d","Dh","T","D","th","thh","dh","dhh","n","N","p","ph","b","bh","B","Ba","m","y","r","l","L","v","w","sh","Sh","S","s","h","f","q","ng","zga","zja","zda","zdha","zqa","zka","zha"]),tt=new Set(["a","aa","A","Aa","AA","i","ii","u","uu","U","e","ee","E","o","oo","O","ai","au","ou","R","Ru"]);function oe(t){if(!t)return{toCommit:"",remaining:""};let e=[],n=0,u=-1;for(;n<t.length;){let m=et(t,n);if(m>0)e.push({start:n,length:m,pattern:t.slice(n,n+m),isPassthrough:!1}),n+=m;else if(Qe(t[n])){u=n;break}else e.push({start:n,length:1,pattern:t[n],isPassthrough:!0}),n+=1}if(e.length===0)return{toCommit:"",remaining:t};if(u>=0){let m=e.length;for(;m>0;){let a=e[m-1];if(!a.isPassthrough&&He.has(a.pattern)){m--;continue}break}let A=m>0?e[m-1].start+e[m-1].length:0;return A===0?{toCommit:"",remaining:t}:{toCommit:H(t.slice(0,A)),remaining:t.slice(A)}}let o=e.length-1,s=e[o],i=s.start+s.length;if(e.length===1)return s.isPassthrough?{toCommit:s.pattern,remaining:""}:{toCommit:"",remaining:t};let g=o;for(i===t.length&&Ce(s.pattern)&&(g=o);g>0;){let m=e[g],A=e[g-1];if(!A.isPassthrough&&He.has(A.pattern)&&!m.isPassthrough&&(tt.has(m.pattern)||Ce(m.pattern))){g--;continue}break}let _=e[g].start;if(_===0)return{toCommit:"",remaining:t};let k=t.slice(0,_),V=t.slice(_);return{toCommit:H(k),remaining:V}}var D=class{constructor(){de(this,"buffer","")}getBuffer(){return this.buffer}getSpeculativeDisplay(){return this.buffer?H(this.buffer):""}processKey(e){this.buffer+=e;let n=oe(this.buffer);return this.buffer=n.remaining,n}backspace(){return this.buffer.length>0?(this.buffer=this.buffer.slice(0,-1),!0):!1}flush(){if(!this.buffer)return"";let e=H(this.buffer);return this.buffer="",e}hasPending(){return this.buffer.length>0}reset(){this.buffer=""}};function ie(t){return t.length===1&&/[a-zA-Z]/.test(t)}function xe(t){let{enabled:e=!1,onConvert:n,options:u,initialValue:o="",mobileSupport:s=!1}=t||{},[i,g]=(0,c.useState)(o),[_,k]=(0,c.useState)(e),[V,m]=(0,c.useState)(""),A=(0,c.useRef)(null),a=(0,c.useRef)(new D),N=(0,c.useRef)(0),x=(0,c.useRef)(-1),E=(0,c.useRef)(null),v=(0,c.useRef)(null),l=(0,c.useCallback)(()=>{let r=a.current.getBuffer(),f=a.current.getSpeculativeDisplay();N.current=f.length,m(r)},[]),h=(0,c.useCallback)((r,f,S)=>{let O=N.current,C=Math.max(0,f-O),I=r.slice(0,C),d=r.slice(f);return{newValue:I+S+d,newCursor:I.length+S.length}},[]),b=(0,c.useCallback)((r,f)=>{x.current=f,v.current=r,g(r)},[]),M=(0,c.useCallback)(()=>{a.current.reset(),N.current=0,l(),x.current=-1,E.current=null,v.current=null},[l]),w=(0,c.useCallback)((r,f)=>{if(!a.current.hasPending())return{value:f,cursor:r};let S=a.current.flush(),O=h(f,r,S);return l(),{value:O.newValue,cursor:O.newCursor}},[h,l]),ee=(0,c.useCallback)(r=>{M(),g(r)},[M]),y=(0,c.useCallback)(()=>{A.current?.focus()},[]),R=(0,c.useCallback)(()=>{M(),g("")},[M]),F=(0,c.useCallback)(()=>{if(!i)return;let r=i,f=H(r,u);M(),v.current=f,g(f),n&&f!==r&&n(r,f)},[i,u,n,M]),G=(0,c.useCallback)(()=>{if(!a.current.hasPending())return i;let r=A.current?.selectionStart??i.length,f=w(r,i);return b(f.value,f.cursor),f.value},[i,w,b]),K=(0,c.useCallback)(r=>{if(!r&&a.current.hasPending()){let f=A.current?.selectionStart??i.length,S=a.current.flush(),O=h(i,f,S);l(),g(O.newValue)}a.current.reset(),l(),k(r)},[i,h,l]),X=(0,c.useCallback)(()=>{K(!_)},[_,K]),z=(0,c.useCallback)(r=>{A.current=r},[]),ue=(0,c.useCallback)(r=>{if(A.current=r.currentTarget,!_||!s)return;let f=r.nativeEvent;if(f.inputType!=="insertText")return;let S=f.data??"";if(S.length!==1)return;if(E.current===S){r.preventDefault(),E.current=null;return}E.current=null;let O=r.currentTarget,C=O.selectionStart,I=O.selectionEnd,d=C,p=C!==I;if(ie(S)){r.preventDefault();let T=i,L=d;if(p){if(a.current.hasPending()){let Me=a.current.flush();T=h(T,L,Me).newValue,N.current=0}let j=Math.min(C,I),ge=Math.max(C,I);T=T.slice(0,j)+T.slice(ge),L=j,a.current.reset(),N.current=0}let P=a.current.processKey(S),U=h(T,L,P.toCommit+a.current.getSpeculativeDisplay());l(),b(U.newValue,U.newCursor);return}if(a.current.hasPending()){r.preventDefault();let T=a.current.flush(),L=h(i,d,T+S);l(),b(L.newValue,L.newCursor)}},[_,s,i,h,l,b]),le=(0,c.useCallback)(r=>{if(A.current=r.currentTarget,!_)return;let f=r.currentTarget,S=f.selectionStart,O=f.selectionEnd,C=S,I=S!==O;if(ie(r.key)&&!r.ctrlKey&&!r.metaKey&&!r.altKey){r.preventDefault(),E.current=r.key;let d=i,p=C;if(I){if(a.current.hasPending()){let j=a.current.flush();d=h(d,p,j).newValue,N.current=0}let P=Math.min(S,O),U=Math.max(S,O);d=d.slice(0,P)+d.slice(U),p=P,a.current.reset(),N.current=0}let T=a.current.processKey(r.key),L=h(d,p,T.toCommit+a.current.getSpeculativeDisplay());l(),b(L.newValue,L.newCursor);return}if(r.key==="Backspace"&&!r.ctrlKey&&!r.metaKey&&!I&&a.current.hasPending()){r.preventDefault(),a.current.backspace();let d=a.current.getSpeculativeDisplay(),p=h(i,C,d);l(),b(p.newValue,p.newCursor);return}if((r.ctrlKey||r.metaKey)&&r.key==="a"){if(a.current.hasPending()){let d=a.current.flush(),p=h(i,C,d);l(),x.current=-1,g(p.newValue)}return}if((r.ctrlKey||r.metaKey)&&(r.key==="z"||r.key==="y")){a.current.reset(),N.current=0,l(),x.current=-1;return}if((r.ctrlKey||r.metaKey)&&r.key==="Enter"){r.preventDefault();let d=i;if(a.current.reset(),l(),d){let p=H(d,u);b(p,p.length),n&&p!==d&&n(d,p)}return}if(r.key.length===1&&!ie(r.key)&&!r.ctrlKey&&!r.metaKey&&!r.altKey){if(a.current.hasPending()){r.preventDefault(),E.current=r.key;let d=a.current.flush(),p=h(i,C,d+r.key);l(),b(p.newValue,p.newCursor);return}return}if(r.key==="Enter"&&!r.ctrlKey&&!r.metaKey){if(a.current.hasPending()){r.preventDefault();let d=a.current.flush(),p=h(i,C,d+`
|
|
6
|
+
`);l(),b(p.newValue,p.newCursor);return}return}if(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End"].includes(r.key)){if(a.current.hasPending()){let d=a.current.flush(),p=h(i,C,d);l(),b(p.newValue,p.newCursor)}return}if(r.key==="Backspace"||r.key==="Delete"){if(a.current.hasPending()){r.preventDefault();let d=a.current.flush(),p=h(i,C,d);l();let T=p.newValue,L=p.newCursor;if(I){let P=Math.min(S,O),U=Math.max(S,O);T=T.slice(0,P)+T.slice(U),L=P}else r.key==="Backspace"&&L>0?(T=T.slice(0,L-1)+T.slice(L),L=L-1):r.key==="Delete"&&L<T.length&&(T=T.slice(0,L)+T.slice(L+1));b(T,L)}return}},[_,i,u,n,h,l,b]),ae=(0,c.useCallback)(r=>{if(A.current=r.currentTarget,!_){g(r.target.value);return}if(v.current!==null&&r.target.value===v.current){v.current=null;return}v.current=null,a.current.reset(),N.current=0,l(),x.current=-1,g(r.target.value)},[_,l]),ce=(0,c.useCallback)(r=>{if(A.current=r.currentTarget,!!_&&a.current.hasPending()){let f=A.current?.selectionStart??i.length,S=a.current.flush(),O=h(i,f,S);l(),g(O.newValue)}},[_,i,h,l]),he=(0,c.useCallback)(r=>{if(A.current=r.currentTarget,!!_&&a.current.hasPending()){let f=A.current?.selectionStart??i.length,S=w(f,i);b(S.value,S.cursor)}},[_,i,w,b]);(0,c.useLayoutEffect)(()=>{let r=x.current;r>=0&&A.current&&(A.current.selectionStart=r,A.current.selectionEnd=r),x.current=-1},[i]);let fe=(0,c.useMemo)(()=>({ref:z,value:i,onKeyDown:le,onBeforeInput:ue,onChange:ae,onPaste:ce,onBlur:he}),[z,i,le,ue,ae,ce,he]);return(0,c.useMemo)(()=>({inputProps:fe,value:i,setValue:ee,bufferDisplay:V,enabled:_,toggle:X,setEnabled:K,focus:y,clear:R,convertAll:F,flushPending:G}),[fe,i,ee,V,_,X,K,y,R,F,G])}var nt='input[type="text"], input[type="search"], textarea';function Ve(t={}){let{enabled:e=!0,selector:n=nt,exclude:u,onAttach:o}=t,s=!1,i=null,g=new WeakSet,_=new WeakMap;function k(E){return!(g.has(E)||u&&E.matches(u))}function V(E){if(!k(E))return;let v=new D;_.set(E,v),g.add(E);let l=E instanceof HTMLTextAreaElement,h=E instanceof HTMLInputElement;if(!l&&!h)return;function b(y){if(y.key==="Backspace"){v.backspace()&&(y.preventDefault(),void 0);return}if(y.key==="Enter"||y.key==="Escape"){let R=v.flush();R&&w(R);return}if(y.key.length===1&&!y.ctrlKey&&!y.metaKey&&!y.altKey){y.preventDefault();let R=v.processKey(y.key);R.toCommit&&w(R.toCommit)}}function M(){let y=v.flush();y&&w(y)}function w(y){let R=E,F=R.selectionStart??R.value.length,G=R.selectionEnd??R.value.length,K=R.value.substring(0,F),X=R.value.substring(G);R.value=K+y+X;let z=F+y.length;R.setSelectionRange(z,z),R.dispatchEvent(new Event("input",{bubbles:!0}))}function ee(){}E.addEventListener("keydown",b),E.addEventListener("blur",M),o?.(E)}function m(){document.querySelectorAll(n).forEach(V)}function A(){i=new MutationObserver(E=>{for(let v of E)for(let l of v.addedNodes){if(l.nodeType!==Node.ELEMENT_NODE)continue;let h=l;h.matches(n)&&V(h),h.querySelectorAll(n).forEach(V)}}),i.observe(document.body,{childList:!0,subtree:!0})}function a(){s||(s=!0,m(),A())}function N(){s&&(s=!1,i?.disconnect(),i=null)}function x(){s?N():a()}return e&&a(),{start:a,stop:N,isRunning:()=>s,toggle:x}}var Ie="singlish-enabled";function ke(t={}){let{position:e="bottom-right",theme:n="auto",showLabel:u=!0,onToggle:o}=t,s=_(),i=null,g=null;function _(){if(typeof localStorage>"u")return!0;let l=localStorage.getItem(Ie);return l===null?!0:l==="true"}function k(l){typeof localStorage>"u"||localStorage.setItem(Ie,String(l))}function V(){let l=document.createElement("button");return l.className=`singlish-toggle singlish-toggle--${e}`,l.setAttribute("aria-label","Toggle Singlish input"),l.setAttribute("type","button"),m(l),l.addEventListener("click",A),l.addEventListener("keydown",h=>{(h.key==="Enter"||h.key===" ")&&(h.preventDefault(),A())}),l}function m(l){let h=s?"\u{1F1F1}\u{1F1F0}":"EN",b=s?"\u0DC3\u0DD2\u0D82":"English";u?l.innerHTML=`<span class="singlish-toggle__icon">${h}</span><span class="singlish-toggle__label">${b}</span>`:l.innerHTML=`<span class="singlish-toggle__icon">${h}</span>`,l.classList.toggle("singlish-toggle--enabled",s),l.setAttribute("aria-pressed",String(s))}function A(){s=!s,k(s),i&&m(i),o?.(s)}function a(l){i||(g=l||document.body,i=V(),g.appendChild(i),v())}function N(){i&&(i.remove(),i=null,g=null)}function x(l){s!==l&&(s=l,k(l),i&&m(i))}function E(){return s}function v(){if(document.getElementById("singlish-toggle-styles"))return;let l=document.createElement("style");l.id="singlish-toggle-styles",l.textContent=rt(n),document.head.appendChild(l)}return{mount:a,unmount:N,setEnabled:x,getEnabled:E}}function rt(t){let e="rgba(255, 255, 255, 0.9)",n="rgba(30, 30, 30, 0.9)",u="#1a1a1a",o="#ffffff",s=t==="dark"?n:e,i=t==="dark"?o:u;return`
|
|
7
|
+
.singlish-toggle {
|
|
8
|
+
position: fixed;
|
|
9
|
+
z-index: 9999;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
gap: 8px;
|
|
13
|
+
padding: 10px 16px;
|
|
14
|
+
background: ${s};
|
|
15
|
+
backdrop-filter: blur(10px);
|
|
16
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
17
|
+
border-radius: 12px;
|
|
18
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
19
|
+
color: ${i};
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
21
|
+
font-size: 14px;
|
|
22
|
+
font-weight: 500;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
transition: all 0.2s ease;
|
|
25
|
+
user-select: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.singlish-toggle:hover {
|
|
29
|
+
transform: translateY(-2px);
|
|
30
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.singlish-toggle:active {
|
|
34
|
+
transform: translateY(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.singlish-toggle:focus {
|
|
38
|
+
outline: 2px solid #4A90E2;
|
|
39
|
+
outline-offset: 2px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.singlish-toggle--top-right {
|
|
43
|
+
top: 20px;
|
|
44
|
+
right: 20px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.singlish-toggle--top-left {
|
|
48
|
+
top: 20px;
|
|
49
|
+
left: 20px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.singlish-toggle--bottom-right {
|
|
53
|
+
bottom: 20px;
|
|
54
|
+
right: 20px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.singlish-toggle--bottom-left {
|
|
58
|
+
bottom: 20px;
|
|
59
|
+
left: 20px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.singlish-toggle__icon {
|
|
63
|
+
font-size: 18px;
|
|
64
|
+
line-height: 1;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.singlish-toggle__label {
|
|
68
|
+
font-size: 13px;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.singlish-toggle--enabled {
|
|
73
|
+
background: linear-gradient(135deg, rgba(74, 144, 226, 0.9), rgba(106, 90, 205, 0.9));
|
|
74
|
+
color: white;
|
|
75
|
+
border-color: rgba(255, 255, 255, 0.3);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@media (prefers-color-scheme: dark) {
|
|
79
|
+
.singlish-toggle {
|
|
80
|
+
background: ${t==="auto"?n:s};
|
|
81
|
+
color: ${t==="auto"?o:i};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@media (max-width: 768px) {
|
|
86
|
+
.singlish-toggle {
|
|
87
|
+
padding: 8px 12px;
|
|
88
|
+
font-size: 13px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.singlish-toggle__icon {
|
|
92
|
+
font-size: 16px;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`}0&&(module.exports={CONSONANTS,HAL_CHAR,SPECIAL,SinglishIME,VOWELS,VOWEL_MODIFIERS_MAP,ZWJ_CHAR,containsSinhala,convertLastWord,convertSinglishToSinhala,convertWithMetadata,createAutoAttach,createUIToggle,isSinhalaChar,resolveBuffer,segmentText,useSinglishConverter});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
interface ConversionOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Whether to preserve non-Sinhala characters (numbers, punctuation, English)
|
|
4
|
+
* @default true
|
|
5
|
+
*/
|
|
6
|
+
preserveNonSinhala?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Maximum pattern length to attempt matching
|
|
9
|
+
* @default 4
|
|
10
|
+
*/
|
|
11
|
+
maxPatternLength?: number;
|
|
12
|
+
}
|
|
13
|
+
interface ConversionResult {
|
|
14
|
+
/**
|
|
15
|
+
* The converted Sinhala text
|
|
16
|
+
*/
|
|
17
|
+
text: string;
|
|
18
|
+
/**
|
|
19
|
+
* Original Singlish input
|
|
20
|
+
*/
|
|
21
|
+
original: string;
|
|
22
|
+
/**
|
|
23
|
+
* Number of characters converted
|
|
24
|
+
*/
|
|
25
|
+
conversions: number;
|
|
26
|
+
}
|
|
27
|
+
interface UseSinglishConverterOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Initial enabled state
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Callback fired when conversion occurs
|
|
35
|
+
*/
|
|
36
|
+
onConvert?: (original: string, converted: string) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Conversion options
|
|
39
|
+
*/
|
|
40
|
+
options?: ConversionOptions;
|
|
41
|
+
/**
|
|
42
|
+
* Initial input value
|
|
43
|
+
* @default ''
|
|
44
|
+
*/
|
|
45
|
+
initialValue?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Experimental mobile support.
|
|
48
|
+
* Use with caution.
|
|
49
|
+
*/
|
|
50
|
+
mobileSupport?: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface SinglishTextareaInputProps {
|
|
53
|
+
ref: React.RefCallback<HTMLTextAreaElement>;
|
|
54
|
+
value: string;
|
|
55
|
+
onKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
|
|
56
|
+
onBeforeInput: (e: React.FormEvent<HTMLTextAreaElement>) => void;
|
|
57
|
+
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
|
58
|
+
onPaste: (e: React.ClipboardEvent<HTMLTextAreaElement>) => void;
|
|
59
|
+
onBlur: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
|
|
60
|
+
}
|
|
61
|
+
interface UseSinglishConverterReturn {
|
|
62
|
+
/**
|
|
63
|
+
* Spread this object onto a textarea to enable real-time IME behavior.
|
|
64
|
+
*/
|
|
65
|
+
inputProps: SinglishTextareaInputProps;
|
|
66
|
+
/**
|
|
67
|
+
* Current textarea value.
|
|
68
|
+
*/
|
|
69
|
+
value: string;
|
|
70
|
+
/**
|
|
71
|
+
* Set textarea value while resetting IME internal state.
|
|
72
|
+
*/
|
|
73
|
+
setValue: (value: string) => void;
|
|
74
|
+
/**
|
|
75
|
+
* Current raw IME buffer (romanized form), useful for debug UI.
|
|
76
|
+
*/
|
|
77
|
+
bufferDisplay: string;
|
|
78
|
+
/**
|
|
79
|
+
* Current enabled state
|
|
80
|
+
*/
|
|
81
|
+
enabled: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Toggle enabled state
|
|
84
|
+
*/
|
|
85
|
+
toggle: () => void;
|
|
86
|
+
/**
|
|
87
|
+
* Set enabled state explicitly.
|
|
88
|
+
*/
|
|
89
|
+
setEnabled: (enabled: boolean) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Focus the bound textarea.
|
|
92
|
+
*/
|
|
93
|
+
focus: () => void;
|
|
94
|
+
/**
|
|
95
|
+
* Clear textarea and reset IME.
|
|
96
|
+
*/
|
|
97
|
+
clear: () => void;
|
|
98
|
+
/**
|
|
99
|
+
* Convert whole current value using stateless converter.
|
|
100
|
+
*/
|
|
101
|
+
convertAll: () => void;
|
|
102
|
+
/**
|
|
103
|
+
* Commit pending IME buffer into value and return the committed text.
|
|
104
|
+
*/
|
|
105
|
+
flushPending: () => string;
|
|
106
|
+
}
|
|
107
|
+
interface AutoAttachOptions {
|
|
108
|
+
/**
|
|
109
|
+
* Start with auto-attach enabled
|
|
110
|
+
* @default true
|
|
111
|
+
*/
|
|
112
|
+
enabled?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* CSS selector for elements to attach to
|
|
115
|
+
* @default 'input[type="text"], input[type="search"], textarea'
|
|
116
|
+
*/
|
|
117
|
+
selector?: string;
|
|
118
|
+
/**
|
|
119
|
+
* CSS selector for elements to exclude
|
|
120
|
+
*/
|
|
121
|
+
exclude?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Callback when element is attached
|
|
124
|
+
*/
|
|
125
|
+
onAttach?: (element: HTMLElement) => void;
|
|
126
|
+
}
|
|
127
|
+
interface AutoAttachInstance {
|
|
128
|
+
start: () => void;
|
|
129
|
+
stop: () => void;
|
|
130
|
+
isRunning: () => boolean;
|
|
131
|
+
toggle: () => void;
|
|
132
|
+
}
|
|
133
|
+
interface UIToggleOptions {
|
|
134
|
+
/**
|
|
135
|
+
* Position of the toggle button
|
|
136
|
+
* @default 'bottom-right'
|
|
137
|
+
*/
|
|
138
|
+
position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
|
139
|
+
/**
|
|
140
|
+
* Theme for the toggle button
|
|
141
|
+
* @default 'auto'
|
|
142
|
+
*/
|
|
143
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
144
|
+
/**
|
|
145
|
+
* Show text label alongside icon
|
|
146
|
+
* @default true
|
|
147
|
+
*/
|
|
148
|
+
showLabel?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Callback when toggle state changes
|
|
151
|
+
*/
|
|
152
|
+
onToggle?: (enabled: boolean) => void;
|
|
153
|
+
}
|
|
154
|
+
interface UIToggleInstance {
|
|
155
|
+
mount: (container?: HTMLElement) => void;
|
|
156
|
+
unmount: () => void;
|
|
157
|
+
setEnabled: (enabled: boolean) => void;
|
|
158
|
+
getEnabled: () => boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Core Singlish to Sinhala conversion logic.
|
|
163
|
+
*
|
|
164
|
+
* Approaches conversion in two steps:
|
|
165
|
+
* 1. Tokenize Singlish -> Phonemes (greedy matching)
|
|
166
|
+
* 2. Phonemes -> Sinhala Unicode (context aware)
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Main conversion function: Singlish → Sinhala
|
|
171
|
+
*/
|
|
172
|
+
declare function convertSinglishToSinhala(text: string, _options?: ConversionOptions): string;
|
|
173
|
+
/**
|
|
174
|
+
* Convert only the last word (for real-time typing)
|
|
175
|
+
*/
|
|
176
|
+
declare function convertLastWord(text: string, options?: ConversionOptions): string;
|
|
177
|
+
/**
|
|
178
|
+
* Convert with metadata
|
|
179
|
+
*/
|
|
180
|
+
declare function convertWithMetadata(text: string, options?: ConversionOptions): ConversionResult;
|
|
181
|
+
/**
|
|
182
|
+
* Check if character is Sinhala
|
|
183
|
+
*/
|
|
184
|
+
declare function isSinhalaChar(char: string): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Check if text contains Sinhala
|
|
187
|
+
*/
|
|
188
|
+
declare function containsSinhala(text: string): boolean;
|
|
189
|
+
/**
|
|
190
|
+
* Segment text into Sinhala and non-Sinhala parts
|
|
191
|
+
*/
|
|
192
|
+
declare function segmentText(text: string): Array<{
|
|
193
|
+
text: string;
|
|
194
|
+
isSinhala: boolean;
|
|
195
|
+
}>;
|
|
196
|
+
declare const VOWELS: Record<string, string>;
|
|
197
|
+
declare const VOWEL_MODIFIERS_MAP: Set<string>;
|
|
198
|
+
declare const CONSONANTS: Set<string>;
|
|
199
|
+
declare const SPECIAL: {
|
|
200
|
+
x: string;
|
|
201
|
+
H: string;
|
|
202
|
+
};
|
|
203
|
+
declare const HAL_CHAR = "\u0DCA";
|
|
204
|
+
declare const ZWJ_CHAR = "\u200D";
|
|
205
|
+
|
|
206
|
+
declare function useSinglishConverter(hookOptions?: UseSinglishConverterOptions): UseSinglishConverterReturn;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Real-time IME for Singlish input.
|
|
210
|
+
*/
|
|
211
|
+
interface ResolveResult {
|
|
212
|
+
/** Sinhala text to commit (may be empty if nothing is committable yet) */
|
|
213
|
+
toCommit: string;
|
|
214
|
+
/** Remaining Roman buffer (ambiguous tail that could extend further) */
|
|
215
|
+
remaining: string;
|
|
216
|
+
}
|
|
217
|
+
declare function resolveBuffer(buffer: string): ResolveResult;
|
|
218
|
+
interface IMEState {
|
|
219
|
+
committed: string;
|
|
220
|
+
pending: string;
|
|
221
|
+
}
|
|
222
|
+
declare class SinglishIME {
|
|
223
|
+
private buffer;
|
|
224
|
+
getBuffer(): string;
|
|
225
|
+
getSpeculativeDisplay(): string;
|
|
226
|
+
processKey(key: string): ResolveResult;
|
|
227
|
+
backspace(): boolean;
|
|
228
|
+
flush(): string;
|
|
229
|
+
hasPending(): boolean;
|
|
230
|
+
reset(): void;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Auto-attach Singlish conversion to input elements.
|
|
235
|
+
* Provides opt-in DOM integration with cleanup support.
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
declare function createAutoAttach(options?: AutoAttachOptions): AutoAttachInstance;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* UI toggle button for Singlish conversion.
|
|
242
|
+
* Provides a floating button with state management.
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
declare function createUIToggle(options?: UIToggleOptions): UIToggleInstance;
|
|
246
|
+
|
|
247
|
+
export { type AutoAttachInstance, type AutoAttachOptions, CONSONANTS, type ConversionOptions, type ConversionResult, HAL_CHAR, type IMEState, type ResolveResult, SPECIAL, SinglishIME, type SinglishTextareaInputProps, type UIToggleInstance, type UIToggleOptions, type UseSinglishConverterOptions, type UseSinglishConverterReturn, VOWELS, VOWEL_MODIFIERS_MAP, ZWJ_CHAR, containsSinhala, convertLastWord, convertSinglishToSinhala, convertWithMetadata, createAutoAttach, createUIToggle, isSinhalaChar, resolveBuffer, segmentText, useSinglishConverter };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
interface ConversionOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Whether to preserve non-Sinhala characters (numbers, punctuation, English)
|
|
4
|
+
* @default true
|
|
5
|
+
*/
|
|
6
|
+
preserveNonSinhala?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Maximum pattern length to attempt matching
|
|
9
|
+
* @default 4
|
|
10
|
+
*/
|
|
11
|
+
maxPatternLength?: number;
|
|
12
|
+
}
|
|
13
|
+
interface ConversionResult {
|
|
14
|
+
/**
|
|
15
|
+
* The converted Sinhala text
|
|
16
|
+
*/
|
|
17
|
+
text: string;
|
|
18
|
+
/**
|
|
19
|
+
* Original Singlish input
|
|
20
|
+
*/
|
|
21
|
+
original: string;
|
|
22
|
+
/**
|
|
23
|
+
* Number of characters converted
|
|
24
|
+
*/
|
|
25
|
+
conversions: number;
|
|
26
|
+
}
|
|
27
|
+
interface UseSinglishConverterOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Initial enabled state
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Callback fired when conversion occurs
|
|
35
|
+
*/
|
|
36
|
+
onConvert?: (original: string, converted: string) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Conversion options
|
|
39
|
+
*/
|
|
40
|
+
options?: ConversionOptions;
|
|
41
|
+
/**
|
|
42
|
+
* Initial input value
|
|
43
|
+
* @default ''
|
|
44
|
+
*/
|
|
45
|
+
initialValue?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Experimental mobile support.
|
|
48
|
+
* Use with caution.
|
|
49
|
+
*/
|
|
50
|
+
mobileSupport?: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface SinglishTextareaInputProps {
|
|
53
|
+
ref: React.RefCallback<HTMLTextAreaElement>;
|
|
54
|
+
value: string;
|
|
55
|
+
onKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
|
|
56
|
+
onBeforeInput: (e: React.FormEvent<HTMLTextAreaElement>) => void;
|
|
57
|
+
onChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
|
|
58
|
+
onPaste: (e: React.ClipboardEvent<HTMLTextAreaElement>) => void;
|
|
59
|
+
onBlur: (e: React.FocusEvent<HTMLTextAreaElement>) => void;
|
|
60
|
+
}
|
|
61
|
+
interface UseSinglishConverterReturn {
|
|
62
|
+
/**
|
|
63
|
+
* Spread this object onto a textarea to enable real-time IME behavior.
|
|
64
|
+
*/
|
|
65
|
+
inputProps: SinglishTextareaInputProps;
|
|
66
|
+
/**
|
|
67
|
+
* Current textarea value.
|
|
68
|
+
*/
|
|
69
|
+
value: string;
|
|
70
|
+
/**
|
|
71
|
+
* Set textarea value while resetting IME internal state.
|
|
72
|
+
*/
|
|
73
|
+
setValue: (value: string) => void;
|
|
74
|
+
/**
|
|
75
|
+
* Current raw IME buffer (romanized form), useful for debug UI.
|
|
76
|
+
*/
|
|
77
|
+
bufferDisplay: string;
|
|
78
|
+
/**
|
|
79
|
+
* Current enabled state
|
|
80
|
+
*/
|
|
81
|
+
enabled: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Toggle enabled state
|
|
84
|
+
*/
|
|
85
|
+
toggle: () => void;
|
|
86
|
+
/**
|
|
87
|
+
* Set enabled state explicitly.
|
|
88
|
+
*/
|
|
89
|
+
setEnabled: (enabled: boolean) => void;
|
|
90
|
+
/**
|
|
91
|
+
* Focus the bound textarea.
|
|
92
|
+
*/
|
|
93
|
+
focus: () => void;
|
|
94
|
+
/**
|
|
95
|
+
* Clear textarea and reset IME.
|
|
96
|
+
*/
|
|
97
|
+
clear: () => void;
|
|
98
|
+
/**
|
|
99
|
+
* Convert whole current value using stateless converter.
|
|
100
|
+
*/
|
|
101
|
+
convertAll: () => void;
|
|
102
|
+
/**
|
|
103
|
+
* Commit pending IME buffer into value and return the committed text.
|
|
104
|
+
*/
|
|
105
|
+
flushPending: () => string;
|
|
106
|
+
}
|
|
107
|
+
interface AutoAttachOptions {
|
|
108
|
+
/**
|
|
109
|
+
* Start with auto-attach enabled
|
|
110
|
+
* @default true
|
|
111
|
+
*/
|
|
112
|
+
enabled?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* CSS selector for elements to attach to
|
|
115
|
+
* @default 'input[type="text"], input[type="search"], textarea'
|
|
116
|
+
*/
|
|
117
|
+
selector?: string;
|
|
118
|
+
/**
|
|
119
|
+
* CSS selector for elements to exclude
|
|
120
|
+
*/
|
|
121
|
+
exclude?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Callback when element is attached
|
|
124
|
+
*/
|
|
125
|
+
onAttach?: (element: HTMLElement) => void;
|
|
126
|
+
}
|
|
127
|
+
interface AutoAttachInstance {
|
|
128
|
+
start: () => void;
|
|
129
|
+
stop: () => void;
|
|
130
|
+
isRunning: () => boolean;
|
|
131
|
+
toggle: () => void;
|
|
132
|
+
}
|
|
133
|
+
interface UIToggleOptions {
|
|
134
|
+
/**
|
|
135
|
+
* Position of the toggle button
|
|
136
|
+
* @default 'bottom-right'
|
|
137
|
+
*/
|
|
138
|
+
position?: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left';
|
|
139
|
+
/**
|
|
140
|
+
* Theme for the toggle button
|
|
141
|
+
* @default 'auto'
|
|
142
|
+
*/
|
|
143
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
144
|
+
/**
|
|
145
|
+
* Show text label alongside icon
|
|
146
|
+
* @default true
|
|
147
|
+
*/
|
|
148
|
+
showLabel?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Callback when toggle state changes
|
|
151
|
+
*/
|
|
152
|
+
onToggle?: (enabled: boolean) => void;
|
|
153
|
+
}
|
|
154
|
+
interface UIToggleInstance {
|
|
155
|
+
mount: (container?: HTMLElement) => void;
|
|
156
|
+
unmount: () => void;
|
|
157
|
+
setEnabled: (enabled: boolean) => void;
|
|
158
|
+
getEnabled: () => boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Core Singlish to Sinhala conversion logic.
|
|
163
|
+
*
|
|
164
|
+
* Approaches conversion in two steps:
|
|
165
|
+
* 1. Tokenize Singlish -> Phonemes (greedy matching)
|
|
166
|
+
* 2. Phonemes -> Sinhala Unicode (context aware)
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Main conversion function: Singlish → Sinhala
|
|
171
|
+
*/
|
|
172
|
+
declare function convertSinglishToSinhala(text: string, _options?: ConversionOptions): string;
|
|
173
|
+
/**
|
|
174
|
+
* Convert only the last word (for real-time typing)
|
|
175
|
+
*/
|
|
176
|
+
declare function convertLastWord(text: string, options?: ConversionOptions): string;
|
|
177
|
+
/**
|
|
178
|
+
* Convert with metadata
|
|
179
|
+
*/
|
|
180
|
+
declare function convertWithMetadata(text: string, options?: ConversionOptions): ConversionResult;
|
|
181
|
+
/**
|
|
182
|
+
* Check if character is Sinhala
|
|
183
|
+
*/
|
|
184
|
+
declare function isSinhalaChar(char: string): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Check if text contains Sinhala
|
|
187
|
+
*/
|
|
188
|
+
declare function containsSinhala(text: string): boolean;
|
|
189
|
+
/**
|
|
190
|
+
* Segment text into Sinhala and non-Sinhala parts
|
|
191
|
+
*/
|
|
192
|
+
declare function segmentText(text: string): Array<{
|
|
193
|
+
text: string;
|
|
194
|
+
isSinhala: boolean;
|
|
195
|
+
}>;
|
|
196
|
+
declare const VOWELS: Record<string, string>;
|
|
197
|
+
declare const VOWEL_MODIFIERS_MAP: Set<string>;
|
|
198
|
+
declare const CONSONANTS: Set<string>;
|
|
199
|
+
declare const SPECIAL: {
|
|
200
|
+
x: string;
|
|
201
|
+
H: string;
|
|
202
|
+
};
|
|
203
|
+
declare const HAL_CHAR = "\u0DCA";
|
|
204
|
+
declare const ZWJ_CHAR = "\u200D";
|
|
205
|
+
|
|
206
|
+
declare function useSinglishConverter(hookOptions?: UseSinglishConverterOptions): UseSinglishConverterReturn;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Real-time IME for Singlish input.
|
|
210
|
+
*/
|
|
211
|
+
interface ResolveResult {
|
|
212
|
+
/** Sinhala text to commit (may be empty if nothing is committable yet) */
|
|
213
|
+
toCommit: string;
|
|
214
|
+
/** Remaining Roman buffer (ambiguous tail that could extend further) */
|
|
215
|
+
remaining: string;
|
|
216
|
+
}
|
|
217
|
+
declare function resolveBuffer(buffer: string): ResolveResult;
|
|
218
|
+
interface IMEState {
|
|
219
|
+
committed: string;
|
|
220
|
+
pending: string;
|
|
221
|
+
}
|
|
222
|
+
declare class SinglishIME {
|
|
223
|
+
private buffer;
|
|
224
|
+
getBuffer(): string;
|
|
225
|
+
getSpeculativeDisplay(): string;
|
|
226
|
+
processKey(key: string): ResolveResult;
|
|
227
|
+
backspace(): boolean;
|
|
228
|
+
flush(): string;
|
|
229
|
+
hasPending(): boolean;
|
|
230
|
+
reset(): void;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Auto-attach Singlish conversion to input elements.
|
|
235
|
+
* Provides opt-in DOM integration with cleanup support.
|
|
236
|
+
*/
|
|
237
|
+
|
|
238
|
+
declare function createAutoAttach(options?: AutoAttachOptions): AutoAttachInstance;
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* UI toggle button for Singlish conversion.
|
|
242
|
+
* Provides a floating button with state management.
|
|
243
|
+
*/
|
|
244
|
+
|
|
245
|
+
declare function createUIToggle(options?: UIToggleOptions): UIToggleInstance;
|
|
246
|
+
|
|
247
|
+
export { type AutoAttachInstance, type AutoAttachOptions, CONSONANTS, type ConversionOptions, type ConversionResult, HAL_CHAR, type IMEState, type ResolveResult, SPECIAL, SinglishIME, type SinglishTextareaInputProps, type UIToggleInstance, type UIToggleOptions, type UseSinglishConverterOptions, type UseSinglishConverterReturn, VOWELS, VOWEL_MODIFIERS_MAP, ZWJ_CHAR, containsSinhala, convertLastWord, convertSinglishToSinhala, convertWithMetadata, createAutoAttach, createUIToggle, isSinhalaChar, resolveBuffer, segmentText, useSinglishConverter };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var Re=Object.defineProperty;var ve=(n,e,t)=>e in n?Re(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var de=(n,e,t)=>ve(n,typeof e!="symbol"?e+"":e,t);var Oe=[["zdha","SANYAKA_DHA"],["chh","ASPIRATED_CH"],["thh","ASPIRATED_TH"],["dhh","ASPIRATED_DH"],["zga","SANYAKA_GA"],["zja","SANYAKA_JA"],["zda","SANYAKA_DA"],["zqa","SANYAKA_DHA"],["zka","SANYAKA_KA"],["zha","SANYAKA_HA"],["aa","V_AA"],["Aa","V_AE_LONG"],["AA","V_AE_LONG"],["ai","V_AI"],["au","V_AU"],["ou","V_AU"],["ii","V_II"],["uu","V_UU"],["ee","V_EE"],["oo","V_OO"],["Ru","V_RU_LONG"],["Lu","SPECIAL_LU"],["kh","KH"],["gh","GH"],["ch","CH"],["ph","PH"],["bh","BH"],["th","TH"],["dh","DH"],["Sh","RETROFLEX_S"],["sh","SH"],["ng","N_G"],["Th","RETROFLEX_TH"],["Dh","RETROFLEX_DH"],["Ba","SANYAKA_BA"],["a","V_A"],["A","V_AE"],["i","V_I"],["u","V_U"],["U","V_UU"],["e","V_E"],["E","V_EE"],["o","V_O"],["O","V_OO"],["R","V_RU"],["k","K"],["g","G"],["j","J"],["t","RETROFLEX_T"],["d","RETROFLEX_D"],["T","RETROFLEX_TH_SINGLE"],["D","RETROFLEX_DH_SINGLE"],["n","N"],["N","RETROFLEX_N"],["p","P"],["b","B_LOWER"],["B","SANYAKA_B"],["m","M"],["y","Y"],["r","R_CONS"],["l","L_CONS"],["L","RETROFLEX_L"],["v","V_CONS"],["w","V_CONS"],["s","S_CONS"],["S","RETROFLEX_S"],["h","H_CONS"],["f","F"],["q","DH"],["x","ANUSVARA"],["X","MAHAPRANAANUSVARA"],["H","VISARGA"],[" "," "],[`
|
|
2
|
+
`,`
|
|
3
|
+
`],[" "," "],[":",":"],[";",";"],[".","."],["-","-"],[",",","],["/","/"],["?","?"],["!","!"],["(","("],[")",")"],["[","["],["]","]"],['"','"'],["'","'"],["0","0"],["1","1"],["2","2"],["3","3"],["4","4"],["5","5"],["6","6"],["7","7"],["8","8"],["9","9"]],Y={K:"\u0D9A",KH:"\u0D9B",G:"\u0D9C",GH:"\u0D9D",CH:"\u0DA0",ASPIRATED_CH:"\u0DA1",J:"\u0DA2",RETROFLEX_T:"\u0DA7",RETROFLEX_TH:"\u0DA8",RETROFLEX_TH_SINGLE:"\u0DA8",RETROFLEX_D:"\u0DA9",RETROFLEX_DH:"\u0DAA",RETROFLEX_DH_SINGLE:"\u0DAA",RETROFLEX_N:"\u0DAB",TH:"\u0DAD",ASPIRATED_TH:"\u0DAE",DH:"\u0DAF",ASPIRATED_DH:"\u0DB0",N:"\u0DB1",P:"\u0DB4",PH:"\u0DB5",B_LOWER:"\u0DB6",BH:"\u0DB7",M:"\u0DB8",Y:"\u0DBA",R_CONS:"\u0DBB",L_CONS:"\u0DBD",RETROFLEX_L:"\u0DC5",V_CONS:"\u0DC0",SH:"\u0DC1",RETROFLEX_S:"\u0DC2",S_CONS:"\u0DC3",H_CONS:"\u0DC4",F:"\u0DC6"},pe=new Set(Object.keys(Y)),Ae={SANYAKA_GA:"\u0D9F",SANYAKA_JA:"\u0DA6",SANYAKA_DA:"\u0DAC",SANYAKA_DHA:"\u0DB3",SANYAKA_KA:"\u0DA4",SANYAKA_HA:"\u0DA5",SANYAKA_B:"\u0DB9",SANYAKA_BA:"\u0DB9"},Ne=new Set(Object.keys(Ae)),ne={V_A:"\u0D85",V_AA:"\u0D86",V_AE:"\u0D87",V_AE_LONG:"\u0D88",V_I:"\u0D89",V_II:"\u0D8A",V_U:"\u0D8B",V_UU:"\u0D8C",V_RU:"\u0D8D",V_RU_LONG:"\u0D8E",V_E:"\u0D91",V_EE:"\u0D92",V_AI:"\u0D93",V_O:"\u0D94",V_OO:"\u0D95",V_AU:"\u0D96"},G={V_AA:"\u0DCF",V_AE:"\u0DD0",V_AE_LONG:"\u0DD1",V_I:"\u0DD2",V_II:"\u0DD3",V_U:"\u0DD4",V_UU:"\u0DD6",V_E:"\u0DD9",V_EE:"\u0DDA",V_AI:"\u0DDB",V_O:"\u0DDC",V_OO:"\u0DDD",V_AU:"\u0DDE"},Ce=new Set(Object.keys(ne)),Ee=new Set(Object.keys(G)),ee={ANUSVARA:"\u0D82",MAHAPRANAANUSVARA:"\u0D9E",VISARGA:"\u0D83",SPECIAL_LU:"\u0DC5\u0DD4"},te="N_G";function B(n){return pe.has(n)}function Z(n){return Ne.has(n)}function He(n){return Ce.has(n)}function q(n){return n==="V_A"}function $(n){return Ee.has(n)}function xe(n){return n===void 0?!0:[" ",".",",","!","?",";",":",`
|
|
4
|
+
`," ","-","/","(",")","[","]",'"',"'"].includes(n)}function Ve(n){return n==="Y"||n==="R_CONS"}function Ie(n){let e=[],t=0;for(;t<n.length;){let u=!1;for(let[i,s]of Oe)if(n.substring(t,t+i.length)===i){e.push(s),t+=i.length,u=!0;break}u||(e.push(n[t]),t++)}return e}function ke(n){let e=[],t=0;for(;t<n.length;){let u=n[t],i=n[t+1];if(ee[u]!==void 0){e.push(ee[u]),t++;continue}if(u===te){let s=Y.N,o=Y.G;i!==void 0&&$(i)?(e.push(s+"\u0DCA"),e.push(o),e.push(G[i]),t+=2):i!==void 0&&q(i)?(e.push(s+"\u0DCA"),e.push(o),t+=2):(i!==void 0&&B(i),e.push(s+"\u0DCA"),e.push(o+"\u0DCA"),t++);continue}if(He(u)&&!B(u)){e.push(ne[u]),t++;continue}if(Z(u)){let s=Ae[u];u==="SANYAKA_B"?i!==void 0&&$(i)?(e.push(s),e.push(G[i]),t+=2):i!==void 0&&q(i)?(e.push(s),t+=2):(i!==void 0&&(B(i)||Z(i)),e.push(s+"\u0DCA"),t++):(e.push(s),t++);continue}if(B(u)){let s=Y[u];if(i!==void 0&&Ve(i)){let o=n[t+2],f=Y[i];if(i==="R_CONS"&&o==="V_U"){e.push(s+"\u0DD8"),t+=3;continue}if(i==="R_CONS"&&o==="V_UU"){e.push(s+"\u0DF2"),t+=3;continue}if(o!==void 0&&$(o)){e.push(s+"\u0DCA\u200D"+f),e.push(G[o]),t+=3;continue}else if(o!==void 0&&q(o)){e.push(s+"\u0DCA\u200D"+f),t+=3;continue}else if(o!==void 0&&(B(o)||Z(o)||o===te)){e.push(s+"\u0DCA\u200D"+f+"\u0DCA"),t+=2;continue}else{e.push(s+"\u0DCA\u200D"+f+"\u0DCA"),t+=2;continue}}if(i!==void 0&&$(i)){e.push(s),e.push(G[i]),t+=2;continue}if(i!==void 0&&q(i)){e.push(s),t+=2;continue}if(i!==void 0&&(B(i)||Z(i)||i===te)){e.push(s+"\u0DCA"),t++;continue}if(xe(i)||i===void 0){e.push(s+"\u0DCA"),t++;continue}if(i!==void 0&&ee[i]!==void 0){e.push(s),t++;continue}e.push(s),t++;continue}e.push(u),t++}return e.join("")}function H(n,e){if(!n)return n;let t=Ie(n);return ke(t)}function Me(n,e){if(!n)return n;let t=-1;for(let s=n.length-1;s>=0;s--)if(n[s]===" "||n[s]===`
|
|
5
|
+
`){t=s;break}if(t===-1)return H(n,e);let u=n.substring(0,t+1),i=n.substring(t+1);return i?u+H(i,e):n}function we(n,e){let t=n,u=H(n,e),i=0;for(let s=0;s<Math.min(t.length,u.length);s++)t[s]!==u[s]&&i++;return{text:u,original:t,conversions:i}}function re(n){let e=n.charCodeAt(0);return e>=3456&&e<=3583}function De(n){for(let e of n)if(re(e))return!0;return!1}function Pe(n){let e=[],t="",u=null;for(let i of n){let s=re(i);u===null&&(u=s),s===u?t+=i:(t&&e.push({text:t,isSinhala:u}),t=i,u=s)}return t&&u!==null&&e.push({text:t,isSinhala:u}),e}var Ke=ne,Ue=Ee,Be=pe,Fe={x:"\u0D82",H:"\u0D83"},ze="\u0DCA",We="\u200D";import{useState as oe,useCallback as R,useMemo as be,useRef as F,useLayoutEffect as Ze}from"react";function Se(){return{children:new Map,isTerminal:!1}}var Ye=["zdha","chh","thh","dhh","zga","zja","zda","zqa","zka","zha","aa","Aa","AA","ai","au","ou","ii","uu","ee","oo","Ru","Lu","kh","gh","ch","ph","bh","th","dh","Sh","sh","ng","Th","Dh","Ba","a","A","i","u","U","e","E","o","O","R","k","g","j","t","d","T","D","n","N","p","b","B","m","y","r","l","L","v","w","s","S","h","f","q","x","X","H"],se=Ge(Ye);function Ge(n){let e=Se();for(let t of n){let u=e;for(let i of t){let s=u.children.get(i);s||(s=Se(),u.children.set(i,s)),u=s}u.isTerminal=!0}return e}function me(n){if(n.length===0)return!0;let e=se;for(let t of n){let u=e.children.get(t);if(!u)return!1;e=u}return e.children.size>0}function Xe(n){if(n.length===0)return!0;let e=se;for(let t of n){let u=e.children.get(t);if(!u)return!1;e=u}return!0}function je(n,e){let t=se,u=0;for(let i=e;i<n.length;i++){let s=t.children.get(n[i]);if(!s)break;t=s,t.isTerminal&&(u=i-e+1)}return u}var _e=new Set(["k","kh","g","gh","ch","chh","j","t","Th","d","Dh","T","D","th","thh","dh","dhh","n","N","p","ph","b","bh","B","Ba","m","y","r","l","L","v","w","sh","Sh","S","s","h","f","q","ng","zga","zja","zda","zdha","zqa","zka","zha"]),Je=new Set(["a","aa","A","Aa","AA","i","ii","u","uu","U","e","ee","E","o","oo","O","ai","au","ou","R","Ru"]);function Te(n){if(!n)return{toCommit:"",remaining:""};let e=[],t=0,u=-1;for(;t<n.length;){let S=je(n,t);if(S>0)e.push({start:t,length:S,pattern:n.slice(t,t+S),isPassthrough:!1}),t+=S;else if(Xe(n[t])){u=t;break}else e.push({start:t,length:1,pattern:n[t],isPassthrough:!0}),t+=1}if(e.length===0)return{toCommit:"",remaining:n};if(u>=0){let S=e.length;for(;S>0;){let a=e[S-1];if(!a.isPassthrough&&_e.has(a.pattern)){S--;continue}break}let p=S>0?e[S-1].start+e[S-1].length:0;return p===0?{toCommit:"",remaining:n}:{toCommit:H(n.slice(0,p)),remaining:n.slice(p)}}let i=e.length-1,s=e[i],o=s.start+s.length;if(e.length===1)return s.isPassthrough?{toCommit:s.pattern,remaining:""}:{toCommit:"",remaining:n};let f=i;for(o===n.length&&me(s.pattern)&&(f=i);f>0;){let S=e[f],p=e[f-1];if(!p.isPassthrough&&_e.has(p.pattern)&&!S.isPassthrough&&(Je.has(S.pattern)||me(S.pattern))){f--;continue}break}let m=e[f].start;if(m===0)return{toCommit:"",remaining:n};let k=n.slice(0,m),V=n.slice(m);return{toCommit:H(k),remaining:V}}var P=class{constructor(){de(this,"buffer","")}getBuffer(){return this.buffer}getSpeculativeDisplay(){return this.buffer?H(this.buffer):""}processKey(e){this.buffer+=e;let t=Te(this.buffer);return this.buffer=t.remaining,t}backspace(){return this.buffer.length>0?(this.buffer=this.buffer.slice(0,-1),!0):!1}flush(){if(!this.buffer)return"";let e=H(this.buffer);return this.buffer="",e}hasPending(){return this.buffer.length>0}reset(){this.buffer=""}};function ie(n){return n.length===1&&/[a-zA-Z]/.test(n)}function qe(n){let{enabled:e=!1,onConvert:t,options:u,initialValue:i="",mobileSupport:s=!1}=n||{},[o,f]=oe(i),[m,k]=oe(e),[V,S]=oe(""),p=F(null),a=F(new P),N=F(0),x=F(-1),A=F(null),v=F(null),l=R(()=>{let r=a.current.getBuffer(),h=a.current.getSpeculativeDisplay();N.current=h.length,S(r)},[]),c=R((r,h,E)=>{let O=N.current,C=Math.max(0,h-O),I=r.slice(0,C),g=r.slice(h);return{newValue:I+E+g,newCursor:I.length+E.length}},[]),T=R((r,h)=>{x.current=h,v.current=r,f(r)},[]),M=R(()=>{a.current.reset(),N.current=0,l(),x.current=-1,A.current=null,v.current=null},[l]),w=R((r,h)=>{if(!a.current.hasPending())return{value:h,cursor:r};let E=a.current.flush(),O=c(h,r,E);return l(),{value:O.newValue,cursor:O.newCursor}},[c,l]),Q=R(r=>{M(),f(r)},[M]),L=R(()=>{p.current?.focus()},[]),y=R(()=>{M(),f("")},[M]),z=R(()=>{if(!o)return;let r=o,h=H(r,u);M(),v.current=h,f(h),t&&h!==r&&t(r,h)},[o,u,t,M]),X=R(()=>{if(!a.current.hasPending())return o;let r=p.current?.selectionStart??o.length,h=w(r,o);return T(h.value,h.cursor),h.value},[o,w,T]),K=R(r=>{if(!r&&a.current.hasPending()){let h=p.current?.selectionStart??o.length,E=a.current.flush(),O=c(o,h,E);l(),f(O.newValue)}a.current.reset(),l(),k(r)},[o,c,l]),j=R(()=>{K(!m)},[m,K]),W=R(r=>{p.current=r},[]),ue=R(r=>{if(p.current=r.currentTarget,!m||!s)return;let h=r.nativeEvent;if(h.inputType!=="insertText")return;let E=h.data??"";if(E.length!==1)return;if(A.current===E){r.preventDefault(),A.current=null;return}A.current=null;let O=r.currentTarget,C=O.selectionStart,I=O.selectionEnd,g=C,d=C!==I;if(ie(E)){r.preventDefault();let _=o,b=g;if(d){if(a.current.hasPending()){let ye=a.current.flush();_=c(_,b,ye).newValue,N.current=0}let J=Math.min(C,I),ge=Math.max(C,I);_=_.slice(0,J)+_.slice(ge),b=J,a.current.reset(),N.current=0}let D=a.current.processKey(E),U=c(_,b,D.toCommit+a.current.getSpeculativeDisplay());l(),T(U.newValue,U.newCursor);return}if(a.current.hasPending()){r.preventDefault();let _=a.current.flush(),b=c(o,g,_+E);l(),T(b.newValue,b.newCursor)}},[m,s,o,c,l,T]),le=R(r=>{if(p.current=r.currentTarget,!m)return;let h=r.currentTarget,E=h.selectionStart,O=h.selectionEnd,C=E,I=E!==O;if(ie(r.key)&&!r.ctrlKey&&!r.metaKey&&!r.altKey){r.preventDefault(),A.current=r.key;let g=o,d=C;if(I){if(a.current.hasPending()){let J=a.current.flush();g=c(g,d,J).newValue,N.current=0}let D=Math.min(E,O),U=Math.max(E,O);g=g.slice(0,D)+g.slice(U),d=D,a.current.reset(),N.current=0}let _=a.current.processKey(r.key),b=c(g,d,_.toCommit+a.current.getSpeculativeDisplay());l(),T(b.newValue,b.newCursor);return}if(r.key==="Backspace"&&!r.ctrlKey&&!r.metaKey&&!I&&a.current.hasPending()){r.preventDefault(),a.current.backspace();let g=a.current.getSpeculativeDisplay(),d=c(o,C,g);l(),T(d.newValue,d.newCursor);return}if((r.ctrlKey||r.metaKey)&&r.key==="a"){if(a.current.hasPending()){let g=a.current.flush(),d=c(o,C,g);l(),x.current=-1,f(d.newValue)}return}if((r.ctrlKey||r.metaKey)&&(r.key==="z"||r.key==="y")){a.current.reset(),N.current=0,l(),x.current=-1;return}if((r.ctrlKey||r.metaKey)&&r.key==="Enter"){r.preventDefault();let g=o;if(a.current.reset(),l(),g){let d=H(g,u);T(d,d.length),t&&d!==g&&t(g,d)}return}if(r.key.length===1&&!ie(r.key)&&!r.ctrlKey&&!r.metaKey&&!r.altKey){if(a.current.hasPending()){r.preventDefault(),A.current=r.key;let g=a.current.flush(),d=c(o,C,g+r.key);l(),T(d.newValue,d.newCursor);return}return}if(r.key==="Enter"&&!r.ctrlKey&&!r.metaKey){if(a.current.hasPending()){r.preventDefault();let g=a.current.flush(),d=c(o,C,g+`
|
|
6
|
+
`);l(),T(d.newValue,d.newCursor);return}return}if(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End"].includes(r.key)){if(a.current.hasPending()){let g=a.current.flush(),d=c(o,C,g);l(),T(d.newValue,d.newCursor)}return}if(r.key==="Backspace"||r.key==="Delete"){if(a.current.hasPending()){r.preventDefault();let g=a.current.flush(),d=c(o,C,g);l();let _=d.newValue,b=d.newCursor;if(I){let D=Math.min(E,O),U=Math.max(E,O);_=_.slice(0,D)+_.slice(U),b=D}else r.key==="Backspace"&&b>0?(_=_.slice(0,b-1)+_.slice(b),b=b-1):r.key==="Delete"&&b<_.length&&(_=_.slice(0,b)+_.slice(b+1));T(_,b)}return}},[m,o,u,t,c,l,T]),ae=R(r=>{if(p.current=r.currentTarget,!m){f(r.target.value);return}if(v.current!==null&&r.target.value===v.current){v.current=null;return}v.current=null,a.current.reset(),N.current=0,l(),x.current=-1,f(r.target.value)},[m,l]),ce=R(r=>{if(p.current=r.currentTarget,!!m&&a.current.hasPending()){let h=p.current?.selectionStart??o.length,E=a.current.flush(),O=c(o,h,E);l(),f(O.newValue)}},[m,o,c,l]),he=R(r=>{if(p.current=r.currentTarget,!!m&&a.current.hasPending()){let h=p.current?.selectionStart??o.length,E=w(h,o);T(E.value,E.cursor)}},[m,o,w,T]);Ze(()=>{let r=x.current;r>=0&&p.current&&(p.current.selectionStart=r,p.current.selectionEnd=r),x.current=-1},[o]);let fe=be(()=>({ref:W,value:o,onKeyDown:le,onBeforeInput:ue,onChange:ae,onPaste:ce,onBlur:he}),[W,o,le,ue,ae,ce,he]);return be(()=>({inputProps:fe,value:o,setValue:Q,bufferDisplay:V,enabled:m,toggle:j,setEnabled:K,focus:L,clear:y,convertAll:z,flushPending:X}),[fe,o,Q,V,m,j,K,L,y,z,X])}var $e='input[type="text"], input[type="search"], textarea';function Qe(n={}){let{enabled:e=!0,selector:t=$e,exclude:u,onAttach:i}=n,s=!1,o=null,f=new WeakSet,m=new WeakMap;function k(A){return!(f.has(A)||u&&A.matches(u))}function V(A){if(!k(A))return;let v=new P;m.set(A,v),f.add(A);let l=A instanceof HTMLTextAreaElement,c=A instanceof HTMLInputElement;if(!l&&!c)return;function T(L){if(L.key==="Backspace"){v.backspace()&&(L.preventDefault(),void 0);return}if(L.key==="Enter"||L.key==="Escape"){let y=v.flush();y&&w(y);return}if(L.key.length===1&&!L.ctrlKey&&!L.metaKey&&!L.altKey){L.preventDefault();let y=v.processKey(L.key);y.toCommit&&w(y.toCommit)}}function M(){let L=v.flush();L&&w(L)}function w(L){let y=A,z=y.selectionStart??y.value.length,X=y.selectionEnd??y.value.length,K=y.value.substring(0,z),j=y.value.substring(X);y.value=K+L+j;let W=z+L.length;y.setSelectionRange(W,W),y.dispatchEvent(new Event("input",{bubbles:!0}))}function Q(){}A.addEventListener("keydown",T),A.addEventListener("blur",M),i?.(A)}function S(){document.querySelectorAll(t).forEach(V)}function p(){o=new MutationObserver(A=>{for(let v of A)for(let l of v.addedNodes){if(l.nodeType!==Node.ELEMENT_NODE)continue;let c=l;c.matches(t)&&V(c),c.querySelectorAll(t).forEach(V)}}),o.observe(document.body,{childList:!0,subtree:!0})}function a(){s||(s=!0,S(),p())}function N(){s&&(s=!1,o?.disconnect(),o=null)}function x(){s?N():a()}return e&&a(),{start:a,stop:N,isRunning:()=>s,toggle:x}}var Le="singlish-enabled";function et(n={}){let{position:e="bottom-right",theme:t="auto",showLabel:u=!0,onToggle:i}=n,s=m(),o=null,f=null;function m(){if(typeof localStorage>"u")return!0;let l=localStorage.getItem(Le);return l===null?!0:l==="true"}function k(l){typeof localStorage>"u"||localStorage.setItem(Le,String(l))}function V(){let l=document.createElement("button");return l.className=`singlish-toggle singlish-toggle--${e}`,l.setAttribute("aria-label","Toggle Singlish input"),l.setAttribute("type","button"),S(l),l.addEventListener("click",p),l.addEventListener("keydown",c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),p())}),l}function S(l){let c=s?"\u{1F1F1}\u{1F1F0}":"EN",T=s?"\u0DC3\u0DD2\u0D82":"English";u?l.innerHTML=`<span class="singlish-toggle__icon">${c}</span><span class="singlish-toggle__label">${T}</span>`:l.innerHTML=`<span class="singlish-toggle__icon">${c}</span>`,l.classList.toggle("singlish-toggle--enabled",s),l.setAttribute("aria-pressed",String(s))}function p(){s=!s,k(s),o&&S(o),i?.(s)}function a(l){o||(f=l||document.body,o=V(),f.appendChild(o),v())}function N(){o&&(o.remove(),o=null,f=null)}function x(l){s!==l&&(s=l,k(l),o&&S(o))}function A(){return s}function v(){if(document.getElementById("singlish-toggle-styles"))return;let l=document.createElement("style");l.id="singlish-toggle-styles",l.textContent=tt(t),document.head.appendChild(l)}return{mount:a,unmount:N,setEnabled:x,getEnabled:A}}function tt(n){let e="rgba(255, 255, 255, 0.9)",t="rgba(30, 30, 30, 0.9)",u="#1a1a1a",i="#ffffff",s=n==="dark"?t:e,o=n==="dark"?i:u;return`
|
|
7
|
+
.singlish-toggle {
|
|
8
|
+
position: fixed;
|
|
9
|
+
z-index: 9999;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
gap: 8px;
|
|
13
|
+
padding: 10px 16px;
|
|
14
|
+
background: ${s};
|
|
15
|
+
backdrop-filter: blur(10px);
|
|
16
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
17
|
+
border-radius: 12px;
|
|
18
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
19
|
+
color: ${o};
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
21
|
+
font-size: 14px;
|
|
22
|
+
font-weight: 500;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
transition: all 0.2s ease;
|
|
25
|
+
user-select: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.singlish-toggle:hover {
|
|
29
|
+
transform: translateY(-2px);
|
|
30
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.singlish-toggle:active {
|
|
34
|
+
transform: translateY(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.singlish-toggle:focus {
|
|
38
|
+
outline: 2px solid #4A90E2;
|
|
39
|
+
outline-offset: 2px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.singlish-toggle--top-right {
|
|
43
|
+
top: 20px;
|
|
44
|
+
right: 20px;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.singlish-toggle--top-left {
|
|
48
|
+
top: 20px;
|
|
49
|
+
left: 20px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.singlish-toggle--bottom-right {
|
|
53
|
+
bottom: 20px;
|
|
54
|
+
right: 20px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.singlish-toggle--bottom-left {
|
|
58
|
+
bottom: 20px;
|
|
59
|
+
left: 20px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.singlish-toggle__icon {
|
|
63
|
+
font-size: 18px;
|
|
64
|
+
line-height: 1;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.singlish-toggle__label {
|
|
68
|
+
font-size: 13px;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.singlish-toggle--enabled {
|
|
73
|
+
background: linear-gradient(135deg, rgba(74, 144, 226, 0.9), rgba(106, 90, 205, 0.9));
|
|
74
|
+
color: white;
|
|
75
|
+
border-color: rgba(255, 255, 255, 0.3);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@media (prefers-color-scheme: dark) {
|
|
79
|
+
.singlish-toggle {
|
|
80
|
+
background: ${n==="auto"?t:s};
|
|
81
|
+
color: ${n==="auto"?i:o};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@media (max-width: 768px) {
|
|
86
|
+
.singlish-toggle {
|
|
87
|
+
padding: 8px 12px;
|
|
88
|
+
font-size: 13px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.singlish-toggle__icon {
|
|
92
|
+
font-size: 16px;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
`}export{Be as CONSONANTS,ze as HAL_CHAR,Fe as SPECIAL,P as SinglishIME,Ke as VOWELS,Ue as VOWEL_MODIFIERS_MAP,We as ZWJ_CHAR,De as containsSinhala,Me as convertLastWord,H as convertSinglishToSinhala,we as convertWithMetadata,Qe as createAutoAttach,et as createUIToggle,re as isSinhalaChar,Te as resolveBuffer,Pe as segmentText,qe as useSinglishConverter};
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@siyabasa/singlish",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Deterministic Singlish-to-Sinhala transliteration engine with phonetic precision and zero-latency IME.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"**/*.css"
|
|
8
|
+
],
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"dev": "tsup src/index.ts --format esm,cjs --watch --dts",
|
|
26
|
+
"build": "tsup src/index.ts --format esm,cjs --clean --dts --minify",
|
|
27
|
+
"lint": "eslint src/**/*.ts",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"singlish",
|
|
33
|
+
"sinhala",
|
|
34
|
+
"transliteration",
|
|
35
|
+
"ime",
|
|
36
|
+
"unicode",
|
|
37
|
+
"sri-lanka",
|
|
38
|
+
"i18n",
|
|
39
|
+
"siyabasa",
|
|
40
|
+
"remeinium"
|
|
41
|
+
],
|
|
42
|
+
"author": "Remeinium Siyabasa Labs <support@remeinium.com>",
|
|
43
|
+
"license": "ROSL-1.0",
|
|
44
|
+
"homepage": "https://labs.remeinium.com/siyabasa/singlish",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/remeinium/singlish.git"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/remeinium/singlish/issues"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=16.0.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"react": ">=16.8.0"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"react": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@types/react": "^18.3.28",
|
|
65
|
+
"tsup": "^8.5.1",
|
|
66
|
+
"typescript": "^5.9.3",
|
|
67
|
+
"vitest": "^1.6.1"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public",
|
|
71
|
+
"registry": "https://registry.npmjs.org/"
|
|
72
|
+
}
|
|
73
|
+
}
|