geez-input 1.0.0 → 1.0.1

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
@@ -8,7 +8,6 @@ A type-safe React library for Geez (Ethiopic) script input with phonetic keyboar
8
8
  - **Phonetic Keyboard**: Intuitive Latin-to-Geez transformation following standard conventions
9
9
  - **Customizable Components**: Pre-styled input and textarea components with toggle support
10
10
  - **React Hook**: `useGeez` hook for custom implementations
11
- - **Tree-Shakeable**: Optimized bundle size with CSS code splitting
12
11
  - **Form Library Support**: Works with React Hook Form, Formik, and other form libraries
13
12
  - **Controlled & Uncontrolled**: Full support for both component patterns
14
13
 
@@ -194,15 +193,5 @@ Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for det
194
193
 
195
194
  ## License
196
195
 
197
- MIT License - see [LICENSE](LICENSE) for details.
196
+ MIT [LICENSE](LICENSE)
198
197
 
199
- ## Links
200
-
201
- - [GitHub Repository](https://github.com/yourusername/geez-library)
202
- - [NPM Package](https://www.npmjs.com/package/geez-input)
203
- - [Documentation Site](https://geez-library.vercel.app)
204
- - [Issue Tracker](https://github.com/yourusername/geez-library/issues)
205
-
206
- ## Credits
207
-
208
- Built with TypeScript, React, and Vite.
@@ -0,0 +1 @@
1
+ .geez-input-wrapper{position:relative;width:100%}.geez-input-field{width:100%;background-color:var(--geez-bg-paper, #fefefe);border:2px solid var(--geez-border-gold, rgba(212, 175, 55, .2));outline:none;padding:1rem;font-family:var(--geez-font-serif, Georgia, serif);font-size:1.125rem;transition:all .2s ease}.geez-input-field:focus{border-color:var(--geez-border-crimson, #dc143c)}.geez-input-toggle{position:absolute;right:1rem;top:50%;transform:translateY(-50%);padding:.375rem .75rem;border-radius:.375rem;transition:all .2s ease;z-index:10;font-weight:600;font-size:.875rem;border:none;cursor:pointer}.geez-input-toggle--active{background-color:var(--geez-bg-crimson, #dc143c);color:var(--geez-text-white, #ffffff)}.geez-input-toggle--inactive{background-color:var(--geez-bg-gold-light, rgba(212, 175, 55, .1));color:var(--geez-text-gold, #d4af37)}.geez-textarea-wrapper{position:relative;width:100%}.geez-textarea-field{width:100%;background-color:var(--geez-bg-paper, #fefefe);border:2px solid var(--geez-border-gold, rgba(212, 175, 55, .2));outline:none;padding:1.5rem;font-family:var(--geez-font-serif, Georgia, serif);font-size:1.125rem;line-height:1.75;transition:all .2s ease;min-height:150px}.geez-textarea-field:focus{border-color:var(--geez-border-crimson, #dc143c)}.geez-textarea-toggle{position:absolute;right:1rem;top:1rem;padding:.375rem .75rem;border-radius:.375rem;transition:all .2s ease;z-index:10;font-weight:600;font-size:.875rem;border:none;cursor:pointer}.geez-textarea-toggle--active{background-color:var(--geez-bg-crimson, #dc143c);color:var(--geez-text-white, #ffffff)}.geez-textarea-toggle--inactive{background-color:var(--geez-bg-gold-light, rgba(212, 175, 55, .1));color:var(--geez-text-gold, #d4af37)}
@@ -12,7 +12,15 @@ export interface GeezInputProps extends React.InputHTMLAttributes<HTMLInputEleme
12
12
  /**
13
13
  * Additional CSS classes to apply to the input wrapper
14
14
  */
15
- className?: string;
15
+ wrapperClassName?: string;
16
+ /**
17
+ * Additional CSS classes to apply to the input field
18
+ */
19
+ inputClassName?: string;
20
+ /**
21
+ * Additional CSS classes to apply to the toggle button
22
+ */
23
+ buttonClassName?: string;
16
24
  }
17
25
  /**
18
26
  * Styled input component with built-in Geez phonetic keyboard support
@@ -22,7 +30,8 @@ export interface GeezInputProps extends React.InputHTMLAttributes<HTMLInputEleme
22
30
  * - Phonetic transformation (type 'hello' → 'ሀልሎ')
23
31
  * - Full support for controlled and uncontrolled component patterns
24
32
  * - Forward ref support for form libraries
25
- * - Styled with a classic paper and ink aesthetic
33
+ * - Styled with CSS classes that can be customized via className props
34
+ * - Supports Tailwind CSS, CSS modules, or any CSS framework
26
35
  *
27
36
  * @example
28
37
  * \`\`\`tsx
@@ -53,5 +62,27 @@ export interface GeezInputProps extends React.InputHTMLAttributes<HTMLInputEleme
53
62
  * return <GeezInput {...register('name')} />
54
63
  * }
55
64
  * \`\`\`
65
+ *
66
+ * @example
67
+ * \`\`\`tsx
68
+ * // Custom styling with Tailwind CSS
69
+ * <GeezInput
70
+ * wrapperClassName="mb-4"
71
+ * inputClassName="rounded-lg shadow-md"
72
+ * buttonClassName="hover:opacity-80"
73
+ * placeholder="Type here..."
74
+ * />
75
+ * \`\`\`
76
+ *
77
+ * @example
78
+ * \`\`\`tsx
79
+ * // Custom styling with CSS classes
80
+ * <GeezInput
81
+ * wrapperClassName="my-custom-wrapper"
82
+ * inputClassName="my-custom-input"
83
+ * buttonClassName="my-custom-button"
84
+ * placeholder="Type here..."
85
+ * />
86
+ * \`\`\`
56
87
  */
57
88
  export declare const GeezInput: React.ForwardRefExoticComponent<GeezInputProps & React.RefAttributes<HTMLInputElement>>;
@@ -12,7 +12,15 @@ export interface GeezTextAreaProps extends React.TextareaHTMLAttributes<HTMLText
12
12
  /**
13
13
  * Additional CSS classes to apply to the textarea wrapper
14
14
  */
15
- className?: string;
15
+ wrapperClassName?: string;
16
+ /**
17
+ * Additional CSS classes to apply to the textarea field
18
+ */
19
+ textareaClassName?: string;
20
+ /**
21
+ * Additional CSS classes to apply to the toggle button
22
+ */
23
+ buttonClassName?: string;
16
24
  }
17
25
  /**
18
26
  * Styled textarea component with built-in Geez phonetic keyboard support
@@ -22,7 +30,8 @@ export interface GeezTextAreaProps extends React.TextareaHTMLAttributes<HTMLText
22
30
  * - Phonetic transformation for longer text
23
31
  * - Full support for controlled and uncontrolled component patterns
24
32
  * - Forward ref support for form libraries
25
- * - Styled with a classic paper and ink aesthetic
33
+ * - Styled with CSS classes that can be customized via className props
34
+ * - Supports Tailwind CSS, CSS modules, or any CSS framework
26
35
  * - Minimum height of 150px for comfortable writing
27
36
  *
28
37
  * @example
@@ -51,5 +60,27 @@ export interface GeezTextAreaProps extends React.TextareaHTMLAttributes<HTMLText
51
60
  * // Start with English mode
52
61
  * <GeezTextArea defaultGeez={false} placeholder="Type here..." />
53
62
  * \`\`\`
63
+ *
64
+ * @example
65
+ * \`\`\`tsx
66
+ * // Custom styling with Tailwind CSS
67
+ * <GeezTextArea
68
+ * wrapperClassName="mb-4"
69
+ * textareaClassName="rounded-lg shadow-md resize-none"
70
+ * buttonClassName="hover:opacity-80"
71
+ * placeholder="Write here..."
72
+ * />
73
+ * \`\`\`
74
+ *
75
+ * @example
76
+ * \`\`\`tsx
77
+ * // Custom styling with CSS classes
78
+ * <GeezTextArea
79
+ * wrapperClassName="my-custom-wrapper"
80
+ * textareaClassName="my-custom-textarea"
81
+ * buttonClassName="my-custom-button"
82
+ * placeholder="Write here..."
83
+ * />
84
+ * \`\`\`
54
85
  */
55
86
  export declare const GeezTextArea: React.ForwardRefExoticComponent<GeezTextAreaProps & React.RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Utility function to merge CSS class names
3
+ * Filters out empty strings and undefined values
4
+ */
5
+ export declare function cn(...classes: (string | undefined | null | false)[]): string;
package/dist/main.js CHANGED
@@ -1,6 +1,6 @@
1
- import { useCallback as K, forwardRef as A, useState as y } from "react";
2
- import { jsxs as v, jsx as g } from "react/jsx-runtime";
3
- const f = {
1
+ import { useCallback as S, forwardRef as y, useState as N } from "react";
2
+ import { jsxs as D, jsx as A } from "react/jsx-runtime";
3
+ import './assets/main.css';const z = {
4
4
  h: "ህ",
5
5
  l: "ል",
6
6
  m: "ም",
@@ -40,7 +40,7 @@ const f = {
40
40
  A: "ኣ",
41
41
  E: "ኤ",
42
42
  O: "ዖ"
43
- }, r = {
43
+ }, g = {
44
44
  አ: {
45
45
  a: "አ",
46
46
  e: "አ",
@@ -384,13 +384,13 @@ const f = {
384
384
  o: "ቮ",
385
385
  ua: "ቯ"
386
386
  }
387
- }, w = {
387
+ }, v = {
388
388
  ስh: "ሽ",
389
389
  ችh: "ች",
390
390
  ንy: "ኝ",
391
391
  ዝh: "ዥ",
392
392
  ጽh: "ፁ"
393
- }, m = {
393
+ }, b = {
394
394
  ":": "፡",
395
395
  "፡:": "።",
396
396
  "።:": "፡",
@@ -398,7 +398,7 @@ const f = {
398
398
  "፣,": "፤",
399
399
  ";": "፤"
400
400
  };
401
- class S {
401
+ class P {
402
402
  /**
403
403
  * Transform input text based on a new key press
404
404
  *
@@ -430,50 +430,50 @@ class S {
430
430
  * // → { transformedValue: 'ሽ', newCursorPosition: 1, isReplacement: true }
431
431
  * \`\`\`
432
432
  */
433
- static transform(e, a, t) {
434
- const n = e.slice(-1), l = n + t;
435
- if (m[l])
433
+ static transform(e, a, i) {
434
+ const n = e.slice(-1), s = n + i;
435
+ if (b[s])
436
436
  return {
437
- transformedValue: e.slice(0, -1) + m[l] + a,
437
+ transformedValue: e.slice(0, -1) + b[s] + a,
438
438
  newCursorPosition: e.length,
439
439
  isReplacement: !0
440
440
  };
441
- if (m[t])
441
+ if (b[i])
442
442
  return {
443
- transformedValue: e + m[t] + a,
443
+ transformedValue: e + b[i] + a,
444
444
  newCursorPosition: e.length + 1,
445
445
  isReplacement: !1
446
446
  };
447
- if (w[l])
447
+ if (v[s])
448
448
  return {
449
- transformedValue: e.slice(0, -1) + w[l] + a,
449
+ transformedValue: e.slice(0, -1) + v[s] + a,
450
450
  newCursorPosition: e.length,
451
451
  isReplacement: !0
452
452
  };
453
- if (r[n] && r[n][t])
453
+ if (g[n] && g[n][i])
454
454
  return {
455
- transformedValue: e.slice(0, -1) + r[n][t] + a,
455
+ transformedValue: e.slice(0, -1) + g[n][i] + a,
456
456
  newCursorPosition: e.length,
457
457
  isReplacement: !0
458
458
  };
459
- if (["a", "e", "i"].includes(t)) {
460
- const o = this.findSadisBase(n);
461
- if (o && r[o]) {
462
- const i = t + t;
463
- if (r[o][i])
459
+ if (["a", "e", "i"].includes(i)) {
460
+ const t = this.findSadisBase(n);
461
+ if (t && g[t]) {
462
+ const l = i + i;
463
+ if (g[t][l])
464
464
  return {
465
- transformedValue: e.slice(0, -1) + r[o][i] + a,
465
+ transformedValue: e.slice(0, -1) + g[t][l] + a,
466
466
  newCursorPosition: e.length,
467
467
  isReplacement: !0
468
468
  };
469
469
  }
470
470
  }
471
- return f[t] ? {
472
- transformedValue: e + f[t] + a,
471
+ return z[i] ? {
472
+ transformedValue: e + z[i] + a,
473
473
  newCursorPosition: e.length + 1,
474
474
  isReplacement: !1
475
475
  } : {
476
- transformedValue: e + t + a,
476
+ transformedValue: e + i + a,
477
477
  newCursorPosition: e.length + 1,
478
478
  isReplacement: !1
479
479
  };
@@ -496,14 +496,14 @@ class S {
496
496
  * \`\`\`
497
497
  */
498
498
  static findSadisBase(e) {
499
- for (const [a, t] of Object.entries(r))
500
- if (a === e || Object.values(t).includes(e)) return a;
499
+ for (const [a, i] of Object.entries(g))
500
+ if (a === e || Object.values(i).includes(e)) return a;
501
501
  return null;
502
502
  }
503
503
  }
504
- const z = (c = {}) => {
505
- const { enabled: e = !0, onTransform: a } = c;
506
- return { onKeyDown: K(
504
+ const K = (r = {}) => {
505
+ const { enabled: e = !0, onTransform: a } = r;
506
+ return { onKeyDown: S(
507
507
  (n) => {
508
508
  if (!e || [
509
509
  "Backspace",
@@ -521,108 +521,120 @@ const z = (c = {}) => {
521
521
  "PageDown"
522
522
  ].includes(n.key) || n.ctrlKey || n.metaKey || n.key.length !== 1 || n.altKey) return;
523
523
  n.preventDefault();
524
- const o = n.currentTarget, { selectionStart: i, selectionEnd: p, value: d } = o, b = d.substring(0, i || 0), E = d.substring(p || 0), u = S.transform(b, E, n.key), s = Object.getOwnPropertyDescriptor(o.constructor.prototype, "value");
525
- s && s.set ? s.set.bind(o)(u.transformedValue) : o.value = u.transformedValue;
526
- let h;
527
- typeof InputEvent < "u" ? h = new InputEvent("input", {
524
+ const t = n.currentTarget, { selectionStart: l, selectionEnd: f, value: p } = t, o = p.substring(0, l || 0), h = p.substring(f || 0), c = P.transform(o, h, n.key), d = Object.getOwnPropertyDescriptor(t.constructor.prototype, "value");
525
+ d && d.set ? d.set.bind(t)(c.transformedValue) : t.value = c.transformedValue;
526
+ let E;
527
+ typeof InputEvent < "u" ? E = new InputEvent("input", {
528
528
  bubbles: !0,
529
529
  cancelable: !0,
530
530
  inputType: "insertText",
531
531
  data: n.key
532
- }) : h = new Event("input", { bubbles: !0, cancelable: !0 }), o.dispatchEvent(h);
533
- const N = new Event("change", {
532
+ }) : E = new Event("input", { bubbles: !0, cancelable: !0 }), t.dispatchEvent(E);
533
+ const w = new Event("change", {
534
534
  bubbles: !0,
535
535
  cancelable: !0
536
536
  });
537
- o.dispatchEvent(N), requestAnimationFrame(() => {
538
- if (document.activeElement === o)
537
+ t.dispatchEvent(w), requestAnimationFrame(() => {
538
+ if (document.activeElement === t)
539
539
  try {
540
- o.setSelectionRange(u.newCursorPosition, u.newCursorPosition);
540
+ t.setSelectionRange(c.newCursorPosition, c.newCursorPosition);
541
541
  } catch {
542
542
  }
543
- }), a && a(u);
543
+ }), a && a(c);
544
544
  },
545
545
  [e, a]
546
546
  ) };
547
- }, P = A(
548
- ({ defaultGeez: c = !0, className: e, onChange: a, onKeyDown: t, value: n, ...l }, o) => {
549
- const [i, p] = y(c), d = {
550
- ...l,
551
- ...n !== void 0 && { value: n }
552
- }, { onKeyDown: b } = z({ enabled: i });
553
- return /* @__PURE__ */ v("div", { className: "relative group w-full", children: [
554
- /* @__PURE__ */ g(
547
+ };
548
+ function m(...r) {
549
+ return r.filter(Boolean).join(" ");
550
+ }
551
+ const T = y(
552
+ ({ defaultGeez: r = !0, wrapperClassName: e, inputClassName: a, buttonClassName: i, className: n, onChange: s, onKeyDown: t, value: l, ...f }, p) => {
553
+ const [o, h] = N(r), c = {
554
+ ...f,
555
+ ...l !== void 0 && { value: l }
556
+ }, { onKeyDown: d } = K({ enabled: o }), E = (u) => {
557
+ d(u), t && t(u);
558
+ }, w = (u) => {
559
+ s && s(u);
560
+ };
561
+ return /* @__PURE__ */ D("div", { className: m("geez-input-wrapper", e), children: [
562
+ /* @__PURE__ */ A(
555
563
  "input",
556
564
  {
557
- ...d,
558
- ref: o,
559
- onKeyDown: (s) => {
560
- b(s), t && t(s);
561
- },
562
- onChange: (s) => {
563
- a && a(s);
564
- },
565
- className: `w-full bg-paper border-2 border-gold/20 focus:border-crimson outline-none p-4 font-serif text-lg transition-all ${e || ""}`
565
+ ...c,
566
+ ref: p,
567
+ onKeyDown: E,
568
+ onChange: w,
569
+ className: m("geez-input-field", n, a)
566
570
  }
567
571
  ),
568
- /* @__PURE__ */ g(
572
+ /* @__PURE__ */ A(
569
573
  "button",
570
574
  {
571
575
  type: "button",
572
- onClick: () => p(!i),
573
- className: `absolute right-4 top-1/2 -translate-y-1/2 px-3 py-1.5 rounded-md transition-all z-10 font-semibold text-sm ${i ? "bg-crimson text-white" : "bg-gold/10 text-gold"}`,
574
- title: i ? "Switch to English" : "Switch to Ge'ez",
576
+ onClick: () => h(!o),
577
+ className: m(
578
+ "geez-input-toggle",
579
+ o ? "geez-input-toggle--active" : "geez-input-toggle--inactive",
580
+ i
581
+ ),
582
+ title: o ? "Switch to English" : "Switch to Ge'ez",
575
583
  tabIndex: -1,
576
- children: i ? "አማ" : "EN"
584
+ children: o ? "አማ" : "EN"
577
585
  }
578
586
  )
579
587
  ] });
580
588
  }
581
589
  );
582
- P.displayName = "GeezInput";
583
- const T = A(
584
- ({ defaultGeez: c = !0, className: e, onChange: a, onKeyDown: t, value: n, ...l }, o) => {
585
- const [i, p] = y(c), d = {
586
- ...l,
587
- ...n !== void 0 && { value: n }
588
- }, { onKeyDown: b } = z({ enabled: i }), E = (s) => {
589
- b(s), t && t(s);
590
- }, u = (s) => {
591
- a && a(s);
590
+ T.displayName = "GeezInput";
591
+ const G = y(
592
+ ({ defaultGeez: r = !0, wrapperClassName: e, textareaClassName: a, buttonClassName: i, className: n, onChange: s, onKeyDown: t, value: l, ...f }, p) => {
593
+ const [o, h] = N(r), c = {
594
+ ...f,
595
+ ...l !== void 0 && { value: l }
596
+ }, { onKeyDown: d } = K({ enabled: o }), E = (u) => {
597
+ d(u), t && t(u);
598
+ }, w = (u) => {
599
+ s && s(u);
592
600
  };
593
- return /* @__PURE__ */ v("div", { className: `relative group w-full ${e || ""}`, children: [
594
- /* @__PURE__ */ g(
601
+ return /* @__PURE__ */ D("div", { className: m("geez-textarea-wrapper", e), children: [
602
+ /* @__PURE__ */ A(
595
603
  "textarea",
596
604
  {
597
- ...d,
598
- ref: o,
605
+ ...c,
606
+ ref: p,
599
607
  onKeyDown: E,
600
- onChange: u,
601
- className: `w-full bg-paper border-2 border-gold/20 focus:border-crimson outline-none p-6 font-serif text-lg leading-relaxed transition-all min-h-[150px] ${e || ""}`
608
+ onChange: w,
609
+ className: m("geez-textarea-field", n, a)
602
610
  }
603
611
  ),
604
- /* @__PURE__ */ g(
612
+ /* @__PURE__ */ A(
605
613
  "button",
606
614
  {
607
615
  type: "button",
608
- onClick: () => p(!i),
609
- className: `absolute right-4 top-4 px-3 py-1.5 rounded-md transition-all z-10 font-semibold text-sm ${i ? "bg-crimson text-white" : "bg-gold/10 text-gold"}`,
610
- title: i ? "Switch to English" : "Switch to Ge'ez",
616
+ onClick: () => h(!o),
617
+ className: m(
618
+ "geez-textarea-toggle",
619
+ o ? "geez-textarea-toggle--active" : "geez-textarea-toggle--inactive",
620
+ i
621
+ ),
622
+ title: o ? "Switch to English" : "Switch to Ge'ez",
611
623
  tabIndex: -1,
612
- children: i ? "አማ" : "EN"
624
+ children: o ? "አማ" : "EN"
613
625
  }
614
626
  )
615
627
  ] });
616
628
  }
617
629
  );
618
- T.displayName = "GeezTextArea";
630
+ G.displayName = "GeezTextArea";
619
631
  export {
620
- f as CONSONANTS,
621
- S as GeezEngine,
622
- P as GeezInput,
623
- T as GeezTextArea,
624
- w as MULTI_CONSONANTS,
625
- m as PUNCTUATION,
626
- r as SYLLABLES,
627
- z as useGeez
632
+ z as CONSONANTS,
633
+ P as GeezEngine,
634
+ T as GeezInput,
635
+ G as GeezTextArea,
636
+ v as MULTI_CONSONANTS,
637
+ b as PUNCTUATION,
638
+ g as SYLLABLES,
639
+ K as useGeez
628
640
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geez-input",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Type-safe React library for Geez (Ethiopic) script input with phonetic keyboard support",
5
5
  "keywords": [
6
6
  "geez",
@@ -13,16 +13,20 @@
13
13
  "input",
14
14
  "phonetic"
15
15
  ],
16
- "homepage": "https://github.com/yourusername/geez-library#readme",
16
+ "homepage": "https://github.com/onesamket/geez-input#readme",
17
17
  "bugs": {
18
- "url": "https://github.com/yourusername/geez-library/issues"
18
+ "url": "https://github.com/onesamket/geez-input/issues"
19
19
  },
20
20
  "repository": {
21
21
  "type": "git",
22
- "url": "https://github.com/yourusername/geez-library.git"
22
+ "url": "https://github.com/onesamket/geez-input.git"
23
23
  },
24
24
  "license": "MIT",
25
- "author": "Your Name",
25
+ "author":{
26
+ "name": "Tewodros Birhanu",
27
+ "email": "onesamket@gmail.com",
28
+ "url": "https://github.com/onesamket"
29
+ },
26
30
  "sideEffects": [
27
31
  "**/*.css"
28
32
  ],