text-input-guard 1.0.0 → 1.0.2
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/cjs/text-input-guard.cjs +62 -11
- package/dist/cjs/text-input-guard.min.cjs +1 -1
- package/dist/esm/text-input-guard.js +62 -11
- package/dist/esm/text-input-guard.min.js +1 -1
- package/dist/umd/text-input-guard.js +62 -11
- package/dist/umd/text-input-guard.min.js +1 -1
- package/package.json +1 -1
|
@@ -118,11 +118,16 @@
|
|
|
118
118
|
|
|
119
119
|
const UI_ATTRS = [
|
|
120
120
|
"placeholder",
|
|
121
|
+
"list",
|
|
121
122
|
"inputmode",
|
|
122
123
|
"autocomplete",
|
|
124
|
+
"autocapitalize",
|
|
125
|
+
"autocorrect",
|
|
123
126
|
"minlength",
|
|
124
127
|
"maxlength",
|
|
128
|
+
"size",
|
|
125
129
|
"pattern",
|
|
130
|
+
"dir",
|
|
126
131
|
"title",
|
|
127
132
|
"tabindex",
|
|
128
133
|
"style",
|
|
@@ -154,6 +159,7 @@
|
|
|
154
159
|
|
|
155
160
|
for (const [k, v] of Object.entries(input.dataset)) {
|
|
156
161
|
if (k.startsWith("tig")) { continue; }
|
|
162
|
+
if (v == null) { continue; }
|
|
157
163
|
this.originalDataset[k] = v;
|
|
158
164
|
}
|
|
159
165
|
}
|
|
@@ -574,7 +580,7 @@
|
|
|
574
580
|
|
|
575
581
|
/**
|
|
576
582
|
* attach時に登録されたバリデーション結果コールバック
|
|
577
|
-
* @type {(result: ValidateResult) => void | undefined}
|
|
583
|
+
* @type {((result: ValidateResult) => void) | undefined}
|
|
578
584
|
*/
|
|
579
585
|
this.onValidate = options.onValidate;
|
|
580
586
|
|
|
@@ -735,6 +741,11 @@
|
|
|
735
741
|
*/
|
|
736
742
|
this.beforeInputSnapshot = null;
|
|
737
743
|
|
|
744
|
+
/**
|
|
745
|
+
* onBeforeInput イベントが発生したか否か
|
|
746
|
+
*/
|
|
747
|
+
this.existBeforeInputEvent = false;
|
|
748
|
+
|
|
738
749
|
/**
|
|
739
750
|
* ルールからのrevert要求
|
|
740
751
|
* @type {RevertRequest|null}
|
|
@@ -752,7 +763,7 @@
|
|
|
752
763
|
this.applySeparateValue();
|
|
753
764
|
this.bindEvents();
|
|
754
765
|
// 初期値を評価
|
|
755
|
-
this.
|
|
766
|
+
this.evaluateCommit();
|
|
756
767
|
}
|
|
757
768
|
|
|
758
769
|
/**
|
|
@@ -991,12 +1002,12 @@
|
|
|
991
1002
|
*/
|
|
992
1003
|
createCtx({ useSnapshot = true } = {}) {
|
|
993
1004
|
const snap = useSnapshot ? this.beforeInputSnapshot : null;
|
|
994
|
-
|
|
995
|
-
|
|
1005
|
+
let inputType = snap?.inputType ?? "";
|
|
1006
|
+
let insertedText = snap?.insertedText ?? "";
|
|
996
1007
|
|
|
997
1008
|
// 受理済み(正規化済み)の全文を「今回の編集の基準」として使う
|
|
998
1009
|
// display.value はブラウザ側の編集結果が混ざるので、差分再構成の基準にはしない
|
|
999
|
-
|
|
1010
|
+
let beforeText = this.lastAcceptedValue ?? "";
|
|
1000
1011
|
|
|
1001
1012
|
// selection は2系統ある:
|
|
1002
1013
|
// - snapSel: beforeinput 時点で取得した selection(今回の編集の基準点になり得る)
|
|
@@ -1032,6 +1043,38 @@
|
|
|
1032
1043
|
baseSel = lastSel;
|
|
1033
1044
|
}
|
|
1034
1045
|
|
|
1046
|
+
// beforeinput がない環境では、差分再構成の基準が「前回の受理値」しかないため、そこから今回の編集内容を推測する必要がある。
|
|
1047
|
+
if (beforeText.length === 0 || !this.existBeforeInputEvent) {
|
|
1048
|
+
const display = /** @type {HTMLInputElement|HTMLTextAreaElement} */ (this.displayElement);
|
|
1049
|
+
const current = display.value;
|
|
1050
|
+
// 前回の値がとれないものの、何かしら入力情報がある状態
|
|
1051
|
+
if (current.length > 0) {
|
|
1052
|
+
// 文字列の先頭が前回の受理値と同じなら、末尾に何かしら入力されたと考えられる(オートコンプリート等)
|
|
1053
|
+
if (current.toLocaleLowerCase().startsWith(beforeText.toLocaleLowerCase())) {
|
|
1054
|
+
if (!current.startsWith(beforeText)) {
|
|
1055
|
+
// 文字は同じだが、大文字と小文字の情報が替わっているなどのパターン
|
|
1056
|
+
// 差し代わりが起きているため、前回値は基準にならないと判断して、差分全体を insertedText とする
|
|
1057
|
+
beforeText = "";
|
|
1058
|
+
insertedText = current;
|
|
1059
|
+
} else {
|
|
1060
|
+
// 末尾に追加されたと考えられる部分を insertedText とする
|
|
1061
|
+
// 例: beforeText="abc" → current="abcde" なら、"de" が insertedText
|
|
1062
|
+
insertedText = current.slice(beforeText.length);
|
|
1063
|
+
}
|
|
1064
|
+
// キャレットは前回値の末尾にあると推測する
|
|
1065
|
+
baseSel = /** @type {SelectionState} */ {
|
|
1066
|
+
start: beforeText.length,
|
|
1067
|
+
end: beforeText.length,
|
|
1068
|
+
direction: "none"
|
|
1069
|
+
};
|
|
1070
|
+
inputType = "insertText";
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
// existBeforeInputEvent は、少なくとも1回 beforeinput が発生したかどうかのフラグ
|
|
1075
|
+
// これが false の場合、上記のような「beforeinputがない環境での推測ロジック」を走らせる。
|
|
1076
|
+
this.existBeforeInputEvent = false;
|
|
1077
|
+
|
|
1035
1078
|
let replaceStart = baseSel.start ?? 0;
|
|
1036
1079
|
let replaceEnd = baseSel.end ?? 0;
|
|
1037
1080
|
|
|
@@ -1044,10 +1087,10 @@
|
|
|
1044
1087
|
if (inputType === "deleteContentBackward") {
|
|
1045
1088
|
// Backspace: キャレットの左側1文字を削除
|
|
1046
1089
|
replaceStart = Math.max(0, replaceStart - 1);
|
|
1047
|
-
replaceEnd = snapSel
|
|
1090
|
+
replaceEnd = snapSel?.start ?? replaceEnd;
|
|
1048
1091
|
} else if (inputType === "deleteContentForward") {
|
|
1049
1092
|
// Delete: キャレットの右側1文字を削除
|
|
1050
|
-
replaceStart = snapSel
|
|
1093
|
+
replaceStart = snapSel?.start ?? replaceStart;
|
|
1051
1094
|
replaceEnd = Math.min(beforeText.length, replaceEnd + 1);
|
|
1052
1095
|
}
|
|
1053
1096
|
// 追加で拾うならここ:
|
|
@@ -1254,16 +1297,23 @@
|
|
|
1254
1297
|
// console.log("[text-input-guard] input");
|
|
1255
1298
|
// compositionend後に input が来た場合、フォールバックを無効化
|
|
1256
1299
|
this.pendingCompositionCommit = false;
|
|
1257
|
-
|
|
1300
|
+
try {
|
|
1301
|
+
this.evaluateInput();
|
|
1302
|
+
} finally {
|
|
1303
|
+
this.existBeforeInputEvent = false;
|
|
1304
|
+
}
|
|
1258
1305
|
}
|
|
1259
1306
|
|
|
1260
1307
|
/**
|
|
1261
1308
|
* beforeinput:入力が反映される直前に呼ばれる
|
|
1262
1309
|
* - ここでの value/selection が「今回の編集の基準点」になる
|
|
1263
|
-
* @param {
|
|
1310
|
+
* @param {Event} e
|
|
1264
1311
|
* @returns {void}
|
|
1265
1312
|
*/
|
|
1266
1313
|
onBeforeInput(e) {
|
|
1314
|
+
if (!(e instanceof InputEvent)) {
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1267
1317
|
const el = /** @type {HTMLInputElement|HTMLTextAreaElement} */ (this.displayElement);
|
|
1268
1318
|
// 現時点(反映前)の選択範囲
|
|
1269
1319
|
const selection = this.readSelection(el);
|
|
@@ -1271,6 +1321,7 @@
|
|
|
1271
1321
|
const inputType = typeof e.inputType === "string" ? e.inputType : null;
|
|
1272
1322
|
/** @type {string|null} */
|
|
1273
1323
|
const insertedText = typeof e.data === "string" ? e.data : null;
|
|
1324
|
+
this.existBeforeInputEvent = true;
|
|
1274
1325
|
this.beforeInputSnapshot = { selection, inputType, insertedText };
|
|
1275
1326
|
}
|
|
1276
1327
|
|
|
@@ -7441,11 +7492,11 @@
|
|
|
7441
7492
|
|
|
7442
7493
|
/**
|
|
7443
7494
|
* バージョン(ビルド時に置換したいならここを差し替える)
|
|
7444
|
-
* 例: rollup replace で ""1.0.
|
|
7495
|
+
* 例: rollup replace で ""1.0.2"" を package.json の version に置換
|
|
7445
7496
|
*/
|
|
7446
7497
|
// @ts-ignore
|
|
7447
7498
|
// eslint-disable-next-line no-undef
|
|
7448
|
-
const version = "1.0.
|
|
7499
|
+
const version = "1.0.2" ;
|
|
7449
7500
|
|
|
7450
7501
|
exports.ascii = ascii;
|
|
7451
7502
|
exports.attach = attach;
|