geez-input 1.0.7 → 1.0.8

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/README.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  A type-safe React library for Geez (Ethiopic) script input with phonetic keyboard support. Write Amharic, Tigrinya, and other Ethiopic languages using Latin characters that automatically transform to Geez script.
4
4
 
5
+ ## About Geez Script
6
+
7
+ Geez script (ግዕዝ), also known as Ethiopic script, is an ancient writing system used for [Amharic](https://en.wikipedia.org/wiki/Amharic) and other Ethiopian Semitic languages. It's an alphasyllabary where each character represents a consonant-vowel combination. This library makes it easy to type Geez script using familiar Latin characters with phonetic mappings, supporting labialized forms (wa-series) and all standard syllable transformations.
8
+
9
+ **📖 Learn more about Amharic and its writing system:** [Wikipedia - Amharic](https://en.wikipedia.org/wiki/Amharic)
10
+
5
11
  ## Features
6
12
 
7
13
  - **Fully Type-Safe**: Built with TypeScript for complete IntelliSense support and autocomplete
@@ -91,12 +97,8 @@ function MyForm() {
91
97
  A styled input component with built-in Geez phonetic keyboard support.
92
98
 
93
99
  **Props:**
94
- - All standard HTML input attributes (`type`, `placeholder`, `value`, `onChange`, `onFocus`, `onBlur`, `required`, `disabled`, `readOnly`, `maxLength`, `minLength`, `pattern`, `autoComplete`, `autoFocus`, `name`, `id`, `aria-*`, etc.)
95
- - `defaultGeez?: boolean` - Enable Geez mode by default (default: `true`)
96
- - `className?: string` - CSS classes for the input field
97
- - `wrapperClassName?: string` - CSS classes for the wrapper div
98
- - `inputClassName?: string` - Additional CSS classes for the input field
99
- - `buttonClassName?: string` - CSS classes for the toggle button
100
+ - All standard HTML input attributes (`type`, `placeholder`, `value`, `onChange`, `onFocus`, `onBlur`, `required`, `disabled`, `readOnly`, `maxLength`, `minLength`, `pattern`, `autoComplete`, `autoFocus`, `name`, `id`, `aria-*`, `className`, etc.)
101
+ - `mode?: "geez" | "latin"` - Input mode: "geez" for phonetic transformation, "latin" for standard input (default: `"geez"`)
100
102
 
101
103
  ```tsx
102
104
  import { GeezInput } from 'geez-input'
@@ -123,12 +125,8 @@ function MyForm() {
123
125
  A styled textarea component for longer text input.
124
126
 
125
127
  **Props:**
126
- - All standard HTML textarea attributes (`rows`, `cols`, `placeholder`, `value`, `onChange`, `onFocus`, `onBlur`, `required`, `disabled`, `readOnly`, `maxLength`, `minLength`, `wrap`, `spellCheck`, `name`, `id`, `aria-*`, etc.)
127
- - `defaultGeez?: boolean` - Enable Geez mode by default (default: `true`)
128
- - `className?: string` - CSS classes for the textarea field
129
- - `wrapperClassName?: string` - CSS classes for the wrapper div
130
- - `textareaClassName?: string` - Additional CSS classes for the textarea field
131
- - `buttonClassName?: string` - CSS classes for the toggle button
128
+ - All standard HTML textarea attributes (`rows`, `cols`, `placeholder`, `value`, `onChange`, `onFocus`, `onBlur`, `required`, `disabled`, `readOnly`, `maxLength`, `minLength`, `wrap`, `spellCheck`, `name`, `id`, `aria-*`, `className`, etc.)
129
+ - `mode?: "geez" | "latin"` - Input mode: "geez" for phonetic transformation, "latin" for standard input (default: `"geez"`)
132
130
 
133
131
  ```tsx
134
132
  import { GeezTextArea } from 'geez-input'
@@ -188,22 +186,14 @@ Type phonetically to get Geez text:
188
186
  #### GeezInput
189
187
 
190
188
  Props:
191
- - `defaultGeez?: boolean` - Enable Geez mode by default (default: `true`)
192
- - `className?: string` - Additional CSS classes for the input field
193
- - `wrapperClassName?: string` - Additional CSS classes for the wrapper
194
- - `inputClassName?: string` - Additional CSS classes for the input field
195
- - `buttonClassName?: string` - Additional CSS classes for the toggle button
196
- - `...InputHTMLAttributes` - All standard HTML input attributes with full TypeScript support
189
+ - `mode?: "geez" | "latin"` - Input mode: "geez" for phonetic transformation, "latin" for standard input (default: `"geez"`)
190
+ - `...InputHTMLAttributes` - All standard HTML input attributes (including `className`) with full TypeScript support
197
191
 
198
192
  #### GeezTextArea
199
193
 
200
194
  Props:
201
- - `defaultGeez?: boolean` - Enable Geez mode by default (default: `true`)
202
- - `className?: string` - Additional CSS classes for the textarea field
203
- - `wrapperClassName?: string` - Additional CSS classes for the wrapper
204
- - `textareaClassName?: string` - Additional CSS classes for the textarea field
205
- - `buttonClassName?: string` - Additional CSS classes for the toggle button
206
- - `...TextareaHTMLAttributes` - All standard HTML textarea attributes with full TypeScript support
195
+ - `mode?: "geez" | "latin"` - Input mode: "geez" for phonetic transformation, "latin" for standard input (default: `"geez"`)
196
+ - `...TextareaHTMLAttributes` - All standard HTML textarea attributes (including `className`) with full TypeScript support
207
197
 
208
198
  ### Type Exports
209
199
 
@@ -238,9 +228,19 @@ The library is written in TypeScript and provides comprehensive type definitions
238
228
  - React 18 or 19
239
229
  - TypeScript 5+ (optional)
240
230
 
231
+ ## Issues & Support
232
+
233
+ We welcome your feedback and contributions!
234
+
235
+ - **Found a bug?** [Open an issue](https://github.com/tewodrosbirhanu/geez-input/issues)
236
+ - **Have a feature request?** [Create an issue](https://github.com/tewodrosbirhanu/geez-input/issues) and let's discuss it
237
+ - **Questions or suggestions?** Feel free to [start a discussion](https://github.com/tewodrosbirhanu/geez-input/issues)
238
+
239
+ This repository is actively maintained and **open for issues**. We appreciate all contributions, bug reports, and feature requests from the community!
240
+
241
241
  ## Contributing
242
242
 
243
- Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.
243
+ Contributions are welcome! Whether you're fixing bugs, adding features, improving documentation, or adding test coverage, we'd love your help. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to get started.
244
244
 
245
245
  ## License
246
246
 
@@ -3,36 +3,21 @@ import { default as React } from 'react';
3
3
  * Props for the GeezInput component
4
4
  * Extends all standard HTML input attributes
5
5
  */
6
- export interface GeezInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'className'> {
6
+ export interface GeezInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
7
7
  /**
8
- * Whether Geez input mode is enabled by default
9
- * @default true
8
+ * Input mode: "geez" for phonetic transformation, "latin" for standard input
9
+ * @default "geez"
10
10
  */
11
- defaultGeez?: boolean;
12
- /**
13
- * Additional CSS classes to apply to the input wrapper
14
- */
15
- wrapperClassName?: string;
16
- /**
17
- * Additional CSS classes to apply to the input field
18
- * This is combined with the className prop for backward compatibility
19
- */
20
- inputClassName?: string;
21
- /**
22
- * Additional CSS classes to apply to the input field
23
- * This is an alias for inputClassName for consistency with standard HTML inputs
24
- */
25
- className?: string;
11
+ mode?: "geez" | "latin";
26
12
  }
27
13
  /**
28
14
  * Input component with built-in Geez phonetic keyboard support
29
15
  *
30
16
  * Features:
31
- * - Press Cmd+Shift+S (or Ctrl+Shift+S) to toggle between Geez and English input modes
32
17
  * - Phonetic transformation (type 'hello' → 'ሀልሎ')
33
18
  * - Full support for controlled and uncontrolled component patterns
34
19
  * - Forward ref support for form libraries
35
- * - Supports any CSS framework via className props
20
+ * - Supports any CSS framework via standard className prop
36
21
  *
37
22
  * @example
38
23
  * \`\`\`tsx
@@ -3,36 +3,21 @@ import { default as React } from 'react';
3
3
  * Props for the GeezTextArea component
4
4
  * Extends all standard HTML textarea attributes
5
5
  */
6
- export interface GeezTextAreaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'className'> {
6
+ export interface GeezTextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
7
7
  /**
8
- * Whether Geez input mode is enabled by default
9
- * @default true
8
+ * Input mode: "geez" for phonetic transformation, "latin" for standard input
9
+ * @default "geez"
10
10
  */
11
- defaultGeez?: boolean;
12
- /**
13
- * Additional CSS classes to apply to the textarea wrapper
14
- */
15
- wrapperClassName?: string;
16
- /**
17
- * Additional CSS classes to apply to the textarea field
18
- * This is combined with the className prop for backward compatibility
19
- */
20
- textareaClassName?: string;
21
- /**
22
- * Additional CSS classes to apply to the textarea field
23
- * This is an alias for textareaClassName for consistency with standard HTML textareas
24
- */
25
- className?: string;
11
+ mode?: "geez" | "latin";
26
12
  }
27
13
  /**
28
14
  * Textarea component with built-in Geez phonetic keyboard support
29
15
  *
30
16
  * Features:
31
- * - Press Cmd+Shift+S (or Ctrl+Shift+S) to toggle between Geez and English input modes
32
17
  * - Phonetic transformation for longer text
33
18
  * - Full support for controlled and uncontrolled component patterns
34
19
  * - Forward ref support for form libraries
35
- * - Supports any CSS framework via className props
20
+ * - Supports any CSS framework via standard className prop
36
21
  *
37
22
  * @example
38
23
  * \`\`\`tsx
@@ -57,8 +42,8 @@ export interface GeezTextAreaProps extends Omit<React.TextareaHTMLAttributes<HTM
57
42
  *
58
43
  * @example
59
44
  * \`\`\`tsx
60
- * // Start with English mode
61
- * <GeezTextArea defaultGeez={false} placeholder="Type here..." />
45
+ * // Start with Latin mode
46
+ * <GeezTextArea mode="latin" placeholder="Type here..." />
62
47
  * \`\`\`
63
48
  */
64
49
  export declare const GeezTextArea: React.ForwardRefExoticComponent<GeezTextAreaProps & React.RefAttributes<HTMLTextAreaElement>>;
package/dist/engine.d.ts CHANGED
@@ -64,4 +64,22 @@ export declare class GeezEngine {
64
64
  * \`\`\`
65
65
  */
66
66
  private static findSadisBase;
67
+ /**
68
+ * Find the base consonant for a wa-series character
69
+ *
70
+ * This checks if a character is a "we" form (e.g., ኰ, ቈ, ጐ, ኈ)
71
+ * and returns its base consonant if it is.
72
+ *
73
+ * @param char - The character to check
74
+ * @returns The base consonant character, or null if not a we form
75
+ * @private
76
+ *
77
+ * @example
78
+ * \`\`\`ts
79
+ * GeezEngine.findCharBeforeWaSeries('ኰ') // returns 'ክ'
80
+ * GeezEngine.findCharBeforeWaSeries('ቈ') // returns 'ቅ'
81
+ * GeezEngine.findCharBeforeWaSeries('ላ') // returns null
82
+ * \`\`\`
83
+ */
84
+ private static findCharBeforeWaSeries;
67
85
  }
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
- import { jsx as y } from "react/jsx-runtime";
2
- import { useCallback as z, forwardRef as v, useState as D } from "react";
3
- const p = {
1
+ import { jsx as b } from "react/jsx-runtime";
2
+ import { useCallback as v, forwardRef as S } from "react";
3
+ const f = {
4
4
  h: "ህ",
5
5
  l: "ል",
6
6
  m: "ም",
@@ -40,7 +40,7 @@ const p = {
40
40
  A: "ኣ",
41
41
  E: "ኤ",
42
42
  O: "ዖ"
43
- }, b = {
43
+ }, r = {
44
44
  አ: {
45
45
  e: "አ",
46
46
  u: "ኡ",
@@ -60,9 +60,11 @@ const p = {
60
60
  ee: "ሄ",
61
61
  o: "ሆ",
62
62
  ua: "ኋ",
63
- wa: "",
63
+ wa: "",
64
64
  wi: "ኊ",
65
- we: "",
65
+ we: "",
66
+ wee: "ኌ",
67
+ wu: "ኍ",
66
68
  wei: "ኍ"
67
69
  },
68
70
  ኃ: {
@@ -80,7 +82,8 @@ const p = {
80
82
  a: "ላ",
81
83
  ee: "ሌ",
82
84
  o: "ሎ",
83
- wa: "ሏ"
85
+ wa: "ሏ",
86
+ ua: "ሏ"
84
87
  },
85
88
  ም: {
86
89
  e: "መ",
@@ -89,7 +92,8 @@ const p = {
89
92
  a: "ማ",
90
93
  ee: "ሜ",
91
94
  o: "ሞ",
92
- ua: "ሟ"
95
+ ua: "ሟ",
96
+ wa: "ሟ"
93
97
  },
94
98
  ር: {
95
99
  e: "ረ",
@@ -98,7 +102,8 @@ const p = {
98
102
  a: "ራ",
99
103
  ee: "ሬ",
100
104
  o: "ሮ",
101
- ua: "ሯ"
105
+ ua: "ሯ",
106
+ wa: "ሯ"
102
107
  },
103
108
  ስ: {
104
109
  e: "ሰ",
@@ -107,7 +112,8 @@ const p = {
107
112
  a: "ሳ",
108
113
  ee: "ሴ",
109
114
  o: "ሶ",
110
- ua: "ሷ"
115
+ ua: "ሷ",
116
+ wa: "ሷ"
111
117
  },
112
118
  ሽ: {
113
119
  e: "ሸ",
@@ -116,7 +122,8 @@ const p = {
116
122
  a: "ሻ",
117
123
  ee: "ሼ",
118
124
  o: "ሾ",
119
- ua: "ሿ"
125
+ ua: "ሿ",
126
+ wa: "ሿ"
120
127
  },
121
128
  ቅ: {
122
129
  e: "ቀ",
@@ -126,10 +133,12 @@ const p = {
126
133
  ee: "ቄ",
127
134
  o: "ቆ",
128
135
  ua: "ቋ",
129
- wa: "",
136
+ wa: "",
130
137
  wi: "ቊ",
131
138
  waa: "ቋ",
132
- we: "",
139
+ we: "",
140
+ wee: "ቌ",
141
+ wu: "ቍ",
133
142
  wei: "ቍ"
134
143
  },
135
144
  ብ: {
@@ -139,7 +148,8 @@ const p = {
139
148
  a: "ባ",
140
149
  ee: "ቤ",
141
150
  o: "ቦ",
142
- ua: "ቧ"
151
+ ua: "ቧ",
152
+ wa: "ቧ"
143
153
  },
144
154
  ት: {
145
155
  e: "ተ",
@@ -148,7 +158,8 @@ const p = {
148
158
  a: "ታ",
149
159
  ee: "ቴ",
150
160
  o: "ቶ",
151
- ua: "ቷ"
161
+ ua: "ቷ",
162
+ wa: "ቷ"
152
163
  },
153
164
  ች: {
154
165
  e: "ቸ",
@@ -157,7 +168,8 @@ const p = {
157
168
  a: "ቻ",
158
169
  ee: "ቼ",
159
170
  o: "ቾ",
160
- ua: "ቿ"
171
+ ua: "ቿ",
172
+ wa: "ቿ"
161
173
  },
162
174
  ን: {
163
175
  e: "ነ",
@@ -166,7 +178,8 @@ const p = {
166
178
  a: "ና",
167
179
  ee: "ኔ",
168
180
  o: "ኖ",
169
- ua: "ኗ"
181
+ ua: "ኗ",
182
+ wa: "ኗ"
170
183
  },
171
184
  ኝ: {
172
185
  e: "ኘ",
@@ -175,7 +188,8 @@ const p = {
175
188
  a: "ኛ",
176
189
  ee: "ኜ",
177
190
  o: "ኞ",
178
- ua: "ኟ"
191
+ ua: "ኟ",
192
+ wa: "ኟ"
179
193
  },
180
194
  ክ: {
181
195
  e: "ከ",
@@ -185,10 +199,12 @@ const p = {
185
199
  ee: "ኬ",
186
200
  o: "ኮ",
187
201
  ua: "ኳ",
188
- wa: "",
202
+ wa: "",
189
203
  wi: "ኲ",
190
204
  waa: "ኳ",
191
- we: "",
205
+ we: "",
206
+ wee: "ኴ",
207
+ wu: "ኵ",
192
208
  wei: "ኵ"
193
209
  },
194
210
  ው: {
@@ -207,7 +223,8 @@ const p = {
207
223
  a: "ዛ",
208
224
  ee: "ዜ",
209
225
  o: "ዞ",
210
- ua: "ዟ"
226
+ ua: "ዟ",
227
+ wa: "ዟ"
211
228
  },
212
229
  ዥ: {
213
230
  e: "ዠ",
@@ -216,7 +233,8 @@ const p = {
216
233
  a: "ዣ",
217
234
  ee: "ዤ",
218
235
  o: "ዦ",
219
- ua: "ዧ"
236
+ ua: "ዧ",
237
+ wa: "ዧ"
220
238
  },
221
239
  ይ: {
222
240
  e: "የ",
@@ -233,7 +251,8 @@ const p = {
233
251
  a: "ጃ",
234
252
  ee: "ጄ",
235
253
  o: "ጆ",
236
- ua: "ጇ"
254
+ ua: "ጇ",
255
+ wa: "ጇ"
237
256
  },
238
257
  ድ: {
239
258
  e: "ደ",
@@ -242,7 +261,8 @@ const p = {
242
261
  a: "ዳ",
243
262
  ee: "ዴ",
244
263
  o: "ዶ",
245
- ua: "ዷ"
264
+ ua: "ዷ",
265
+ wa: "ዷ"
246
266
  },
247
267
  ግ: {
248
268
  e: "ገ",
@@ -252,10 +272,12 @@ const p = {
252
272
  ee: "ጌ",
253
273
  o: "ጎ",
254
274
  ua: "ጓ",
255
- wa: "",
275
+ wa: "",
256
276
  wi: "ጒ",
257
277
  waa: "ጓ",
258
- we: "",
278
+ we: "",
279
+ wee: "ጔ",
280
+ wu: "ጕ",
259
281
  wei: "ጕ"
260
282
  },
261
283
  ጥ: {
@@ -265,7 +287,8 @@ const p = {
265
287
  a: "ጣ",
266
288
  ee: "ጤ",
267
289
  o: "ጦ",
268
- ua: "ጧ"
290
+ ua: "ጧ",
291
+ wa: "ጧ"
269
292
  },
270
293
  ጭ: {
271
294
  e: "ጨ",
@@ -274,7 +297,8 @@ const p = {
274
297
  a: "ጫ",
275
298
  ee: "ጬ",
276
299
  o: "ጮ",
277
- ua: ""
300
+ ua: "",
301
+ wa: "ጯ"
278
302
  },
279
303
  ጵ: {
280
304
  e: "ጰ",
@@ -283,7 +307,8 @@ const p = {
283
307
  a: "ጳ",
284
308
  ee: "ጴ",
285
309
  o: "ጶ",
286
- ua: ""
310
+ ua: "",
311
+ wa: "ጷ"
287
312
  },
288
313
  ጽ: {
289
314
  e: "ጸ",
@@ -292,7 +317,8 @@ const p = {
292
317
  a: "ጻ",
293
318
  ee: "ጼ",
294
319
  o: "ጾ",
295
- ua: "ጿ"
320
+ ua: "ጿ",
321
+ wa: "ጿ"
296
322
  },
297
323
  ፍ: {
298
324
  e: "ፈ",
@@ -301,7 +327,8 @@ const p = {
301
327
  a: "ፋ",
302
328
  ee: "ፌ",
303
329
  o: "ፎ",
304
- ua: "ፏ"
330
+ ua: "ፏ",
331
+ wa: "ፏ"
305
332
  },
306
333
  ፕ: {
307
334
  e: "ፐ",
@@ -310,7 +337,8 @@ const p = {
310
337
  a: "ፓ",
311
338
  ee: "ፔ",
312
339
  o: "ፖ",
313
- ua: "ፗ"
340
+ ua: "ፗ",
341
+ wa: "ፗ"
314
342
  },
315
343
  ቭ: {
316
344
  e: "ቨ",
@@ -319,15 +347,16 @@ const p = {
319
347
  a: "ቫ",
320
348
  ee: "ቬ",
321
349
  o: "ቮ",
322
- ua: "ቯ"
350
+ ua: "ቯ",
351
+ wa: "ቯ"
323
352
  }
324
- }, K = {
353
+ }, g = {
325
354
  ስh: "ሽ",
326
355
  ችh: "ች",
327
356
  ንy: "ኝ",
328
357
  ዝh: "ዥ",
329
358
  ጽh: "ፁ"
330
- }, g = {
359
+ }, h = {
331
360
  ":": "፡",
332
361
  "፡:": "።",
333
362
  "።:": "፡",
@@ -335,7 +364,7 @@ const p = {
335
364
  "፣,": "፤",
336
365
  ";": "፤"
337
366
  };
338
- class N {
367
+ class E {
339
368
  /**
340
369
  * Transform input text based on a new key press
341
370
  *
@@ -367,72 +396,96 @@ class N {
367
396
  * // → { transformedValue: 'ሽ', newCursorPosition: 1, isReplacement: true }
368
397
  * \`\`\`
369
398
  */
370
- static transform(e, i, t) {
371
- const n = e.slice(-1), o = n + t;
372
- if (g[o])
399
+ static transform(e, n, a) {
400
+ const i = e.slice(-1), l = i + a;
401
+ if (h[l])
373
402
  return {
374
- transformedValue: e.slice(0, -1) + g[o] + i,
403
+ transformedValue: e.slice(0, -1) + h[l] + n,
375
404
  newCursorPosition: e.length,
376
405
  isReplacement: !0
377
406
  };
378
- if (g[t])
407
+ if (h[a])
379
408
  return {
380
- transformedValue: e + g[t] + i,
409
+ transformedValue: e + h[a] + n,
381
410
  newCursorPosition: e.length + 1,
382
411
  isReplacement: !1
383
412
  };
384
- if (K[o])
413
+ if (g[l])
385
414
  return {
386
- transformedValue: e.slice(0, -1) + K[o] + i,
415
+ transformedValue: e.slice(0, -1) + g[l] + n,
387
416
  newCursorPosition: e.length,
388
417
  isReplacement: !0
389
418
  };
390
- if (p[o] && n.length === 1 && /^[a-zA-Z]$/.test(n) && /^[a-zA-Z]$/.test(t))
419
+ if (f[l] && i.length === 1 && /^[a-zA-Z]$/.test(i) && /^[a-zA-Z]$/.test(a))
391
420
  return {
392
- transformedValue: e.slice(0, -1) + p[o] + i,
421
+ transformedValue: e.slice(0, -1) + f[l] + n,
393
422
  newCursorPosition: e.length,
394
423
  isReplacement: !0
395
424
  };
396
- const s = b[n];
397
- if (s && s[t])
425
+ if (i === "ው" && ["a", "i", "e", "u"].includes(a)) {
426
+ const t = e.slice(-2, -1), s = r[t];
427
+ if (s) {
428
+ const c = a === "a" ? "wa" : a === "i" ? "wi" : a === "e" ? "we" : a === "u" ? "wu" : null;
429
+ if (c && s[c])
430
+ return {
431
+ transformedValue: e.slice(0, -2) + s[c] + n,
432
+ newCursorPosition: e.length - 1,
433
+ isReplacement: !0
434
+ };
435
+ }
436
+ }
437
+ if (a === "e") {
438
+ const t = this.findCharBeforeWaSeries(i);
439
+ if (t) {
440
+ const s = r[t];
441
+ if (s && s.wee)
442
+ return {
443
+ transformedValue: e.slice(0, -1) + s.wee + n,
444
+ newCursorPosition: e.length,
445
+ isReplacement: !0
446
+ };
447
+ }
448
+ }
449
+ const o = r[i];
450
+ if (o && o[a])
398
451
  return {
399
- transformedValue: e.slice(0, -1) + s[t] + i,
452
+ transformedValue: e.slice(0, -1) + o[a] + n,
400
453
  newCursorPosition: e.length,
401
454
  isReplacement: !0
402
455
  };
403
- if (t === "e" && n) {
404
- const u = this.findSadisBase(n);
405
- if (u && u !== n) {
406
- const l = b[u];
407
- if (l && l.ee)
456
+ if (a === "e" && i) {
457
+ const t = this.findSadisBase(i);
458
+ if (t && t !== i) {
459
+ const s = r[t];
460
+ if (s && s.ee)
408
461
  return {
409
- transformedValue: e.slice(0, -1) + l.ee + i,
462
+ transformedValue: e.slice(0, -1) + s.ee + n,
410
463
  newCursorPosition: e.length,
411
464
  isReplacement: !0
412
465
  };
413
466
  }
414
467
  }
415
- if (["a", "i"].includes(t)) {
416
- const u = this.findSadisBase(n);
417
- if (u) {
418
- const l = b[u];
419
- if (l) {
420
- const c = t + t, r = l[c];
421
- if (r)
468
+ if (["a", "i"].includes(a)) {
469
+ const t = this.findSadisBase(i);
470
+ if (t) {
471
+ const s = r[t];
472
+ if (s) {
473
+ const c = a + a, u = s[c];
474
+ if (u)
422
475
  return {
423
- transformedValue: e.slice(0, -1) + r + i,
476
+ transformedValue: e.slice(0, -1) + u + n,
424
477
  newCursorPosition: e.length,
425
478
  isReplacement: !0
426
479
  };
427
480
  }
428
481
  }
429
482
  }
430
- return p[t] ? {
431
- transformedValue: e + p[t] + i,
483
+ return f[a] ? {
484
+ transformedValue: e + f[a] + n,
432
485
  newCursorPosition: e.length + 1,
433
486
  isReplacement: !1
434
487
  } : {
435
- transformedValue: e + t + i,
488
+ transformedValue: e + a + n,
436
489
  newCursorPosition: e.length + 1,
437
490
  isReplacement: !1
438
491
  };
@@ -455,15 +508,37 @@ class N {
455
508
  * \`\`\`
456
509
  */
457
510
  static findSadisBase(e) {
458
- for (const [i, t] of Object.entries(b))
459
- if (i === e || Object.values(t).includes(e)) return i;
511
+ for (const [n, a] of Object.entries(r))
512
+ if (n === e || Object.values(a).includes(e)) return n;
513
+ return null;
514
+ }
515
+ /**
516
+ * Find the base consonant for a wa-series character
517
+ *
518
+ * This checks if a character is a "we" form (e.g., ኰ, ቈ, ጐ, ኈ)
519
+ * and returns its base consonant if it is.
520
+ *
521
+ * @param char - The character to check
522
+ * @returns The base consonant character, or null if not a we form
523
+ * @private
524
+ *
525
+ * @example
526
+ * \`\`\`ts
527
+ * GeezEngine.findCharBeforeWaSeries('ኰ') // returns 'ክ'
528
+ * GeezEngine.findCharBeforeWaSeries('ቈ') // returns 'ቅ'
529
+ * GeezEngine.findCharBeforeWaSeries('ላ') // returns null
530
+ * \`\`\`
531
+ */
532
+ static findCharBeforeWaSeries(e) {
533
+ for (const [n, a] of Object.entries(r))
534
+ if (a.we === e) return n;
460
535
  return null;
461
536
  }
462
537
  }
463
- const E = (w = {}) => {
464
- const { enabled: e = !0, onTransform: i } = w;
465
- return { onKeyDown: z(
466
- (n) => {
538
+ const y = (w = {}) => {
539
+ const { enabled: e = !0, onTransform: n } = w;
540
+ return { onKeyDown: v(
541
+ (i) => {
467
542
  if (!e || [
468
543
  "Backspace",
469
544
  "Delete",
@@ -478,78 +553,70 @@ const E = (w = {}) => {
478
553
  "Escape",
479
554
  "PageUp",
480
555
  "PageDown"
481
- ].includes(n.key) || n.ctrlKey || n.metaKey || n.key.length !== 1 || n.altKey) return;
482
- n.preventDefault();
483
- const s = n.currentTarget, { selectionStart: u, selectionEnd: l, value: c } = s, r = c.substring(0, u || 0), m = c.substring(l || 0), d = N.transform(r, m, n.key), h = Object.getOwnPropertyDescriptor(s.constructor.prototype, "value");
484
- h && h.set ? h.set.bind(s)(d.transformedValue) : s.value = d.transformedValue;
485
- let a;
486
- typeof InputEvent < "u" ? a = new InputEvent("input", {
556
+ ].includes(i.key) || i.ctrlKey || i.metaKey || i.key.length !== 1 || i.altKey) return;
557
+ i.preventDefault();
558
+ const o = i.currentTarget, { selectionStart: t, selectionEnd: s, value: c } = o, u = c.substring(0, t || 0), K = c.substring(s || 0), d = E.transform(u, K, i.key), m = Object.getOwnPropertyDescriptor(o.constructor.prototype, "value");
559
+ m && m.set ? m.set.bind(o)(d.transformedValue) : o.value = d.transformedValue;
560
+ let p;
561
+ typeof InputEvent < "u" ? p = new InputEvent("input", {
487
562
  bubbles: !0,
488
563
  cancelable: !0,
489
564
  inputType: "insertText",
490
- data: n.key
491
- }) : a = new Event("input", { bubbles: !0, cancelable: !0 }), s.dispatchEvent(a);
492
- const f = new Event("change", {
565
+ data: i.key
566
+ }) : p = new Event("input", { bubbles: !0, cancelable: !0 }), o.dispatchEvent(p);
567
+ const z = new Event("change", {
493
568
  bubbles: !0,
494
569
  cancelable: !0
495
570
  });
496
- s.dispatchEvent(f), requestAnimationFrame(() => {
497
- if (document.activeElement === s)
571
+ o.dispatchEvent(z), requestAnimationFrame(() => {
572
+ if (document.activeElement === o)
498
573
  try {
499
- s.setSelectionRange(d.newCursorPosition, d.newCursorPosition);
574
+ o.setSelectionRange(d.newCursorPosition, d.newCursorPosition);
500
575
  } catch {
501
576
  }
502
- }), i && i(d);
577
+ }), n && n(d);
503
578
  },
504
- [e, i]
579
+ [e, n]
505
580
  ) };
506
- }, P = v(
507
- ({ defaultGeez: w = !0, wrapperClassName: e, inputClassName: i, className: t, onChange: n, onKeyDown: o, value: s, ...u }, l) => {
508
- const [c, r] = D(w), { onKeyDown: m } = E({ enabled: c });
509
- return /* @__PURE__ */ y("div", { className: e, children: /* @__PURE__ */ y(
581
+ }, P = S(
582
+ ({ mode: w = "geez", className: e, onChange: n, onKeyDown: a, value: i, ...l }, o) => {
583
+ const { onKeyDown: t } = y({ enabled: w === "geez" });
584
+ return /* @__PURE__ */ b(
510
585
  "input",
511
586
  {
512
- ...u,
513
- ...s !== void 0 && { value: s },
514
- ref: l,
515
- onKeyDown: (a) => {
516
- if ((a.metaKey || a.ctrlKey) && a.shiftKey && a.key === "S") {
517
- a.preventDefault(), r((f) => !f);
518
- return;
519
- }
520
- m(a), o && o(a);
587
+ ...l,
588
+ ...i !== void 0 && { value: i },
589
+ ref: o,
590
+ onKeyDown: (u) => {
591
+ w === "geez" && t(u), a && a(u);
521
592
  },
522
- onChange: (a) => {
523
- n && n(a);
593
+ onChange: (u) => {
594
+ n && n(u);
524
595
  },
525
- className: t || i
596
+ className: e
526
597
  }
527
- ) });
598
+ );
528
599
  }
529
600
  );
530
601
  P.displayName = "GeezInput";
531
- const R = v(
532
- ({ defaultGeez: w = !0, wrapperClassName: e, textareaClassName: i, className: t, onChange: n, onKeyDown: o, value: s, ...u }, l) => {
533
- const [c, r] = D(w), { onKeyDown: m } = E({ enabled: c });
534
- return /* @__PURE__ */ y("div", { className: e, children: /* @__PURE__ */ y(
602
+ const R = S(
603
+ ({ mode: w = "geez", className: e, onChange: n, onKeyDown: a, value: i, ...l }, o) => {
604
+ const { onKeyDown: t } = y({ enabled: w === "geez" });
605
+ return /* @__PURE__ */ b(
535
606
  "textarea",
536
607
  {
537
- ...u,
538
- ...s !== void 0 && { value: s },
539
- ref: l,
540
- onKeyDown: (a) => {
541
- if ((a.metaKey || a.ctrlKey) && a.shiftKey && a.key === "S") {
542
- a.preventDefault(), r((f) => !f);
543
- return;
544
- }
545
- m(a), o && o(a);
608
+ ...l,
609
+ ...i !== void 0 && { value: i },
610
+ ref: o,
611
+ onKeyDown: (u) => {
612
+ w === "geez" && t(u), a && a(u);
546
613
  },
547
- onChange: (a) => {
548
- n && n(a);
614
+ onChange: (u) => {
615
+ n && n(u);
549
616
  },
550
- className: t || i
617
+ className: e
551
618
  }
552
- ) });
619
+ );
553
620
  }
554
621
  );
555
622
  R.displayName = "GeezTextArea";
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geez-input",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Type-safe React library for Geez (Ethiopic) script input with phonetic keyboard support",
5
5
  "keywords": [
6
6
  "geez",