@writegeez/ime 0.0.2 → 0.1.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/dist/index.cjs +93 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -3
- package/dist/index.d.ts +39 -3
- package/dist/index.mjs +90 -30
- package/dist/index.mjs.map +1 -1
- package/dist/input-methods/ti-ER.json +1 -0
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,48 @@ function buildReverseMap(inputMethod2, prefix = "") {
|
|
|
30
30
|
function isLatinChar(char) {
|
|
31
31
|
return char >= "a" && char <= "z" || char >= "A" && char <= "Z";
|
|
32
32
|
}
|
|
33
|
+
function trailingWord(text) {
|
|
34
|
+
return /[^\s\p{P}]*$/u.exec(text)[0];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/transliterator.ts
|
|
38
|
+
var Transliterator = class {
|
|
39
|
+
constructor(spec) {
|
|
40
|
+
this.inputMap = spec.map;
|
|
41
|
+
this.geezToLatinMap = buildReverseMap(this.inputMap);
|
|
42
|
+
}
|
|
43
|
+
feed(prevChar, key) {
|
|
44
|
+
let prevLatinChar = prevChar;
|
|
45
|
+
if (!isLatinChar(prevChar))
|
|
46
|
+
prevLatinChar = this.geezToLatinMap[prevChar] || prevChar;
|
|
47
|
+
let currentNode = null;
|
|
48
|
+
let tempNode = this.inputMap;
|
|
49
|
+
for (const char of prevLatinChar) {
|
|
50
|
+
if (tempNode[char]) {
|
|
51
|
+
currentNode = tempNode[char];
|
|
52
|
+
tempNode = currentNode.next || {};
|
|
53
|
+
} else {
|
|
54
|
+
currentNode = null;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (currentNode?.next && currentNode.next[key])
|
|
59
|
+
return { replace: true, text: currentNode.next[key].value || key };
|
|
60
|
+
const newNode = this.inputMap[key];
|
|
61
|
+
if (newNode) return { replace: false, text: newNode.value || key };
|
|
62
|
+
return { replace: false, text: key };
|
|
63
|
+
}
|
|
64
|
+
/** Run a whole key sequence, e.g. `"selam"` → `"ሰላም"`. */
|
|
65
|
+
transliterate(keys) {
|
|
66
|
+
const out = [];
|
|
67
|
+
for (const key of keys) {
|
|
68
|
+
const { replace, text } = this.feed(out[out.length - 1] ?? "", key);
|
|
69
|
+
if (replace) out.pop();
|
|
70
|
+
out.push(text);
|
|
71
|
+
}
|
|
72
|
+
return out.join("");
|
|
73
|
+
}
|
|
74
|
+
};
|
|
33
75
|
|
|
34
76
|
// src/webGeezIme.ts
|
|
35
77
|
var WebGeezIME = class {
|
|
@@ -46,8 +88,7 @@ var WebGeezIME = class {
|
|
|
46
88
|
this.boundCompositionEnd = () => {
|
|
47
89
|
this.composing = false;
|
|
48
90
|
};
|
|
49
|
-
this.
|
|
50
|
-
this.geezToLatinMap = buildReverseMap(this.inputMap);
|
|
91
|
+
this.transliterator = new Transliterator(inputMethodSpec);
|
|
51
92
|
if (typeof options?.enabled === "boolean")
|
|
52
93
|
this.enabled = options.enabled;
|
|
53
94
|
this.attachToElement(element);
|
|
@@ -103,30 +144,46 @@ var WebGeezIME = class {
|
|
|
103
144
|
);
|
|
104
145
|
}
|
|
105
146
|
processInput(prevChar, newChar) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
147
|
+
const { replace, text } = this.transliterator.feed(prevChar, newChar);
|
|
148
|
+
return { output: text, modifiesPrev: replace };
|
|
149
|
+
}
|
|
150
|
+
/** The word before the caret, e.g. `"ሰላ"` while typing `ሰላም`. */
|
|
151
|
+
currentWord() {
|
|
152
|
+
return trailingWord(this.textBeforeCaret());
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Write `text` at the caret, as if typed. With `replaceWord`, the word
|
|
156
|
+
* before the caret is replaced (accepting a suggestion). Returns false
|
|
157
|
+
* while an OS IME composition is in progress, so it cannot be corrupted.
|
|
158
|
+
*/
|
|
159
|
+
insertText(text, options) {
|
|
160
|
+
if (!this.activeElement || this.composing) return false;
|
|
161
|
+
const length = options?.replaceWord ? this.currentWord().length : 0;
|
|
162
|
+
if (length) this.replaceGeezChar(text, length);
|
|
163
|
+
else this.insertGeezChar(text);
|
|
164
|
+
this.dispatchSyntheticInput(length ? "insertReplacementText" : "insertText");
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
textBeforeCaret() {
|
|
168
|
+
if (!this.activeElement) return "";
|
|
169
|
+
if (this.elementType === "input") {
|
|
170
|
+
const el = this.activeElement;
|
|
171
|
+
return el.value.slice(0, el.selectionStart ?? el.value.length);
|
|
119
172
|
}
|
|
120
|
-
if (
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
173
|
+
if (!this.isContentEditable) return "";
|
|
174
|
+
this.activeElement.normalize();
|
|
175
|
+
const sel = window.getSelection();
|
|
176
|
+
if (!sel) return "";
|
|
177
|
+
if (!sel.rangeCount || !this.activeElement.contains(sel.getRangeAt(0).startContainer)) {
|
|
178
|
+
const range2 = document.createRange();
|
|
179
|
+
range2.selectNodeContents(this.activeElement);
|
|
180
|
+
range2.collapse(false);
|
|
181
|
+
sel.removeAllRanges();
|
|
182
|
+
sel.addRange(range2);
|
|
125
183
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return { output: newChar, modifiesPrev: false };
|
|
184
|
+
const range = sel.getRangeAt(0);
|
|
185
|
+
const { node, offset } = this.resolveTextPosition(range.startContainer, range.startOffset);
|
|
186
|
+
return node ? (node.textContent ?? "").slice(0, offset) : "";
|
|
130
187
|
}
|
|
131
188
|
handleBeforeInput(event) {
|
|
132
189
|
if (!this.activeElement) return;
|
|
@@ -178,12 +235,13 @@ var WebGeezIME = class {
|
|
|
178
235
|
sel.addRange(range);
|
|
179
236
|
}
|
|
180
237
|
}
|
|
181
|
-
|
|
238
|
+
/** Replace `length` UTF-16 units before the caret; defaults to the previous grapheme. */
|
|
239
|
+
replaceGeezChar(char, length) {
|
|
182
240
|
if (!this.activeElement) return;
|
|
183
241
|
if (this.elementType === "input") {
|
|
184
242
|
const target = this.activeElement;
|
|
185
243
|
const caret = target.selectionStart ?? 0;
|
|
186
|
-
const start = this.findPrevGraphemeStart(target.value, caret);
|
|
244
|
+
const start = length === void 0 ? this.findPrevGraphemeStart(target.value, caret) : Math.max(0, caret - length);
|
|
187
245
|
target.setRangeText(char, start, caret, "end");
|
|
188
246
|
} else if (this.isContentEditable) {
|
|
189
247
|
const sel = window.getSelection();
|
|
@@ -195,7 +253,7 @@ var WebGeezIME = class {
|
|
|
195
253
|
);
|
|
196
254
|
if (node) {
|
|
197
255
|
const text = node.textContent ?? "";
|
|
198
|
-
const start = this.findPrevGraphemeStart(text, offset);
|
|
256
|
+
const start = length === void 0 ? this.findPrevGraphemeStart(text, offset) : Math.max(0, offset - length);
|
|
199
257
|
const r = document.createRange();
|
|
200
258
|
r.setStart(node, start);
|
|
201
259
|
r.setEnd(node, offset);
|
|
@@ -2217,14 +2275,20 @@ var inputMethod = {
|
|
|
2217
2275
|
var ti_ER_default = inputMethod;
|
|
2218
2276
|
|
|
2219
2277
|
// src/input-methods/index.ts
|
|
2220
|
-
var inputMethods =
|
|
2221
|
-
|
|
2278
|
+
var inputMethods = [ti_ER_default];
|
|
2279
|
+
function getInputMethod(code) {
|
|
2280
|
+
return inputMethods.find((method) => method.code === code);
|
|
2281
|
+
}
|
|
2222
2282
|
|
|
2223
2283
|
// src/index.ts
|
|
2224
2284
|
var ime = webGeezIme_exports;
|
|
2225
2285
|
|
|
2226
2286
|
exports.GeezIME = WebGeezIME;
|
|
2227
2287
|
exports.TigrinyaEritrean = ti_ER_default;
|
|
2288
|
+
exports.Transliterator = Transliterator;
|
|
2289
|
+
exports.getInputMethod = getInputMethod;
|
|
2228
2290
|
exports.ime = ime;
|
|
2291
|
+
exports.inputMethods = inputMethods;
|
|
2292
|
+
exports.trailingWord = trailingWord;
|
|
2229
2293
|
//# sourceMappingURL=index.cjs.map
|
|
2230
2294
|
//# sourceMappingURL=index.cjs.map
|