Skip to main content
インベントリに戻る
vanilla-autokana デモ
📦

vanilla-autokana デモ

2024レア

vanilla-autokanaライブラリを使ったふりがな自動入力デモ。setIntervalポーリング+value基盤のひらがなフィルタリング方式。

使用技術

ReactTypeScriptvanilla-autokana
デモ
性(せい)
名(めい)
ふりがな結果
ふりがな結果
useState: {"lastName":"","firstName":"","lastNameFurigana":"","firstNameFurigana":""}
ソースコード
1"use client";
2
3import { useState, useEffect, useRef, useCallback } from "react";
4import { useLanguage } from "@/context/LanguageContext";
5
6interface AutoKanaInstance {
7 getFurigana: () => string;
8 start: () => void;
9 stop: () => void;
10}
11
12interface FormState {
13 lastName: string;
14 firstName: string;
15 lastNameFurigana: string;
16 firstNameFurigana: string;
17}
18
19const initialState: FormState = {
20 lastName: "",
21 firstName: "",
22 lastNameFurigana: "",
23 firstNameFurigana: "",
24};
25
26export function AutoKanaDemo() {
27 const { t } = useLanguage();
28 const [katakana, setKatakana] = useState(false);
29 const [form, setForm] = useState<FormState>(initialState);
30 const lastNameRef = useRef<AutoKanaInstance | null>(null);
31 const firstNameRef = useRef<AutoKanaInstance | null>(null);
32 const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);
33
34 useEffect(() => {
35 let cancelled = false;
36
37 async function init() {
38 const mod = await import("vanilla-autokana");
39 const bind = mod.bind || mod.default?.bind;
40 if (cancelled || !bind) return;
41
42 lastNameRef.current = bind(
43 "#autokana-lastname",
44 "#autokana-lastname-furigana",
45 { katakana }
46 );
47 firstNameRef.current = bind(
48 "#autokana-firstname",
49 "#autokana-firstname-furigana",
50 { katakana }
51 );
52
53 timerRef.current = setInterval(() => {
54 const lastFuri = lastNameRef.current?.getFurigana() ?? "";
55 const firstFuri = firstNameRef.current?.getFurigana() ?? "";
56 setForm((prev) => {
57 if (
58 prev.lastNameFurigana === lastFuri &&
59 prev.firstNameFurigana === firstFuri
60 ) {
61 return prev;
62 }
63 return {
64 ...prev,
65 lastNameFurigana: lastFuri,
66 firstNameFurigana: firstFuri,
67 };
68 });
69 }, 50);
70 }
71
72 init();
73
74 return () => {
75 cancelled = true;
76 if (timerRef.current) clearInterval(timerRef.current);
77 lastNameRef.current = null;
78 firstNameRef.current = null;
79 };
80 }, [katakana]);
81
82 const handleReset = useCallback(() => {
83 setForm(initialState);
84 const els = [
85 "autokana-lastname", "autokana-firstname",
86 "autokana-lastname-furigana", "autokana-firstname-furigana",
87 ];
88 for (const id of els) {
89 const el = document.getElementById(id) as HTMLInputElement | null;
90 if (el) el.value = "";
91 }
92 }, []);
93
94 const handleKatakanaToggle = useCallback(() => {
95 setKatakana((prev) => !prev);
96 handleReset();
97 }, [handleReset]);
98
99 return (
100 <div className="space-y-4">
101 <div className="grid grid-cols-2 gap-3">
102 <div className="space-y-1">
103 <span>{t.inventory.lastName}</span>
104 <input id="autokana-lastname" type="text" value={form.lastName}
105 onChange={(e) => setForm((prev) => ({ ...prev, lastName: e.target.value }))} />
106 </div>
107 <div className="space-y-1">
108 <span>{t.inventory.firstName}</span>
109 <input id="autokana-firstname" type="text" value={form.firstName}
110 onChange={(e) => setForm((prev) => ({ ...prev, firstName: e.target.value }))} />
111 </div>
112 </div>
113 <div className="grid grid-cols-2 gap-3">
114 <input id="autokana-lastname-furigana" type="text" value={form.lastNameFurigana}
115 onChange={(e) => setForm((prev) => ({ ...prev, lastNameFurigana: e.target.value }))} />
116 <input id="autokana-firstname-furigana" type="text" value={form.firstNameFurigana}
117 onChange={(e) => setForm((prev) => ({ ...prev, firstNameFurigana: e.target.value }))} />
118 </div>
119 <div>{JSON.stringify(form)}</div>
120 <div>
121 <button onClick={handleKatakanaToggle}>{t.inventory.katakanaMode}</button>
122 <button onClick={handleReset}>{t.inventory.reset}</button>
123 </div>
124 </div>
125 );
126}