@j1nn0/vanilla-autokana 2.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 ADDED
@@ -0,0 +1,8 @@
1
+ Copyright 2018 Ryo Utsunomiya
2
+ Modifications Copyright 2026 j1nn0
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,218 @@
1
+ # vanilla-autokana
2
+
3
+ [English README is here](./README_en.md)
4
+
5
+ このプロジェクトは [ryo-utsunomiya/vanilla-autokana](https://github.com/ryo-utsunomiya/vanilla-autokana) からフォークした実装です。
6
+
7
+ フォームのフィールドに文字を入力すると、別のフィールドにかなを自動入力するライブラリです。
8
+
9
+ ## 特徴
10
+
11
+ - jQueryに依存していません
12
+ - scriptタグからの読み込みとESModulesのimportに対応しています
13
+
14
+ ## インストール方法
15
+
16
+ ### npm
17
+
18
+ ```sh
19
+ npm i @j1nn0/vanilla-autokana # or yarn add @j1nn0/vanilla-autokana
20
+ ```
21
+
22
+ ### npmを使わない方法
23
+
24
+ このリポジトリの `dist/autokana.umd.js` をダウンロードし、scriptタグで読み込んでください。
25
+
26
+ ## 使用方法
27
+
28
+ - `AutoKana.bind()` メソッドの第1引数にふりがな入力元の input 要素を指定します。第2引数にはふりがな出力先の input 要素を指定できますが、省略も可能です
29
+ - 要素の指定には `#` / `.` / `[` / `:` で始まるセレクタ文字列、または input / textarea 要素を渡せます。IDのみを渡した場合も従来どおり動作します
30
+ - input / textarea 要素が見つけられない場合は正常に動作できないため、DOMContentLoadedイベント内での実行を推奨します
31
+ - ライブラリ本体はDOMのライフサイクルイベントに依存しないため、ライブラリの読み込みには`defer`属性の追加を推奨します
32
+
33
+ ```html
34
+ <input name="name" id="name">
35
+ <input name="furigana" id="furigana">
36
+ <script src="autokana.umd.js" defer></script>
37
+ <script>
38
+ document.addEventListener("DOMContentLoaded", function() {
39
+ // ひらがなで出力(デフォルト)
40
+ AutoKana.bind("#name", "#furigana");
41
+ // 全角カタカナで出力したい場合
42
+ // AutoKana.bind("#name", "#furigana", { katakana: 'full' });
43
+ // 半角カタカナで出力したい場合
44
+ // AutoKana.bind("#name", "#furigana", { katakana: 'half' });
45
+ });
46
+ </script>
47
+ ```
48
+
49
+ ### モジュールとしてimportする
50
+
51
+ ESModulesとしてimportすることができます。
52
+
53
+ ```js
54
+ import * as AutoKana from '@j1nn0/vanilla-autokana';
55
+
56
+ AutoKana.bind('#name', '#furigana');
57
+ ```
58
+
59
+ ### オプション
60
+
61
+ `AutoKana.bind(name, furigana?, option)` の第3引数には以下を指定できます。
62
+
63
+ - `name`: `#` / `.` / `[` / `:` で始まるセレクタ文字列、または input / textarea 要素
64
+ - `furigana`: `#` / `.` / `[` / `:` で始まるセレクタ文字列、input / textarea 要素、または省略
65
+
66
+ - `katakana`: `'hiragana' | 'full' | 'half'`
67
+ - `debug`: `boolean`
68
+ - `onChange`: `(furigana: string) => void` — ふりがなが変更されるたびに呼ばれるコールバック
69
+
70
+ `katakana` の値ごとの挙動:
71
+
72
+ - `'hiragana'`: ひらがなで出力(デフォルト)
73
+ - `'full'`: 全角カタカナで出力
74
+ - `'half'`: 半角カタカナで出力(全角空白は半角空白に正規化)
75
+
76
+ ### メソッド
77
+
78
+ - `getFurigana()`: 現在のふりがな文字列を返す
79
+ - `start()`: ふりがなの自動追跡を再開する
80
+ - `stop()`: ふりがなの自動追跡を一時停止する
81
+ - `toggle(event?)`: ふりがなの自動追跡を切り替える。チェックボックスの変更イベントを渡すと、その `checked` 状態を使う
82
+ - `reset()`: 内部状態(ふりがな、変換フラグなど)をすべてリセットする
83
+ - `destroy()`: イベントリスナーをすべて削除する
84
+
85
+ > **注意**: `initializeValues()` は非推奨です。代わりに `reset()` を使用してください。
86
+
87
+ ### Vue.jsと組み合わせる
88
+
89
+ `onChange` コールバックを使うと、`getFurigana()` のポーリングなしでふりがなの変更を検知できます。
90
+ また、出力先の input 要素を指定している場合は、その要素に `bubbles: true` の `input` イベントも発火します。
91
+
92
+ ```vue
93
+ <template>
94
+ <div id="app">
95
+ <div>
96
+ <label for="name">名前</label>
97
+ <input name="name" id="name" v-model="name">
98
+ </div>
99
+ <div>
100
+ <label for="furigana">ふりがな</label>
101
+ <input name="furigana" id="furigana" v-model="furigana">
102
+ </div>
103
+ <h2>入力内容の確認</h2>
104
+ <p>名前: {{ name }}</p>
105
+ <p>ふりがな: {{ furigana }}</p>
106
+ </div>
107
+ </template>
108
+
109
+ <script setup>
110
+ import { ref, onMounted, onUnmounted } from 'vue';
111
+ import { bind } from '@j1nn0/vanilla-autokana';
112
+
113
+ const name = ref('');
114
+ const furigana = ref('');
115
+ let autokana;
116
+
117
+ onMounted(() => {
118
+ autokana = bind('#name', '#furigana', {
119
+ onChange: (value) => {
120
+ furigana.value = value;
121
+ },
122
+ });
123
+ });
124
+
125
+ onUnmounted(() => {
126
+ autokana?.destroy();
127
+ });
128
+ </script>
129
+ ```
130
+
131
+ `v-model`を使用している場合でも、出力先 input には `input` イベントが発火します。ただし、状態同期には `onChange` コールバックの利用を推奨します。
132
+ `onChange` コールバックを使わずに `getFurigana` メソッドでふりがなを取り出すこともできますが、`onChange` の使用を推奨します。
133
+
134
+ ```html
135
+ <!-- 非推奨: getFurigana() のポーリング -->
136
+ <input name="name" id="name" v-model="name" @input="handleNameInput">
137
+ ```
138
+
139
+ ### React.jsと組み合わせる
140
+
141
+ Vue.jsと同様に `onChange` コールバックが使えます。
142
+
143
+ ```jsx
144
+ import { useEffect, useState } from 'react';
145
+ import { bind } from '@j1nn0/vanilla-autokana';
146
+
147
+ function App() {
148
+ const [name, setName] = useState('');
149
+ const [furigana, setFurigana] = useState('');
150
+
151
+ useEffect(() => {
152
+ const autokana = bind('#name', '#furigana', {
153
+ onChange: (value) => {
154
+ setFurigana(value);
155
+ },
156
+ });
157
+
158
+ return () => {
159
+ autokana.destroy();
160
+ };
161
+ }, []);
162
+
163
+ return (
164
+ <div className="App">
165
+ <div>
166
+ <label htmlFor="name">名前</label>
167
+ <input
168
+ name="name"
169
+ id="name"
170
+ value={name}
171
+ onInput={(e) => setName(e.target.value)}
172
+ />
173
+ </div>
174
+ <div>
175
+ <label htmlFor="furigana">ふりがな</label>
176
+ <input name="furigana" id="furigana" value={furigana} readOnly />
177
+ </div>
178
+ <h2>入力内容の確認</h2>
179
+ <p>名前: {name}</p>
180
+ <p>ふりがな: {furigana}</p>
181
+ </div>
182
+ );
183
+ }
184
+
185
+ export default App;
186
+ ```
187
+
188
+ ## 移行ガイド(v1 → v2)
189
+
190
+ v2.0.0 で `katakana` オプションの値が変更されました。
191
+
192
+ ### 変更点
193
+
194
+ | 変更前 (v1) | 変更後 (v2) |
195
+ |-------------|-------------|
196
+ | `katakana: false` | `katakana: 'hiragana'` |
197
+ | `katakana: 'full'` | `katakana: 'full'`(変更なし) |
198
+ | `katakana: 'half'` | `katakana: 'half'`(変更なし) |
199
+
200
+ ### 移行手順
201
+
202
+ ```js
203
+ // v1
204
+ AutoKana.bind('#name', '#furigana', { katakana: false });
205
+
206
+ // v2
207
+ AutoKana.bind('#name', '#furigana', { katakana: 'hiragana' });
208
+ ```
209
+
210
+ ## ライセンス
211
+
212
+ MIT
213
+
214
+ ## 謝辞
215
+
216
+ このプロジェクトは [ryo-utsunomiya/vanilla-autokana](https://github.com/ryo-utsunomiya/vanilla-autokana) をベースにしています。
217
+
218
+ このライブラリの設計・実装は jquery-autokana(https://github.com/harisenbon/autokana) に大きく影響を受けています。
@@ -0,0 +1,79 @@
1
+ import { Bindable } from './ElementResolver.cjs';
2
+ export type { Bindable };
3
+ export type { KatakanaOption };
4
+ type KatakanaOption = 'hiragana' | 'full' | 'half';
5
+ export interface AutoKanaOption {
6
+ /** Output format for furigana. `'hiragana'` = hiragana, `'full'` = full-width katakana, `'half'` = half-width katakana. */
7
+ katakana?: KatakanaOption;
8
+ /** When `true`, logs debug information to the console. */
9
+ debug?: boolean;
10
+ /** Callback invoked with the current furigana string whenever it changes. */
11
+ onChange?: (furigana: string) => void;
12
+ }
13
+ export default class AutoKana {
14
+ isActive: boolean;
15
+ option: AutoKanaOption & {
16
+ katakana: KatakanaOption;
17
+ debug: boolean;
18
+ };
19
+ private elName;
20
+ private elFurigana?;
21
+ private committedKana;
22
+ private furigana;
23
+ private isComposing;
24
+ private lastConvertedInput;
25
+ private lastNewInput;
26
+ private pendingKana;
27
+ private previousRawInput;
28
+ private blurHandler;
29
+ private focusHandler;
30
+ private compositionStartHandler;
31
+ private compositionEndHandler;
32
+ private inputHandler;
33
+ constructor(name: Bindable, furigana?: Bindable, option?: Partial<AutoKanaOption>);
34
+ /**
35
+ * Get the current furigana string.
36
+ *
37
+ * @returns The current furigana string.
38
+ */
39
+ getFurigana(): string;
40
+ /**
41
+ * Resume auto-kana tracking.
42
+ */
43
+ start(): void;
44
+ /**
45
+ * Pause auto-kana tracking.
46
+ */
47
+ stop(): void;
48
+ /**
49
+ * Toggle auto-kana tracking on or off.
50
+ *
51
+ * @param event Optional checkbox change event. When provided, uses the checked state of the target.
52
+ */
53
+ toggle(event?: {
54
+ target: {
55
+ checked: boolean;
56
+ };
57
+ }): void;
58
+ /**
59
+ * Reset all internal state (committed kana, furigana, composing flag, etc.).
60
+ */
61
+ reset(): void;
62
+ /**
63
+ * @deprecated Use reset() instead.
64
+ */
65
+ initializeValues(): void;
66
+ private registerEvents;
67
+ setFurigana(force?: boolean): void;
68
+ private extractNewInput;
69
+ detectAndCommitConversion(newPendingKana: string[]): void;
70
+ private handleCompositionInput;
71
+ private handleNormalInput;
72
+ processValue(): void;
73
+ commitPendingKana(): void;
74
+ /**
75
+ * Remove all event listeners (blur, focus, compositionstart, compositionend, input) from the name element.
76
+ */
77
+ destroy(): void;
78
+ private debug;
79
+ }
@@ -0,0 +1,79 @@
1
+ import { Bindable } from './ElementResolver.js';
2
+ export type { Bindable };
3
+ export type { KatakanaOption };
4
+ type KatakanaOption = 'hiragana' | 'full' | 'half';
5
+ export interface AutoKanaOption {
6
+ /** Output format for furigana. `'hiragana'` = hiragana, `'full'` = full-width katakana, `'half'` = half-width katakana. */
7
+ katakana?: KatakanaOption;
8
+ /** When `true`, logs debug information to the console. */
9
+ debug?: boolean;
10
+ /** Callback invoked with the current furigana string whenever it changes. */
11
+ onChange?: (furigana: string) => void;
12
+ }
13
+ export default class AutoKana {
14
+ isActive: boolean;
15
+ option: AutoKanaOption & {
16
+ katakana: KatakanaOption;
17
+ debug: boolean;
18
+ };
19
+ private elName;
20
+ private elFurigana?;
21
+ private committedKana;
22
+ private furigana;
23
+ private isComposing;
24
+ private lastConvertedInput;
25
+ private lastNewInput;
26
+ private pendingKana;
27
+ private previousRawInput;
28
+ private blurHandler;
29
+ private focusHandler;
30
+ private compositionStartHandler;
31
+ private compositionEndHandler;
32
+ private inputHandler;
33
+ constructor(name: Bindable, furigana?: Bindable, option?: Partial<AutoKanaOption>);
34
+ /**
35
+ * Get the current furigana string.
36
+ *
37
+ * @returns The current furigana string.
38
+ */
39
+ getFurigana(): string;
40
+ /**
41
+ * Resume auto-kana tracking.
42
+ */
43
+ start(): void;
44
+ /**
45
+ * Pause auto-kana tracking.
46
+ */
47
+ stop(): void;
48
+ /**
49
+ * Toggle auto-kana tracking on or off.
50
+ *
51
+ * @param event Optional checkbox change event. When provided, uses the checked state of the target.
52
+ */
53
+ toggle(event?: {
54
+ target: {
55
+ checked: boolean;
56
+ };
57
+ }): void;
58
+ /**
59
+ * Reset all internal state (committed kana, furigana, composing flag, etc.).
60
+ */
61
+ reset(): void;
62
+ /**
63
+ * @deprecated Use reset() instead.
64
+ */
65
+ initializeValues(): void;
66
+ private registerEvents;
67
+ setFurigana(force?: boolean): void;
68
+ private extractNewInput;
69
+ detectAndCommitConversion(newPendingKana: string[]): void;
70
+ private handleCompositionInput;
71
+ private handleNormalInput;
72
+ processValue(): void;
73
+ commitPendingKana(): void;
74
+ /**
75
+ * Remove all event listeners (blur, focus, compositionstart, compositionend, input) from the name element.
76
+ */
77
+ destroy(): void;
78
+ private debug;
79
+ }
@@ -0,0 +1,7 @@
1
+ /** A CSS selector string or a DOM Element. */
2
+ export type KanaElement = HTMLInputElement | HTMLTextAreaElement;
3
+ export type Bindable = string | KanaElement;
4
+ export declare function getElementLabel(selectorOrElement: Bindable): string;
5
+ export declare function ensureElement(selectorOrElement: Bindable): HTMLElement | null;
6
+ export declare function isKanaElement(el: HTMLElement): el is KanaElement;
7
+ export declare function requireElement(selectorOrElement: Bindable): KanaElement;
@@ -0,0 +1,7 @@
1
+ /** A CSS selector string or a DOM Element. */
2
+ export type KanaElement = HTMLInputElement | HTMLTextAreaElement;
3
+ export type Bindable = string | KanaElement;
4
+ export declare function getElementLabel(selectorOrElement: Bindable): string;
5
+ export declare function ensureElement(selectorOrElement: Bindable): HTMLElement | null;
6
+ export declare function isKanaElement(el: HTMLElement): el is KanaElement;
7
+ export declare function requireElement(selectorOrElement: Bindable): KanaElement;
@@ -0,0 +1,4 @@
1
+ import { KatakanaOption } from './AutoKana.cjs';
2
+ export declare class KanaConverter {
3
+ static toKatakana(src: string, option: KatakanaOption): string;
4
+ }
@@ -0,0 +1,4 @@
1
+ import { KatakanaOption } from './AutoKana.js';
2
+ export declare class KanaConverter {
3
+ static toKatakana(src: string, option: KatakanaOption): string;
4
+ }
@@ -0,0 +1,7 @@
1
+ export declare class KanaExtractor {
2
+ private static readonly EXTRACTION_PATTERN;
3
+ private static readonly COMPACTING_PATTERN;
4
+ static extract(input: string): string[];
5
+ static compact(input: string): string;
6
+ static containsNonKana(input: string): boolean;
7
+ }
@@ -0,0 +1,7 @@
1
+ export declare class KanaExtractor {
2
+ private static readonly EXTRACTION_PATTERN;
3
+ private static readonly COMPACTING_PATTERN;
4
+ static extract(input: string): string[];
5
+ static compact(input: string): string;
6
+ static containsNonKana(input: string): boolean;
7
+ }
@@ -0,0 +1 @@
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class{static{this.EXTRACTION_PATTERN=/[^  ぁあ-んゔー]/g}static{this.COMPACTING_PATTERN=/[ぁぃぅぇぉっゃゅょ]/g}static extract(e){return e.replace(this.EXTRACTION_PATTERN,``).split(``)}static compact(e){return e.replace(this.COMPACTING_PATTERN,``)}static containsNonKana(e){return e.search(this.EXTRACTION_PATTERN)!==-1}},t={ァ:`ァ`,ア:`ア`,ィ:`ィ`,イ:`イ`,ゥ:`ゥ`,ウ:`ウ`,ェ:`ェ`,エ:`エ`,ォ:`ォ`,オ:`オ`,カ:`カ`,ガ:`ガ`,キ:`キ`,ギ:`ギ`,ク:`ク`,グ:`グ`,ケ:`ケ`,ゲ:`ゲ`,コ:`コ`,ゴ:`ゴ`,サ:`サ`,ザ:`ザ`,シ:`シ`,ジ:`ジ`,ス:`ス`,ズ:`ズ`,セ:`セ`,ゼ:`ゼ`,ソ:`ソ`,ゾ:`ゾ`,タ:`タ`,ダ:`ダ`,チ:`チ`,ヂ:`ヂ`,ッ:`ッ`,ツ:`ツ`,ヅ:`ヅ`,テ:`テ`,デ:`デ`,ト:`ト`,ド:`ド`,ナ:`ナ`,ニ:`ニ`,ヌ:`ヌ`,ネ:`ネ`,ノ:`ノ`,ハ:`ハ`,バ:`バ`,パ:`パ`,ヒ:`ヒ`,ビ:`ビ`,ピ:`ピ`,フ:`フ`,ブ:`ブ`,プ:`プ`,ヘ:`ヘ`,ベ:`ベ`,ペ:`ペ`,ホ:`ホ`,ボ:`ボ`,ポ:`ポ`,マ:`マ`,ミ:`ミ`,ム:`ム`,メ:`メ`,モ:`モ`,ャ:`ャ`,ヤ:`ヤ`,ュ:`ュ`,ユ:`ユ`,ョ:`ョ`,ヨ:`ヨ`,ラ:`ラ`,リ:`リ`,ル:`ル`,レ:`レ`,ロ:`ロ`,ワ:`ワ`,ヰ:`イ`,ヱ:`エ`,ヲ:`ヲ`,ヺ:`ヺ`,ン:`ン`,ヴ:`ヴ`,ー:`ー`,"。":`。`,"、":`、`},n=12353,r=12436,i=12445,a=12446;function o(e){return e>=n&&e<=r||e===i||e===a}var s=class{static toKatakana(e,n){if(n===`hiragana`)return e;let r,i=``;for(let t=0;t<e.length;t+=1)r=e.charCodeAt(t),o(r)?i+=String.fromCharCode(r+96):i+=e.charAt(t);return n===`half`?i.replace(/[ァ-ヴヺー。、]/g,e=>t[e]??e):i}};function c(e){return typeof e==`string`?`"${e}"`:`the provided element`}function l(e){if(typeof e==`string`){if(!/^[[.#:]/.test(e))return document.getElementById(e);try{return document.querySelector(e)}catch{throw Error(`AutoKana: Invalid selector for ${c(e)}.`)}}return e instanceof HTMLElement?e:null}function u(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement}function d(e){let t=l(e);if(!t){let t=c(e);throw Error(`AutoKana: Element not found for ${t}. Ensure the DOM element exists before calling bind(). For Vue/React, call bind() inside onMounted()/useEffect() or after the component is mounted.`)}if(!u(t)){let t=c(e);throw Error(`AutoKana: Element must be an input or textarea for ${t}.`)}return t}function f(e){if(e===void 0||e===``)return;let t=l(e);if(t){if(!u(t))throw Error(`AutoKana: Element must be an input or textarea for ${c(e)}.`);return t}}var p=class{constructor(e,t=``,n={}){this.blurHandler=()=>{this.debug(`blur`),this.isComposing=!1},this.focusHandler=()=>{this.debug(`focus`),this.elFurigana&&(this.committedKana=this.elFurigana.value),this.isComposing=!1,this.pendingKana=[],this.lastNewInput=``,this.previousRawInput=``,this.lastConvertedInput=this.elName.value,this.processValue()},this.compositionStartHandler=()=>{this.debug(`compositionstart`),this.isComposing=!0},this.compositionEndHandler=()=>{this.debug(`compositionend`),this.isComposing=!1,this.lastNewInput=``,this.previousRawInput=``,this.processValue()},this.inputHandler=e=>{this.debug(`input`,e.isComposing),this.processValue()},this.isActive=!0,this.committedKana=``,this.furigana=``,this.isComposing=!1,this.lastConvertedInput=``,this.lastNewInput=``,this.pendingKana=[],this.previousRawInput=``,this.option=Object.assign({katakana:`hiragana`,debug:!1},n);let r=d(e),i=f(t);this.elName=r,i&&(this.elFurigana=i),this.registerEvents(this.elName)}getFurigana(){return this.furigana}start(){this.isActive=!0}stop(){this.isActive=!1}toggle(e){e?this.isActive=e.target.checked:this.isActive=!this.isActive}reset(){this.committedKana=``,this.furigana=``,this.isComposing=!1,this.lastConvertedInput=``,this.lastNewInput=``,this.pendingKana=[],this.previousRawInput=``}initializeValues(){this.reset()}registerEvents(e){e.addEventListener(`blur`,this.blurHandler),e.addEventListener(`focus`,this.focusHandler),e.addEventListener(`compositionstart`,this.compositionStartHandler),e.addEventListener(`compositionend`,this.compositionEndHandler),e.addEventListener(`input`,this.inputHandler)}setFurigana(e=!1){if(this.isActive){let t=s.toKatakana(this.committedKana+this.pendingKana.join(``),this.option.katakana),n=this.option.katakana===`half`?t.replace(/ /g,` `):t;if(!e&&n===this.furigana)return;this.furigana=n,this.elFurigana&&(this.elFurigana.value=this.furigana,this.elFurigana.dispatchEvent(new Event(`input`,{bubbles:!0}))),this.option.onChange&&this.option.onChange(this.furigana)}}extractNewInput(e){if(e.indexOf(this.lastConvertedInput)!==-1)return e.replace(this.lastConvertedInput,``);let t=this.lastConvertedInput.split(``),n=e.split(``);for(let e=0;e<t.length;e+=1)t[e]===n[e]&&(n[e]=``);return n.join(``)}detectAndCommitConversion(t){if(Math.abs(this.pendingKana.length-t.length)>1){let n=this.pendingKana.join(``),r=t.join(``);if(!r.startsWith(n)){let t=e.compact(r).split(``);Math.abs(this.pendingKana.length-t.length)>1&&this.commitPendingKana()}}else this.pendingKana.length===this.lastNewInput.length&&this.pendingKana.join(``)!==this.lastNewInput&&e.containsNonKana(this.lastNewInput)&&this.commitPendingKana()}handleCompositionInput(t){let n=e.extract(t);n.length>=this.pendingKana.length&&(this.pendingKana=n),this.setFurigana()}handleNormalInput(t,n){if(this.lastNewInput===t)return;let r=n.length<this.previousRawInput.length;this.lastNewInput=t,this.previousRawInput=n;let i=e.extract(t);if(!r){let e=this.committedKana;if(this.detectAndCommitConversion(i),this.committedKana!==e){this.lastConvertedInput=n,this.setFurigana();return}}this.pendingKana=i,this.setFurigana()}processValue(){let e=this.elName.value;if(e===``){this.reset(),this.setFurigana(!0);return}let t=this.extractNewInput(e);if(this.isComposing){this.handleCompositionInput(t);return}this.handleNormalInput(t,e)}commitPendingKana(){this.committedKana+=this.pendingKana.join(``),this.pendingKana=[]}destroy(){this.elName.removeEventListener(`blur`,this.blurHandler),this.elName.removeEventListener(`focus`,this.focusHandler),this.elName.removeEventListener(`compositionstart`,this.compositionStartHandler),this.elName.removeEventListener(`compositionend`,this.compositionEndHandler),this.elName.removeEventListener(`input`,this.inputHandler),this.elName=null,this.elFurigana=void 0}debug(...e){this.option.debug&&console.log(...e)}};function m(e,t,n={}){return new p(e,t,n)}exports.AutoKana=p,exports.KanaConverter=s,exports.KanaExtractor=e,exports.bind=m;
@@ -0,0 +1,268 @@
1
+ //#region src/KanaExtractor.ts
2
+ var e = class {
3
+ static {
4
+ this.EXTRACTION_PATTERN = /[^  ぁあ-んゔー]/g;
5
+ }
6
+ static {
7
+ this.COMPACTING_PATTERN = /[ぁぃぅぇぉっゃゅょ]/g;
8
+ }
9
+ static extract(e) {
10
+ return e.replace(this.EXTRACTION_PATTERN, "").split("");
11
+ }
12
+ static compact(e) {
13
+ return e.replace(this.COMPACTING_PATTERN, "");
14
+ }
15
+ static containsNonKana(e) {
16
+ return e.search(this.EXTRACTION_PATTERN) !== -1;
17
+ }
18
+ }, t = {
19
+ ァ: "ァ",
20
+ ア: "ア",
21
+ ィ: "ィ",
22
+ イ: "イ",
23
+ ゥ: "ゥ",
24
+ ウ: "ウ",
25
+ ェ: "ェ",
26
+ エ: "エ",
27
+ ォ: "ォ",
28
+ オ: "オ",
29
+ カ: "カ",
30
+ ガ: "ガ",
31
+ キ: "キ",
32
+ ギ: "ギ",
33
+ ク: "ク",
34
+ グ: "グ",
35
+ ケ: "ケ",
36
+ ゲ: "ゲ",
37
+ コ: "コ",
38
+ ゴ: "ゴ",
39
+ サ: "サ",
40
+ ザ: "ザ",
41
+ シ: "シ",
42
+ ジ: "ジ",
43
+ ス: "ス",
44
+ ズ: "ズ",
45
+ セ: "セ",
46
+ ゼ: "ゼ",
47
+ ソ: "ソ",
48
+ ゾ: "ゾ",
49
+ タ: "タ",
50
+ ダ: "ダ",
51
+ チ: "チ",
52
+ ヂ: "ヂ",
53
+ ッ: "ッ",
54
+ ツ: "ツ",
55
+ ヅ: "ヅ",
56
+ テ: "テ",
57
+ デ: "デ",
58
+ ト: "ト",
59
+ ド: "ド",
60
+ ナ: "ナ",
61
+ ニ: "ニ",
62
+ ヌ: "ヌ",
63
+ ネ: "ネ",
64
+ ノ: "ノ",
65
+ ハ: "ハ",
66
+ バ: "バ",
67
+ パ: "パ",
68
+ ヒ: "ヒ",
69
+ ビ: "ビ",
70
+ ピ: "ピ",
71
+ フ: "フ",
72
+ ブ: "ブ",
73
+ プ: "プ",
74
+ ヘ: "ヘ",
75
+ ベ: "ベ",
76
+ ペ: "ペ",
77
+ ホ: "ホ",
78
+ ボ: "ボ",
79
+ ポ: "ポ",
80
+ マ: "マ",
81
+ ミ: "ミ",
82
+ ム: "ム",
83
+ メ: "メ",
84
+ モ: "モ",
85
+ ャ: "ャ",
86
+ ヤ: "ヤ",
87
+ ュ: "ュ",
88
+ ユ: "ユ",
89
+ ョ: "ョ",
90
+ ヨ: "ヨ",
91
+ ラ: "ラ",
92
+ リ: "リ",
93
+ ル: "ル",
94
+ レ: "レ",
95
+ ロ: "ロ",
96
+ ワ: "ワ",
97
+ ヰ: "イ",
98
+ ヱ: "エ",
99
+ ヲ: "ヲ",
100
+ ヺ: "ヺ",
101
+ ン: "ン",
102
+ ヴ: "ヴ",
103
+ ー: "ー",
104
+ "。": "。",
105
+ "、": "、"
106
+ }, n = 12353, r = 12436, i = 12445, a = 12446;
107
+ function o(e) {
108
+ return e >= n && e <= r || e === i || e === a;
109
+ }
110
+ var s = class {
111
+ static toKatakana(e, n) {
112
+ if (n === "hiragana") return e;
113
+ let r, i = "";
114
+ for (let t = 0; t < e.length; t += 1) r = e.charCodeAt(t), o(r) ? i += String.fromCharCode(r + 96) : i += e.charAt(t);
115
+ return n === "half" ? i.replace(/[ァ-ヴヺー。、]/g, (e) => t[e] ?? e) : i;
116
+ }
117
+ };
118
+ //#endregion
119
+ //#region src/ElementResolver.ts
120
+ function c(e) {
121
+ return typeof e == "string" ? `"${e}"` : "the provided element";
122
+ }
123
+ function l(e) {
124
+ if (typeof e == "string") {
125
+ if (!/^[[.#:]/.test(e)) return document.getElementById(e);
126
+ try {
127
+ return document.querySelector(e);
128
+ } catch {
129
+ throw Error(`AutoKana: Invalid selector for ${c(e)}.`);
130
+ }
131
+ }
132
+ return e instanceof HTMLElement ? e : null;
133
+ }
134
+ function u(e) {
135
+ return e instanceof HTMLInputElement || e instanceof HTMLTextAreaElement;
136
+ }
137
+ function d(e) {
138
+ let t = l(e);
139
+ if (!t) {
140
+ let t = c(e);
141
+ throw Error(`AutoKana: Element not found for ${t}. Ensure the DOM element exists before calling bind(). For Vue/React, call bind() inside onMounted()/useEffect() or after the component is mounted.`);
142
+ }
143
+ if (!u(t)) {
144
+ let t = c(e);
145
+ throw Error(`AutoKana: Element must be an input or textarea for ${t}.`);
146
+ }
147
+ return t;
148
+ }
149
+ //#endregion
150
+ //#region src/AutoKana.ts
151
+ function f(e) {
152
+ if (e === void 0 || e === "") return;
153
+ let t = l(e);
154
+ if (t) {
155
+ if (!u(t)) throw Error(`AutoKana: Element must be an input or textarea for ${c(e)}.`);
156
+ return t;
157
+ }
158
+ }
159
+ var p = class {
160
+ constructor(e, t = "", n = {}) {
161
+ this.blurHandler = () => {
162
+ this.debug("blur"), this.isComposing = !1;
163
+ }, this.focusHandler = () => {
164
+ this.debug("focus"), this.elFurigana && (this.committedKana = this.elFurigana.value), this.isComposing = !1, this.pendingKana = [], this.lastNewInput = "", this.previousRawInput = "", this.lastConvertedInput = this.elName.value, this.processValue();
165
+ }, this.compositionStartHandler = () => {
166
+ this.debug("compositionstart"), this.isComposing = !0;
167
+ }, this.compositionEndHandler = () => {
168
+ this.debug("compositionend"), this.isComposing = !1, this.lastNewInput = "", this.previousRawInput = "", this.processValue();
169
+ }, this.inputHandler = (e) => {
170
+ this.debug("input", e.isComposing), this.processValue();
171
+ }, this.isActive = !0, this.committedKana = "", this.furigana = "", this.isComposing = !1, this.lastConvertedInput = "", this.lastNewInput = "", this.pendingKana = [], this.previousRawInput = "", this.option = Object.assign({
172
+ katakana: "hiragana",
173
+ debug: !1
174
+ }, n);
175
+ let r = d(e), i = f(t);
176
+ this.elName = r, i && (this.elFurigana = i), this.registerEvents(this.elName);
177
+ }
178
+ getFurigana() {
179
+ return this.furigana;
180
+ }
181
+ start() {
182
+ this.isActive = !0;
183
+ }
184
+ stop() {
185
+ this.isActive = !1;
186
+ }
187
+ toggle(e) {
188
+ e ? this.isActive = e.target.checked : this.isActive = !this.isActive;
189
+ }
190
+ reset() {
191
+ this.committedKana = "", this.furigana = "", this.isComposing = !1, this.lastConvertedInput = "", this.lastNewInput = "", this.pendingKana = [], this.previousRawInput = "";
192
+ }
193
+ initializeValues() {
194
+ this.reset();
195
+ }
196
+ registerEvents(e) {
197
+ e.addEventListener("blur", this.blurHandler), e.addEventListener("focus", this.focusHandler), e.addEventListener("compositionstart", this.compositionStartHandler), e.addEventListener("compositionend", this.compositionEndHandler), e.addEventListener("input", this.inputHandler);
198
+ }
199
+ setFurigana(e = !1) {
200
+ if (this.isActive) {
201
+ let t = s.toKatakana(this.committedKana + this.pendingKana.join(""), this.option.katakana), n = this.option.katakana === "half" ? t.replace(/ /g, " ") : t;
202
+ if (!e && n === this.furigana) return;
203
+ this.furigana = n, this.elFurigana && (this.elFurigana.value = this.furigana, this.elFurigana.dispatchEvent(new Event("input", { bubbles: !0 }))), this.option.onChange && this.option.onChange(this.furigana);
204
+ }
205
+ }
206
+ extractNewInput(e) {
207
+ if (e.indexOf(this.lastConvertedInput) !== -1) return e.replace(this.lastConvertedInput, "");
208
+ let t = this.lastConvertedInput.split(""), n = e.split("");
209
+ for (let e = 0; e < t.length; e += 1) t[e] === n[e] && (n[e] = "");
210
+ return n.join("");
211
+ }
212
+ detectAndCommitConversion(t) {
213
+ if (Math.abs(this.pendingKana.length - t.length) > 1) {
214
+ let n = this.pendingKana.join(""), r = t.join("");
215
+ if (!r.startsWith(n)) {
216
+ let t = e.compact(r).split("");
217
+ Math.abs(this.pendingKana.length - t.length) > 1 && this.commitPendingKana();
218
+ }
219
+ } else this.pendingKana.length === this.lastNewInput.length && this.pendingKana.join("") !== this.lastNewInput && e.containsNonKana(this.lastNewInput) && this.commitPendingKana();
220
+ }
221
+ handleCompositionInput(t) {
222
+ let n = e.extract(t);
223
+ n.length >= this.pendingKana.length && (this.pendingKana = n), this.setFurigana();
224
+ }
225
+ handleNormalInput(t, n) {
226
+ if (this.lastNewInput === t) return;
227
+ let r = n.length < this.previousRawInput.length;
228
+ this.lastNewInput = t, this.previousRawInput = n;
229
+ let i = e.extract(t);
230
+ if (!r) {
231
+ let e = this.committedKana;
232
+ if (this.detectAndCommitConversion(i), this.committedKana !== e) {
233
+ this.lastConvertedInput = n, this.setFurigana();
234
+ return;
235
+ }
236
+ }
237
+ this.pendingKana = i, this.setFurigana();
238
+ }
239
+ processValue() {
240
+ let e = this.elName.value;
241
+ if (e === "") {
242
+ this.reset(), this.setFurigana(!0);
243
+ return;
244
+ }
245
+ let t = this.extractNewInput(e);
246
+ if (this.isComposing) {
247
+ this.handleCompositionInput(t);
248
+ return;
249
+ }
250
+ this.handleNormalInput(t, e);
251
+ }
252
+ commitPendingKana() {
253
+ this.committedKana += this.pendingKana.join(""), this.pendingKana = [];
254
+ }
255
+ destroy() {
256
+ this.elName.removeEventListener("blur", this.blurHandler), this.elName.removeEventListener("focus", this.focusHandler), this.elName.removeEventListener("compositionstart", this.compositionStartHandler), this.elName.removeEventListener("compositionend", this.compositionEndHandler), this.elName.removeEventListener("input", this.inputHandler), this.elName = null, this.elFurigana = void 0;
257
+ }
258
+ debug(...e) {
259
+ this.option.debug && console.log(...e);
260
+ }
261
+ };
262
+ //#endregion
263
+ //#region src/index.ts
264
+ function m(e, t, n = {}) {
265
+ return new p(e, t, n);
266
+ }
267
+ //#endregion
268
+ export { p as AutoKana, s as KanaConverter, e as KanaExtractor, m as bind };
@@ -0,0 +1 @@
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.AutoKana={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class{static{this.EXTRACTION_PATTERN=/[^  ぁあ-んゔー]/g}static{this.COMPACTING_PATTERN=/[ぁぃぅぇぉっゃゅょ]/g}static extract(e){return e.replace(this.EXTRACTION_PATTERN,``).split(``)}static compact(e){return e.replace(this.COMPACTING_PATTERN,``)}static containsNonKana(e){return e.search(this.EXTRACTION_PATTERN)!==-1}},n={ァ:`ァ`,ア:`ア`,ィ:`ィ`,イ:`イ`,ゥ:`ゥ`,ウ:`ウ`,ェ:`ェ`,エ:`エ`,ォ:`ォ`,オ:`オ`,カ:`カ`,ガ:`ガ`,キ:`キ`,ギ:`ギ`,ク:`ク`,グ:`グ`,ケ:`ケ`,ゲ:`ゲ`,コ:`コ`,ゴ:`ゴ`,サ:`サ`,ザ:`ザ`,シ:`シ`,ジ:`ジ`,ス:`ス`,ズ:`ズ`,セ:`セ`,ゼ:`ゼ`,ソ:`ソ`,ゾ:`ゾ`,タ:`タ`,ダ:`ダ`,チ:`チ`,ヂ:`ヂ`,ッ:`ッ`,ツ:`ツ`,ヅ:`ヅ`,テ:`テ`,デ:`デ`,ト:`ト`,ド:`ド`,ナ:`ナ`,ニ:`ニ`,ヌ:`ヌ`,ネ:`ネ`,ノ:`ノ`,ハ:`ハ`,バ:`バ`,パ:`パ`,ヒ:`ヒ`,ビ:`ビ`,ピ:`ピ`,フ:`フ`,ブ:`ブ`,プ:`プ`,ヘ:`ヘ`,ベ:`ベ`,ペ:`ペ`,ホ:`ホ`,ボ:`ボ`,ポ:`ポ`,マ:`マ`,ミ:`ミ`,ム:`ム`,メ:`メ`,モ:`モ`,ャ:`ャ`,ヤ:`ヤ`,ュ:`ュ`,ユ:`ユ`,ョ:`ョ`,ヨ:`ヨ`,ラ:`ラ`,リ:`リ`,ル:`ル`,レ:`レ`,ロ:`ロ`,ワ:`ワ`,ヰ:`イ`,ヱ:`エ`,ヲ:`ヲ`,ヺ:`ヺ`,ン:`ン`,ヴ:`ヴ`,ー:`ー`,"。":`。`,"、":`、`},r=12353,i=12436,a=12445,o=12446;function s(e){return e>=r&&e<=i||e===a||e===o}var c=class{static toKatakana(e,t){if(t===`hiragana`)return e;let r,i=``;for(let t=0;t<e.length;t+=1)r=e.charCodeAt(t),s(r)?i+=String.fromCharCode(r+96):i+=e.charAt(t);return t===`half`?i.replace(/[ァ-ヴヺー。、]/g,e=>n[e]??e):i}};function l(e){return typeof e==`string`?`"${e}"`:`the provided element`}function u(e){if(typeof e==`string`){if(!/^[[.#:]/.test(e))return document.getElementById(e);try{return document.querySelector(e)}catch{throw Error(`AutoKana: Invalid selector for ${l(e)}.`)}}return e instanceof HTMLElement?e:null}function d(e){return e instanceof HTMLInputElement||e instanceof HTMLTextAreaElement}function f(e){let t=u(e);if(!t){let t=l(e);throw Error(`AutoKana: Element not found for ${t}. Ensure the DOM element exists before calling bind(). For Vue/React, call bind() inside onMounted()/useEffect() or after the component is mounted.`)}if(!d(t)){let t=l(e);throw Error(`AutoKana: Element must be an input or textarea for ${t}.`)}return t}function p(e){if(e===void 0||e===``)return;let t=u(e);if(t){if(!d(t))throw Error(`AutoKana: Element must be an input or textarea for ${l(e)}.`);return t}}var m=class{constructor(e,t=``,n={}){this.blurHandler=()=>{this.debug(`blur`),this.isComposing=!1},this.focusHandler=()=>{this.debug(`focus`),this.elFurigana&&(this.committedKana=this.elFurigana.value),this.isComposing=!1,this.pendingKana=[],this.lastNewInput=``,this.previousRawInput=``,this.lastConvertedInput=this.elName.value,this.processValue()},this.compositionStartHandler=()=>{this.debug(`compositionstart`),this.isComposing=!0},this.compositionEndHandler=()=>{this.debug(`compositionend`),this.isComposing=!1,this.lastNewInput=``,this.previousRawInput=``,this.processValue()},this.inputHandler=e=>{this.debug(`input`,e.isComposing),this.processValue()},this.isActive=!0,this.committedKana=``,this.furigana=``,this.isComposing=!1,this.lastConvertedInput=``,this.lastNewInput=``,this.pendingKana=[],this.previousRawInput=``,this.option=Object.assign({katakana:`hiragana`,debug:!1},n);let r=f(e),i=p(t);this.elName=r,i&&(this.elFurigana=i),this.registerEvents(this.elName)}getFurigana(){return this.furigana}start(){this.isActive=!0}stop(){this.isActive=!1}toggle(e){e?this.isActive=e.target.checked:this.isActive=!this.isActive}reset(){this.committedKana=``,this.furigana=``,this.isComposing=!1,this.lastConvertedInput=``,this.lastNewInput=``,this.pendingKana=[],this.previousRawInput=``}initializeValues(){this.reset()}registerEvents(e){e.addEventListener(`blur`,this.blurHandler),e.addEventListener(`focus`,this.focusHandler),e.addEventListener(`compositionstart`,this.compositionStartHandler),e.addEventListener(`compositionend`,this.compositionEndHandler),e.addEventListener(`input`,this.inputHandler)}setFurigana(e=!1){if(this.isActive){let t=c.toKatakana(this.committedKana+this.pendingKana.join(``),this.option.katakana),n=this.option.katakana===`half`?t.replace(/ /g,` `):t;if(!e&&n===this.furigana)return;this.furigana=n,this.elFurigana&&(this.elFurigana.value=this.furigana,this.elFurigana.dispatchEvent(new Event(`input`,{bubbles:!0}))),this.option.onChange&&this.option.onChange(this.furigana)}}extractNewInput(e){if(e.indexOf(this.lastConvertedInput)!==-1)return e.replace(this.lastConvertedInput,``);let t=this.lastConvertedInput.split(``),n=e.split(``);for(let e=0;e<t.length;e+=1)t[e]===n[e]&&(n[e]=``);return n.join(``)}detectAndCommitConversion(e){if(Math.abs(this.pendingKana.length-e.length)>1){let n=this.pendingKana.join(``),r=e.join(``);if(!r.startsWith(n)){let e=t.compact(r).split(``);Math.abs(this.pendingKana.length-e.length)>1&&this.commitPendingKana()}}else this.pendingKana.length===this.lastNewInput.length&&this.pendingKana.join(``)!==this.lastNewInput&&t.containsNonKana(this.lastNewInput)&&this.commitPendingKana()}handleCompositionInput(e){let n=t.extract(e);n.length>=this.pendingKana.length&&(this.pendingKana=n),this.setFurigana()}handleNormalInput(e,n){if(this.lastNewInput===e)return;let r=n.length<this.previousRawInput.length;this.lastNewInput=e,this.previousRawInput=n;let i=t.extract(e);if(!r){let e=this.committedKana;if(this.detectAndCommitConversion(i),this.committedKana!==e){this.lastConvertedInput=n,this.setFurigana();return}}this.pendingKana=i,this.setFurigana()}processValue(){let e=this.elName.value;if(e===``){this.reset(),this.setFurigana(!0);return}let t=this.extractNewInput(e);if(this.isComposing){this.handleCompositionInput(t);return}this.handleNormalInput(t,e)}commitPendingKana(){this.committedKana+=this.pendingKana.join(``),this.pendingKana=[]}destroy(){this.elName.removeEventListener(`blur`,this.blurHandler),this.elName.removeEventListener(`focus`,this.focusHandler),this.elName.removeEventListener(`compositionstart`,this.compositionStartHandler),this.elName.removeEventListener(`compositionend`,this.compositionEndHandler),this.elName.removeEventListener(`input`,this.inputHandler),this.elName=null,this.elFurigana=void 0}debug(...e){this.option.debug&&console.log(...e)}};function h(e,t,n={}){return new m(e,t,n)}e.AutoKana=m,e.KanaConverter=c,e.KanaExtractor=t,e.bind=h});
@@ -0,0 +1,14 @@
1
+ import { default as AutoKana, AutoKanaOption, Bindable, KatakanaOption } from './AutoKana.cjs';
2
+ import { KanaConverter } from './KanaConverter.cjs';
3
+ import { KanaExtractor } from './KanaExtractor.cjs';
4
+ /**
5
+ * Bind elements to AutoKana.
6
+ *
7
+ * @param name Selector string starting with `#`, `.`, `[`, or `:`, or an element of the name input. Bare ID strings are also supported.
8
+ * @param furigana Selector string starting with `#`, `.`, `[`, or `:`, or an element of the furigana output input. Optional. Bare ID strings are also supported.
9
+ * @param option Option.
10
+ * @returns An AutoKana instance.
11
+ */
12
+ export declare function bind(name: Bindable, furigana?: Bindable, option?: AutoKanaOption): AutoKana;
13
+ export { AutoKana, KanaConverter, KanaExtractor };
14
+ export type { AutoKanaOption, Bindable, KatakanaOption };
@@ -0,0 +1,14 @@
1
+ import { default as AutoKana, AutoKanaOption, Bindable, KatakanaOption } from './AutoKana.js';
2
+ import { KanaConverter } from './KanaConverter.js';
3
+ import { KanaExtractor } from './KanaExtractor.js';
4
+ /**
5
+ * Bind elements to AutoKana.
6
+ *
7
+ * @param name Selector string starting with `#`, `.`, `[`, or `:`, or an element of the name input. Bare ID strings are also supported.
8
+ * @param furigana Selector string starting with `#`, `.`, `[`, or `:`, or an element of the furigana output input. Optional. Bare ID strings are also supported.
9
+ * @param option Option.
10
+ * @returns An AutoKana instance.
11
+ */
12
+ export declare function bind(name: Bindable, furigana?: Bindable, option?: AutoKanaOption): AutoKana;
13
+ export { AutoKana, KanaConverter, KanaExtractor };
14
+ export type { AutoKanaOption, Bindable, KatakanaOption };
@@ -0,0 +1 @@
1
+ export declare const fullToHalfKatakanaMap: Record<string, string>;
@@ -0,0 +1 @@
1
+ export declare const fullToHalfKatakanaMap: Record<string, string>;
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@j1nn0/vanilla-autokana",
3
+ "version": "2.0.0",
4
+ "description": "A JavaScript library to complete furigana automatically (forked from ryo-utsunomiya/vanilla-autokana).",
5
+ "author": "j1nn0 <j1nn0.github@gmail.com>",
6
+ "contributors": [
7
+ "j1nn0 <j1nn0.github@gmail.com>",
8
+ "Ryo Utsunomiya <millionsnowliving@gmail.com>"
9
+ ],
10
+ "license": "MIT",
11
+ "main": "dist/autokana.cjs",
12
+ "module": "dist/autokana.es.js",
13
+ "types": "dist/index.d.ts",
14
+ "type": "module",
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "import": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/autokana.es.js"
23
+ },
24
+ "require": {
25
+ "types": "./dist/index.d.cts",
26
+ "default": "./dist/autokana.cjs"
27
+ }
28
+ }
29
+ },
30
+ "sideEffects": false,
31
+ "engines": {
32
+ "node": ">=24",
33
+ "pnpm": ">=10"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/j1nn0/vanilla-autokana.git"
38
+ },
39
+ "bugs": {
40
+ "url": "https://github.com/j1nn0/vanilla-autokana/issues"
41
+ },
42
+ "homepage": "https://github.com/j1nn0/vanilla-autokana#readme",
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "provenance": true
46
+ },
47
+ "devDependencies": {
48
+ "@storybook/html": "^10.4.2",
49
+ "@storybook/html-vite": "^10.4.2",
50
+ "@types/node": "^25.9.2",
51
+ "@types/react": "^19.2.17",
52
+ "@types/react-dom": "^19.2.3",
53
+ "@vitejs/plugin-react": "^6.0.2",
54
+ "@vitest/coverage-v8": "4.1.8",
55
+ "jsdom": "^29.1.1",
56
+ "oxfmt": "^0.53.0",
57
+ "oxlint": "^1.68.0",
58
+ "react": "^19.2.7",
59
+ "react-dom": "^19.2.7",
60
+ "storybook": "^10.4.2",
61
+ "typescript": "^6.0.2",
62
+ "unplugin-dts": "^1.0.2",
63
+ "vite": "^8.0.16",
64
+ "vitest": "^4.1.8",
65
+ "vue": "^3.5.35"
66
+ },
67
+ "scripts": {
68
+ "build": "vite build && node scripts/prepare-cjs-types.mjs",
69
+ "watch": "vite build --watch",
70
+ "lint": "oxlint src __tests__",
71
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.build.json",
72
+ "format": "oxfmt --write src",
73
+ "test": "vitest",
74
+ "test:coverage": "vitest run --coverage",
75
+ "verify:exports": "node scripts/verify-package-exports.mjs",
76
+ "ci": "oxlint src __tests__ && tsc --noEmit && tsc --noEmit -p tsconfig.build.json && vitest run --coverage && vite build && node scripts/prepare-cjs-types.mjs && node scripts/verify-package-exports.mjs",
77
+ "storybook": "storybook dev -p 6006",
78
+ "build-storybook": "storybook build"
79
+ }
80
+ }