@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.d.cts
CHANGED
|
@@ -10,8 +10,7 @@ type InputMethodSpec = {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
declare class WebGeezIME {
|
|
13
|
-
private
|
|
14
|
-
private geezToLatinMap;
|
|
13
|
+
private transliterator;
|
|
15
14
|
private activeElement;
|
|
16
15
|
private elementType;
|
|
17
16
|
private isContentEditable;
|
|
@@ -32,8 +31,20 @@ declare class WebGeezIME {
|
|
|
32
31
|
output: string;
|
|
33
32
|
modifiesPrev: boolean;
|
|
34
33
|
};
|
|
34
|
+
/** The word before the caret, e.g. `"ሰላ"` while typing `ሰላም`. */
|
|
35
|
+
currentWord(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Write `text` at the caret, as if typed. With `replaceWord`, the word
|
|
38
|
+
* before the caret is replaced (accepting a suggestion). Returns false
|
|
39
|
+
* while an OS IME composition is in progress, so it cannot be corrupted.
|
|
40
|
+
*/
|
|
41
|
+
insertText(text: string, options?: {
|
|
42
|
+
replaceWord?: boolean;
|
|
43
|
+
}): boolean;
|
|
44
|
+
private textBeforeCaret;
|
|
35
45
|
private handleBeforeInput;
|
|
36
46
|
private insertGeezChar;
|
|
47
|
+
/** Replace `length` UTF-16 units before the caret; defaults to the previous grapheme. */
|
|
37
48
|
private replaceGeezChar;
|
|
38
49
|
private dispatchSyntheticInput;
|
|
39
50
|
private getPreviousCharByTargetRanges;
|
|
@@ -50,6 +61,31 @@ declare namespace core {
|
|
|
50
61
|
|
|
51
62
|
declare const inputMethod: InputMethodSpec;
|
|
52
63
|
|
|
64
|
+
/** Every input method bundled with the package, in menu order. */
|
|
65
|
+
declare const inputMethods: InputMethodSpec[];
|
|
66
|
+
/** Look one up by its `code`, e.g. `"ti-ER"`. */
|
|
67
|
+
declare function getInputMethod(code: string): InputMethodSpec | undefined;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* DOM-free transliteration engine. Feed it the character before the caret
|
|
71
|
+
* and the key just typed; it says what to write and whether that replaces
|
|
72
|
+
* the previous character.
|
|
73
|
+
*/
|
|
74
|
+
declare class Transliterator {
|
|
75
|
+
private inputMap;
|
|
76
|
+
private geezToLatinMap;
|
|
77
|
+
constructor(spec: InputMethodSpec);
|
|
78
|
+
feed(prevChar: string, key: string): {
|
|
79
|
+
replace: boolean;
|
|
80
|
+
text: string;
|
|
81
|
+
};
|
|
82
|
+
/** Run a whole key sequence, e.g. `"selam"` → `"ሰላም"`. */
|
|
83
|
+
transliterate(keys: string): string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The word at the end of `text`: everything after the last space or punctuation mark. */
|
|
87
|
+
declare function trailingWord(text: string): string;
|
|
88
|
+
|
|
53
89
|
declare const ime: typeof core;
|
|
54
90
|
|
|
55
|
-
export { WebGeezIME as GeezIME, type InputMethod, type InputMethodSpec, type SymbolMap, inputMethod as TigrinyaEritrean, ime };
|
|
91
|
+
export { WebGeezIME as GeezIME, type InputMethod, type InputMethodSpec, type SymbolMap, inputMethod as TigrinyaEritrean, Transliterator, getInputMethod, ime, inputMethods, trailingWord };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,8 +10,7 @@ type InputMethodSpec = {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
declare class WebGeezIME {
|
|
13
|
-
private
|
|
14
|
-
private geezToLatinMap;
|
|
13
|
+
private transliterator;
|
|
15
14
|
private activeElement;
|
|
16
15
|
private elementType;
|
|
17
16
|
private isContentEditable;
|
|
@@ -32,8 +31,20 @@ declare class WebGeezIME {
|
|
|
32
31
|
output: string;
|
|
33
32
|
modifiesPrev: boolean;
|
|
34
33
|
};
|
|
34
|
+
/** The word before the caret, e.g. `"ሰላ"` while typing `ሰላም`. */
|
|
35
|
+
currentWord(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Write `text` at the caret, as if typed. With `replaceWord`, the word
|
|
38
|
+
* before the caret is replaced (accepting a suggestion). Returns false
|
|
39
|
+
* while an OS IME composition is in progress, so it cannot be corrupted.
|
|
40
|
+
*/
|
|
41
|
+
insertText(text: string, options?: {
|
|
42
|
+
replaceWord?: boolean;
|
|
43
|
+
}): boolean;
|
|
44
|
+
private textBeforeCaret;
|
|
35
45
|
private handleBeforeInput;
|
|
36
46
|
private insertGeezChar;
|
|
47
|
+
/** Replace `length` UTF-16 units before the caret; defaults to the previous grapheme. */
|
|
37
48
|
private replaceGeezChar;
|
|
38
49
|
private dispatchSyntheticInput;
|
|
39
50
|
private getPreviousCharByTargetRanges;
|
|
@@ -50,6 +61,31 @@ declare namespace core {
|
|
|
50
61
|
|
|
51
62
|
declare const inputMethod: InputMethodSpec;
|
|
52
63
|
|
|
64
|
+
/** Every input method bundled with the package, in menu order. */
|
|
65
|
+
declare const inputMethods: InputMethodSpec[];
|
|
66
|
+
/** Look one up by its `code`, e.g. `"ti-ER"`. */
|
|
67
|
+
declare function getInputMethod(code: string): InputMethodSpec | undefined;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* DOM-free transliteration engine. Feed it the character before the caret
|
|
71
|
+
* and the key just typed; it says what to write and whether that replaces
|
|
72
|
+
* the previous character.
|
|
73
|
+
*/
|
|
74
|
+
declare class Transliterator {
|
|
75
|
+
private inputMap;
|
|
76
|
+
private geezToLatinMap;
|
|
77
|
+
constructor(spec: InputMethodSpec);
|
|
78
|
+
feed(prevChar: string, key: string): {
|
|
79
|
+
replace: boolean;
|
|
80
|
+
text: string;
|
|
81
|
+
};
|
|
82
|
+
/** Run a whole key sequence, e.g. `"selam"` → `"ሰላም"`. */
|
|
83
|
+
transliterate(keys: string): string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The word at the end of `text`: everything after the last space or punctuation mark. */
|
|
87
|
+
declare function trailingWord(text: string): string;
|
|
88
|
+
|
|
53
89
|
declare const ime: typeof core;
|
|
54
90
|
|
|
55
|
-
export { WebGeezIME as GeezIME, type InputMethod, type InputMethodSpec, type SymbolMap, inputMethod as TigrinyaEritrean, ime };
|
|
91
|
+
export { WebGeezIME as GeezIME, type InputMethod, type InputMethodSpec, type SymbolMap, inputMethod as TigrinyaEritrean, Transliterator, getInputMethod, ime, inputMethods, trailingWord };
|
package/dist/index.mjs
CHANGED
|
@@ -28,6 +28,48 @@ function buildReverseMap(inputMethod2, prefix = "") {
|
|
|
28
28
|
function isLatinChar(char) {
|
|
29
29
|
return char >= "a" && char <= "z" || char >= "A" && char <= "Z";
|
|
30
30
|
}
|
|
31
|
+
function trailingWord(text) {
|
|
32
|
+
return /[^\s\p{P}]*$/u.exec(text)[0];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/transliterator.ts
|
|
36
|
+
var Transliterator = class {
|
|
37
|
+
constructor(spec) {
|
|
38
|
+
this.inputMap = spec.map;
|
|
39
|
+
this.geezToLatinMap = buildReverseMap(this.inputMap);
|
|
40
|
+
}
|
|
41
|
+
feed(prevChar, key) {
|
|
42
|
+
let prevLatinChar = prevChar;
|
|
43
|
+
if (!isLatinChar(prevChar))
|
|
44
|
+
prevLatinChar = this.geezToLatinMap[prevChar] || prevChar;
|
|
45
|
+
let currentNode = null;
|
|
46
|
+
let tempNode = this.inputMap;
|
|
47
|
+
for (const char of prevLatinChar) {
|
|
48
|
+
if (tempNode[char]) {
|
|
49
|
+
currentNode = tempNode[char];
|
|
50
|
+
tempNode = currentNode.next || {};
|
|
51
|
+
} else {
|
|
52
|
+
currentNode = null;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (currentNode?.next && currentNode.next[key])
|
|
57
|
+
return { replace: true, text: currentNode.next[key].value || key };
|
|
58
|
+
const newNode = this.inputMap[key];
|
|
59
|
+
if (newNode) return { replace: false, text: newNode.value || key };
|
|
60
|
+
return { replace: false, text: key };
|
|
61
|
+
}
|
|
62
|
+
/** Run a whole key sequence, e.g. `"selam"` → `"ሰላም"`. */
|
|
63
|
+
transliterate(keys) {
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const key of keys) {
|
|
66
|
+
const { replace, text } = this.feed(out[out.length - 1] ?? "", key);
|
|
67
|
+
if (replace) out.pop();
|
|
68
|
+
out.push(text);
|
|
69
|
+
}
|
|
70
|
+
return out.join("");
|
|
71
|
+
}
|
|
72
|
+
};
|
|
31
73
|
|
|
32
74
|
// src/webGeezIme.ts
|
|
33
75
|
var WebGeezIME = class {
|
|
@@ -44,8 +86,7 @@ var WebGeezIME = class {
|
|
|
44
86
|
this.boundCompositionEnd = () => {
|
|
45
87
|
this.composing = false;
|
|
46
88
|
};
|
|
47
|
-
this.
|
|
48
|
-
this.geezToLatinMap = buildReverseMap(this.inputMap);
|
|
89
|
+
this.transliterator = new Transliterator(inputMethodSpec);
|
|
49
90
|
if (typeof options?.enabled === "boolean")
|
|
50
91
|
this.enabled = options.enabled;
|
|
51
92
|
this.attachToElement(element);
|
|
@@ -101,30 +142,46 @@ var WebGeezIME = class {
|
|
|
101
142
|
);
|
|
102
143
|
}
|
|
103
144
|
processInput(prevChar, newChar) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
145
|
+
const { replace, text } = this.transliterator.feed(prevChar, newChar);
|
|
146
|
+
return { output: text, modifiesPrev: replace };
|
|
147
|
+
}
|
|
148
|
+
/** The word before the caret, e.g. `"ሰላ"` while typing `ሰላም`. */
|
|
149
|
+
currentWord() {
|
|
150
|
+
return trailingWord(this.textBeforeCaret());
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Write `text` at the caret, as if typed. With `replaceWord`, the word
|
|
154
|
+
* before the caret is replaced (accepting a suggestion). Returns false
|
|
155
|
+
* while an OS IME composition is in progress, so it cannot be corrupted.
|
|
156
|
+
*/
|
|
157
|
+
insertText(text, options) {
|
|
158
|
+
if (!this.activeElement || this.composing) return false;
|
|
159
|
+
const length = options?.replaceWord ? this.currentWord().length : 0;
|
|
160
|
+
if (length) this.replaceGeezChar(text, length);
|
|
161
|
+
else this.insertGeezChar(text);
|
|
162
|
+
this.dispatchSyntheticInput(length ? "insertReplacementText" : "insertText");
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
textBeforeCaret() {
|
|
166
|
+
if (!this.activeElement) return "";
|
|
167
|
+
if (this.elementType === "input") {
|
|
168
|
+
const el = this.activeElement;
|
|
169
|
+
return el.value.slice(0, el.selectionStart ?? el.value.length);
|
|
117
170
|
}
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
171
|
+
if (!this.isContentEditable) return "";
|
|
172
|
+
this.activeElement.normalize();
|
|
173
|
+
const sel = window.getSelection();
|
|
174
|
+
if (!sel) return "";
|
|
175
|
+
if (!sel.rangeCount || !this.activeElement.contains(sel.getRangeAt(0).startContainer)) {
|
|
176
|
+
const range2 = document.createRange();
|
|
177
|
+
range2.selectNodeContents(this.activeElement);
|
|
178
|
+
range2.collapse(false);
|
|
179
|
+
sel.removeAllRanges();
|
|
180
|
+
sel.addRange(range2);
|
|
123
181
|
}
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return { output: newChar, modifiesPrev: false };
|
|
182
|
+
const range = sel.getRangeAt(0);
|
|
183
|
+
const { node, offset } = this.resolveTextPosition(range.startContainer, range.startOffset);
|
|
184
|
+
return node ? (node.textContent ?? "").slice(0, offset) : "";
|
|
128
185
|
}
|
|
129
186
|
handleBeforeInput(event) {
|
|
130
187
|
if (!this.activeElement) return;
|
|
@@ -176,12 +233,13 @@ var WebGeezIME = class {
|
|
|
176
233
|
sel.addRange(range);
|
|
177
234
|
}
|
|
178
235
|
}
|
|
179
|
-
|
|
236
|
+
/** Replace `length` UTF-16 units before the caret; defaults to the previous grapheme. */
|
|
237
|
+
replaceGeezChar(char, length) {
|
|
180
238
|
if (!this.activeElement) return;
|
|
181
239
|
if (this.elementType === "input") {
|
|
182
240
|
const target = this.activeElement;
|
|
183
241
|
const caret = target.selectionStart ?? 0;
|
|
184
|
-
const start = this.findPrevGraphemeStart(target.value, caret);
|
|
242
|
+
const start = length === void 0 ? this.findPrevGraphemeStart(target.value, caret) : Math.max(0, caret - length);
|
|
185
243
|
target.setRangeText(char, start, caret, "end");
|
|
186
244
|
} else if (this.isContentEditable) {
|
|
187
245
|
const sel = window.getSelection();
|
|
@@ -193,7 +251,7 @@ var WebGeezIME = class {
|
|
|
193
251
|
);
|
|
194
252
|
if (node) {
|
|
195
253
|
const text = node.textContent ?? "";
|
|
196
|
-
const start = this.findPrevGraphemeStart(text, offset);
|
|
254
|
+
const start = length === void 0 ? this.findPrevGraphemeStart(text, offset) : Math.max(0, offset - length);
|
|
197
255
|
const r = document.createRange();
|
|
198
256
|
r.setStart(node, start);
|
|
199
257
|
r.setEnd(node, offset);
|
|
@@ -2215,12 +2273,14 @@ var inputMethod = {
|
|
|
2215
2273
|
var ti_ER_default = inputMethod;
|
|
2216
2274
|
|
|
2217
2275
|
// src/input-methods/index.ts
|
|
2218
|
-
var inputMethods =
|
|
2219
|
-
|
|
2276
|
+
var inputMethods = [ti_ER_default];
|
|
2277
|
+
function getInputMethod(code) {
|
|
2278
|
+
return inputMethods.find((method) => method.code === code);
|
|
2279
|
+
}
|
|
2220
2280
|
|
|
2221
2281
|
// src/index.ts
|
|
2222
2282
|
var ime = webGeezIme_exports;
|
|
2223
2283
|
|
|
2224
|
-
export { WebGeezIME as GeezIME, ti_ER_default as TigrinyaEritrean, ime };
|
|
2284
|
+
export { WebGeezIME as GeezIME, ti_ER_default as TigrinyaEritrean, Transliterator, getInputMethod, ime, inputMethods, trailingWord };
|
|
2225
2285
|
//# sourceMappingURL=index.mjs.map
|
|
2226
2286
|
//# sourceMappingURL=index.mjs.map
|