what-input 5.2.11 → 6.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/README.md +253 -60
- package/dist/what-input.d.mts +88 -0
- package/dist/what-input.d.ts +88 -0
- package/dist/what-input.js +296 -512
- package/dist/what-input.min.js +17 -2
- package/dist/what-input.min.js.map +7 -1
- package/dist/what-input.mjs +284 -0
- package/package.json +51 -30
- package/.browserslistrc +0 -5
- package/.editorconfig +0 -12
- package/.eslintrc +0 -12
- package/.nvmrc +0 -1
- package/.prettierrc +0 -4
- package/.stylelintrc +0 -9
- package/Gulpfile.js +0 -178
- package/src/images/select-arrow.svg +0 -1
- package/src/markup/index.html +0 -141
- package/src/scripts/what-input.d.ts +0 -15
- package/src/scripts/what-input.js +0 -482
- package/src/styles/_html.scss +0 -49
- package/src/styles/_layout.scss +0 -229
- package/src/styles/_mixins.scss +0 -70
- package/src/styles/_variables.scss +0 -2
- package/src/styles/index.scss +0 -51
package/dist/what-input.js
CHANGED
|
@@ -1,517 +1,301 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* what-input - A global utility for tracking the current input method (mouse, keyboard or touch).
|
|
3
|
-
* @version
|
|
3
|
+
* @version v6.0.0
|
|
4
4
|
* @link https://github.com/ten1seven/what-input
|
|
5
5
|
* @license MIT
|
|
6
6
|
*/
|
|
7
|
-
(function
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
fireFunctions(which);
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
// updates input intent for `mousemove` and `pointermove`
|
|
307
|
-
var setIntent = function setIntent(event) {
|
|
308
|
-
var value = inputMap[event.type];
|
|
309
|
-
|
|
310
|
-
if (value === 'pointer') {
|
|
311
|
-
value = pointerType(event);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// test to see if `mousemove` happened relative to the screen to detect scrolling versus mousemove
|
|
315
|
-
detectScrolling(event);
|
|
316
|
-
|
|
317
|
-
// only execute if scrolling isn't happening
|
|
318
|
-
if ((!isScrolling && !validateTouch(value) || isScrolling && event.type === 'wheel' || event.type === 'mousewheel' || event.type === 'DOMMouseScroll') && currentIntent !== value) {
|
|
319
|
-
currentIntent = value;
|
|
320
|
-
|
|
321
|
-
persistInput('intent', currentIntent);
|
|
322
|
-
doUpdate('intent');
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
|
|
326
|
-
var setElement = function setElement(event) {
|
|
327
|
-
if (!event.target.nodeName) {
|
|
328
|
-
// If nodeName is undefined, clear the element
|
|
329
|
-
// This can happen if click inside an <svg> element.
|
|
330
|
-
clearElement();
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
currentElement = event.target.nodeName.toLowerCase();
|
|
335
|
-
docElem.setAttribute('data-whatelement', currentElement);
|
|
336
|
-
|
|
337
|
-
if (event.target.classList && event.target.classList.length) {
|
|
338
|
-
docElem.setAttribute('data-whatclasses', event.target.classList.toString().replace(' ', ','));
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
var clearElement = function clearElement() {
|
|
343
|
-
currentElement = null;
|
|
344
|
-
|
|
345
|
-
docElem.removeAttribute('data-whatelement');
|
|
346
|
-
docElem.removeAttribute('data-whatclasses');
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
var persistInput = function persistInput(which, value) {
|
|
350
|
-
if (shouldPersist) {
|
|
351
|
-
try {
|
|
352
|
-
window.sessionStorage.setItem('what-' + which, value);
|
|
353
|
-
} catch (e) {
|
|
354
|
-
// fail silently
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
/*
|
|
360
|
-
* utilities
|
|
361
|
-
*/
|
|
362
|
-
|
|
363
|
-
var pointerType = function pointerType(event) {
|
|
364
|
-
if (typeof event.pointerType === 'number') {
|
|
365
|
-
return pointerMap[event.pointerType];
|
|
366
|
-
} else {
|
|
367
|
-
// treat pen like touch
|
|
368
|
-
return event.pointerType === 'pen' ? 'touch' : event.pointerType;
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
// prevent touch detection from being overridden by event execution order
|
|
373
|
-
var validateTouch = function validateTouch(value) {
|
|
374
|
-
var timestamp = Date.now();
|
|
375
|
-
|
|
376
|
-
var touchIsValid = value === 'mouse' && currentInput === 'touch' && timestamp - currentTimestamp < 200;
|
|
377
|
-
|
|
378
|
-
currentTimestamp = timestamp;
|
|
379
|
-
|
|
380
|
-
return touchIsValid;
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
// detect version of mouse wheel event to use
|
|
384
|
-
// via https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
|
|
385
|
-
var detectWheel = function detectWheel() {
|
|
386
|
-
var wheelType = null;
|
|
387
|
-
|
|
388
|
-
// Modern browsers support "wheel"
|
|
389
|
-
if ('onwheel' in document.createElement('div')) {
|
|
390
|
-
wheelType = 'wheel';
|
|
391
|
-
} else {
|
|
392
|
-
// Webkit and IE support at least "mousewheel"
|
|
393
|
-
// or assume that remaining browsers are older Firefox
|
|
394
|
-
wheelType = document.onmousewheel !== undefined ? 'mousewheel' : 'DOMMouseScroll';
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return wheelType;
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
// runs callback functions
|
|
401
|
-
var fireFunctions = function fireFunctions(type) {
|
|
402
|
-
for (var i = 0, len = functionList.length; i < len; i++) {
|
|
403
|
-
if (functionList[i].type === type) {
|
|
404
|
-
functionList[i].fn.call(undefined, type === 'input' ? currentInput : currentIntent);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
// finds matching element in an object
|
|
410
|
-
var objPos = function objPos(match) {
|
|
411
|
-
for (var i = 0, len = functionList.length; i < len; i++) {
|
|
412
|
-
if (functionList[i].fn === match) {
|
|
413
|
-
return i;
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
var detectScrolling = function detectScrolling(event) {
|
|
419
|
-
if (mousePos.x !== event.screenX || mousePos.y !== event.screenY) {
|
|
420
|
-
isScrolling = false;
|
|
421
|
-
|
|
422
|
-
mousePos.x = event.screenX;
|
|
423
|
-
mousePos.y = event.screenY;
|
|
424
|
-
} else {
|
|
425
|
-
isScrolling = true;
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
// manual version of `closest()`
|
|
430
|
-
var checkClosest = function checkClosest(elem, tag) {
|
|
431
|
-
var ElementPrototype = window.Element.prototype;
|
|
432
|
-
|
|
433
|
-
if (!ElementPrototype.matches) {
|
|
434
|
-
ElementPrototype.matches = ElementPrototype.msMatchesSelector || ElementPrototype.webkitMatchesSelector;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
if (!ElementPrototype.closest) {
|
|
438
|
-
do {
|
|
439
|
-
if (elem.matches(tag)) {
|
|
440
|
-
return elem;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
elem = elem.parentElement || elem.parentNode;
|
|
444
|
-
} while (elem !== null && elem.nodeType === 1);
|
|
445
|
-
|
|
446
|
-
return null;
|
|
447
|
-
} else {
|
|
448
|
-
return elem.closest(tag);
|
|
449
|
-
}
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
/*
|
|
453
|
-
* init
|
|
454
|
-
*/
|
|
455
|
-
|
|
456
|
-
// don't start script unless browser cuts the mustard
|
|
457
|
-
// (also passes if polyfills are used)
|
|
458
|
-
if ('addEventListener' in window && Array.prototype.indexOf) {
|
|
459
|
-
setUp();
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/*
|
|
463
|
-
* api
|
|
464
|
-
*/
|
|
465
|
-
|
|
466
|
-
return {
|
|
467
|
-
// returns string: the current input type
|
|
468
|
-
// opt: 'intent'|'input'
|
|
469
|
-
// 'input' (default): returns the same value as the `data-whatinput` attribute
|
|
470
|
-
// 'intent': includes `data-whatintent` value if it's different than `data-whatinput`
|
|
471
|
-
ask: function ask(opt) {
|
|
472
|
-
return opt === 'intent' ? currentIntent : currentInput;
|
|
473
|
-
},
|
|
474
|
-
|
|
475
|
-
// returns string: the currently focused element or null
|
|
476
|
-
element: function element() {
|
|
477
|
-
return currentElement;
|
|
478
|
-
},
|
|
479
|
-
|
|
480
|
-
// overwrites ignored keys with provided array
|
|
481
|
-
ignoreKeys: function ignoreKeys(arr) {
|
|
482
|
-
ignoreMap = arr;
|
|
483
|
-
},
|
|
484
|
-
|
|
485
|
-
// overwrites specific char keys to update on
|
|
486
|
-
specificKeys: function specificKeys(arr) {
|
|
487
|
-
specificMap = arr;
|
|
488
|
-
},
|
|
489
|
-
|
|
490
|
-
// attach functions to input and intent "events"
|
|
491
|
-
// funct: function to fire on change
|
|
492
|
-
// eventType: 'input'|'intent'
|
|
493
|
-
registerOnChange: function registerOnChange(fn, eventType) {
|
|
494
|
-
functionList.push({
|
|
495
|
-
fn: fn,
|
|
496
|
-
type: eventType || 'input'
|
|
497
|
-
});
|
|
498
|
-
},
|
|
499
|
-
|
|
500
|
-
unRegisterOnChange: function unRegisterOnChange(fn) {
|
|
501
|
-
var position = objPos(fn);
|
|
502
|
-
|
|
503
|
-
if (position || position === 0) {
|
|
504
|
-
functionList.splice(position, 1);
|
|
505
|
-
}
|
|
506
|
-
},
|
|
507
|
-
|
|
508
|
-
clearStorage: function clearStorage() {
|
|
509
|
-
window.sessionStorage.clear();
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
}();
|
|
513
|
-
|
|
514
|
-
/***/ })
|
|
515
|
-
/******/ ])
|
|
516
|
-
});
|
|
517
|
-
;
|
|
7
|
+
;(function (root, factory) {
|
|
8
|
+
if (typeof exports === 'object' && typeof module === 'object') {
|
|
9
|
+
module.exports = factory()
|
|
10
|
+
} else if (typeof define === 'function' && define.amd) {
|
|
11
|
+
define('whatInput', [], factory)
|
|
12
|
+
} else {
|
|
13
|
+
root.whatInput = factory()
|
|
14
|
+
}
|
|
15
|
+
})(
|
|
16
|
+
typeof globalThis !== 'undefined' ? globalThis : typeof self !== 'undefined' ? self : this,
|
|
17
|
+
function () {
|
|
18
|
+
var __whatInput
|
|
19
|
+
"use strict";
|
|
20
|
+
(() => {
|
|
21
|
+
// src/what-input.ts
|
|
22
|
+
var ATTRIBUTE_PREFIX = "data-what";
|
|
23
|
+
var STORAGE_KEYS = {
|
|
24
|
+
input: "what-input",
|
|
25
|
+
intent: "what-intent"
|
|
26
|
+
};
|
|
27
|
+
var INPUT_METHODS = /* @__PURE__ */ new Set([
|
|
28
|
+
"initial",
|
|
29
|
+
"mouse",
|
|
30
|
+
"keyboard",
|
|
31
|
+
"touch"
|
|
32
|
+
]);
|
|
33
|
+
var POINTER_TYPES = {
|
|
34
|
+
mouse: "mouse",
|
|
35
|
+
pen: "touch",
|
|
36
|
+
touch: "touch"
|
|
37
|
+
};
|
|
38
|
+
var DEFAULT_IGNORED_KEYS = [
|
|
39
|
+
"Shift",
|
|
40
|
+
"Control",
|
|
41
|
+
"Alt",
|
|
42
|
+
"Meta",
|
|
43
|
+
// Windows key / Apple command
|
|
44
|
+
"ContextMenu"
|
|
45
|
+
// Windows menu key
|
|
46
|
+
];
|
|
47
|
+
var TEXT_ENTRY_ELEMENTS = /* @__PURE__ */ new Set(["input", "select", "textarea"]);
|
|
48
|
+
var TOGGLE_INPUT_TYPES = /* @__PURE__ */ new Set(["checkbox", "radio"]);
|
|
49
|
+
var FREEZE_SELECTOR = "[data-whatfreeze]";
|
|
50
|
+
var HINT_QUERIES = {
|
|
51
|
+
touch: "(pointer: coarse)",
|
|
52
|
+
mouse: "(pointer: fine)"
|
|
53
|
+
};
|
|
54
|
+
var hasDom = () => typeof window !== "undefined" && typeof document !== "undefined";
|
|
55
|
+
var isInputMethod = (value) => typeof value === "string" && INPUT_METHODS.has(value);
|
|
56
|
+
var deepActiveElement = () => {
|
|
57
|
+
let element = document.activeElement;
|
|
58
|
+
while (element?.shadowRoot?.activeElement) {
|
|
59
|
+
element = element.shadowRoot.activeElement;
|
|
60
|
+
}
|
|
61
|
+
return element;
|
|
62
|
+
};
|
|
63
|
+
var isTextEntry = (element) => {
|
|
64
|
+
if (!element) return false;
|
|
65
|
+
const tag = element.localName;
|
|
66
|
+
if (tag === "input") return !TOGGLE_INPUT_TYPES.has(element.type);
|
|
67
|
+
if (TEXT_ENTRY_ELEMENTS.has(tag)) return true;
|
|
68
|
+
if (tag === "button" && element.closest("form") !== null) return true;
|
|
69
|
+
if (element.isContentEditable === true) return true;
|
|
70
|
+
if (element.closest(FREEZE_SELECTOR) !== null) return true;
|
|
71
|
+
return element.constructor.formAssociated === true;
|
|
72
|
+
};
|
|
73
|
+
var hintQueries = () => typeof window.matchMedia === "function" ? Object.values(HINT_QUERIES).map((query) => window.matchMedia(query)) : [];
|
|
74
|
+
var readHint = () => {
|
|
75
|
+
if (typeof window.matchMedia !== "function") return "unknown";
|
|
76
|
+
for (const [hint, query] of Object.entries(HINT_QUERIES)) {
|
|
77
|
+
if (window.matchMedia(query).matches) return hint;
|
|
78
|
+
}
|
|
79
|
+
return "unknown";
|
|
80
|
+
};
|
|
81
|
+
var eventTarget = (event) => {
|
|
82
|
+
const target = event.composedPath()[0] ?? event.target;
|
|
83
|
+
return target instanceof Element ? target : null;
|
|
84
|
+
};
|
|
85
|
+
var WhatInput = class extends EventTarget {
|
|
86
|
+
#state = {
|
|
87
|
+
input: "initial",
|
|
88
|
+
intent: "initial",
|
|
89
|
+
hint: "unknown"
|
|
90
|
+
};
|
|
91
|
+
#element = null;
|
|
92
|
+
#persist = false;
|
|
93
|
+
#ignoredKeys = DEFAULT_IGNORED_KEYS;
|
|
94
|
+
#specificKeys = [];
|
|
95
|
+
#callbacks = {
|
|
96
|
+
input: /* @__PURE__ */ new Set(),
|
|
97
|
+
intent: /* @__PURE__ */ new Set(),
|
|
98
|
+
hint: /* @__PURE__ */ new Set()
|
|
99
|
+
};
|
|
100
|
+
#controller = null;
|
|
101
|
+
#lastPointerPosition = { x: NaN, y: NaN };
|
|
102
|
+
constructor() {
|
|
103
|
+
super();
|
|
104
|
+
if (hasDom()) this.#start();
|
|
105
|
+
}
|
|
106
|
+
ask(strategy = "input") {
|
|
107
|
+
return this.#state[strategy];
|
|
108
|
+
}
|
|
109
|
+
/** The tag name of the currently focused element, or `null`. */
|
|
110
|
+
element() {
|
|
111
|
+
return this.#element;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Replaces the list of keys that are ignored (do not switch to `keyboard`)
|
|
115
|
+
* when pressed. Defaults to the modifier keys.
|
|
116
|
+
*/
|
|
117
|
+
ignoreKeys(keys) {
|
|
118
|
+
this.#ignoredKeys = [...keys];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Replaces the list of keys that are the *only* keys that switch to
|
|
122
|
+
* `keyboard`. When set, this overrides `ignoreKeys()`. Pass an empty array
|
|
123
|
+
* to restore the `ignoreKeys()` behavior.
|
|
124
|
+
*/
|
|
125
|
+
specificKeys(keys) {
|
|
126
|
+
this.#specificKeys = [...keys];
|
|
127
|
+
}
|
|
128
|
+
registerOnChange(callback, strategy = "input") {
|
|
129
|
+
this.#callbacks[strategy].add(callback);
|
|
130
|
+
}
|
|
131
|
+
/** Removes a callback added with `registerOnChange()`. */
|
|
132
|
+
unRegisterOnChange(callback) {
|
|
133
|
+
for (const callbacks of Object.values(this.#callbacks)) {
|
|
134
|
+
callbacks.delete(callback);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** Removes the persisted input and intent from session storage. */
|
|
138
|
+
clearStorage() {
|
|
139
|
+
try {
|
|
140
|
+
for (const key of Object.values(STORAGE_KEYS)) {
|
|
141
|
+
window.sessionStorage.removeItem(key);
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Stops listening, removes the `data-what*` attributes from `<html>` and
|
|
148
|
+
* drops every registered callback. Useful for tests and app teardown.
|
|
149
|
+
*/
|
|
150
|
+
destroy() {
|
|
151
|
+
this.#controller?.abort();
|
|
152
|
+
this.#controller = null;
|
|
153
|
+
for (const callbacks of Object.values(this.#callbacks)) {
|
|
154
|
+
callbacks.clear();
|
|
155
|
+
}
|
|
156
|
+
if (!hasDom()) return;
|
|
157
|
+
const html = document.documentElement;
|
|
158
|
+
for (const name of ["input", "intent", "hint", "element", "classes"]) {
|
|
159
|
+
html.removeAttribute(ATTRIBUTE_PREFIX + name);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/*
|
|
163
|
+
* set up
|
|
164
|
+
*/
|
|
165
|
+
#start() {
|
|
166
|
+
const controller = new AbortController();
|
|
167
|
+
const { signal } = controller;
|
|
168
|
+
this.#controller = controller;
|
|
169
|
+
const options = { capture: true, passive: true, signal };
|
|
170
|
+
window.addEventListener("pointerdown", this.#onPointerDown, options);
|
|
171
|
+
window.addEventListener("keydown", this.#onKey, options);
|
|
172
|
+
window.addEventListener("keyup", this.#onKey, options);
|
|
173
|
+
window.addEventListener("pointermove", this.#onPointerMove, options);
|
|
174
|
+
window.addEventListener("wheel", this.#onWheel, options);
|
|
175
|
+
window.addEventListener("focusin", this.#onFocusIn, options);
|
|
176
|
+
window.addEventListener("focusout", this.#onFocusOut, options);
|
|
177
|
+
for (const query of hintQueries()) {
|
|
178
|
+
query.addEventListener("change", this.#onHintChange, { signal });
|
|
179
|
+
}
|
|
180
|
+
if (document.readyState === "loading") {
|
|
181
|
+
document.addEventListener("DOMContentLoaded", this.#init, { once: true, signal });
|
|
182
|
+
} else {
|
|
183
|
+
this.#init();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/** Restores persisted state (if allowed) and publishes the initial state. */
|
|
187
|
+
#init = () => {
|
|
188
|
+
const { documentElement, body } = document;
|
|
189
|
+
this.#persist = documentElement.dataset.whatpersist !== "false" && body?.dataset.whatpersist !== "false";
|
|
190
|
+
if (this.#persist) {
|
|
191
|
+
for (const strategy of ["input", "intent"]) {
|
|
192
|
+
const stored = this.#restore(strategy);
|
|
193
|
+
if (stored && this.#state[strategy] === "initial") {
|
|
194
|
+
this.#state[strategy] = stored;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
this.#state.hint = readHint();
|
|
199
|
+
this.#publish("input");
|
|
200
|
+
this.#publish("intent");
|
|
201
|
+
this.#publish("hint");
|
|
202
|
+
};
|
|
203
|
+
/*
|
|
204
|
+
* events
|
|
205
|
+
*/
|
|
206
|
+
#onPointerDown = (event) => {
|
|
207
|
+
const value = POINTER_TYPES[event.pointerType];
|
|
208
|
+
if (!value) return;
|
|
209
|
+
this.#set("input", value);
|
|
210
|
+
this.#set("intent", value);
|
|
211
|
+
};
|
|
212
|
+
#onPointerMove = (event) => {
|
|
213
|
+
const value = POINTER_TYPES[event.pointerType];
|
|
214
|
+
if (!value) return;
|
|
215
|
+
const { x, y } = this.#lastPointerPosition;
|
|
216
|
+
this.#lastPointerPosition = { x: event.screenX, y: event.screenY };
|
|
217
|
+
if (event.screenX === x && event.screenY === y) return;
|
|
218
|
+
this.#set("intent", value);
|
|
219
|
+
};
|
|
220
|
+
#onWheel = () => {
|
|
221
|
+
this.#set("intent", "mouse");
|
|
222
|
+
};
|
|
223
|
+
#onHintChange = () => {
|
|
224
|
+
this.#set("hint", readHint());
|
|
225
|
+
};
|
|
226
|
+
#onKey = (event) => {
|
|
227
|
+
if (!this.#isCountedKey(event)) return;
|
|
228
|
+
this.#set("input", "keyboard");
|
|
229
|
+
if (!isTextEntry(deepActiveElement())) {
|
|
230
|
+
this.#set("intent", "keyboard");
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
#onFocusIn = (event) => {
|
|
234
|
+
const target = eventTarget(event);
|
|
235
|
+
if (!target) {
|
|
236
|
+
this.#onFocusOut();
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const html = document.documentElement;
|
|
240
|
+
this.#element = target.localName;
|
|
241
|
+
html.setAttribute(ATTRIBUTE_PREFIX + "element", this.#element);
|
|
242
|
+
if (target.classList.length) {
|
|
243
|
+
html.setAttribute(ATTRIBUTE_PREFIX + "classes", Array.from(target.classList).join(","));
|
|
244
|
+
} else {
|
|
245
|
+
html.removeAttribute(ATTRIBUTE_PREFIX + "classes");
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
#onFocusOut = () => {
|
|
249
|
+
const html = document.documentElement;
|
|
250
|
+
this.#element = null;
|
|
251
|
+
html.removeAttribute(ATTRIBUTE_PREFIX + "element");
|
|
252
|
+
html.removeAttribute(ATTRIBUTE_PREFIX + "classes");
|
|
253
|
+
};
|
|
254
|
+
/*
|
|
255
|
+
* state
|
|
256
|
+
*/
|
|
257
|
+
#isCountedKey(event) {
|
|
258
|
+
const matches = (key) => typeof key === "number" ? key === event.keyCode : key === event.key || key === event.code;
|
|
259
|
+
return this.#specificKeys.length ? this.#specificKeys.some(matches) : !this.#ignoredKeys.some(matches);
|
|
260
|
+
}
|
|
261
|
+
#set(channel, value) {
|
|
262
|
+
if (this.#state[channel] === value) return;
|
|
263
|
+
this.#state[channel] = value;
|
|
264
|
+
this.#store(channel, value);
|
|
265
|
+
this.#publish(channel);
|
|
266
|
+
}
|
|
267
|
+
/** Writes the attribute, runs the callbacks and dispatches the event. */
|
|
268
|
+
#publish(channel) {
|
|
269
|
+
const value = this.#state[channel];
|
|
270
|
+
document.documentElement.setAttribute(ATTRIBUTE_PREFIX + channel, value);
|
|
271
|
+
for (const callback of this.#callbacks[channel]) {
|
|
272
|
+
;
|
|
273
|
+
callback(value);
|
|
274
|
+
}
|
|
275
|
+
this.dispatchEvent(new CustomEvent(channel, { detail: value }));
|
|
276
|
+
}
|
|
277
|
+
#store(channel, value) {
|
|
278
|
+
if (channel === "hint" || !this.#persist) return;
|
|
279
|
+
try {
|
|
280
|
+
window.sessionStorage.setItem(STORAGE_KEYS[channel], value);
|
|
281
|
+
} catch {
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
#restore(strategy) {
|
|
285
|
+
try {
|
|
286
|
+
const value = window.sessionStorage.getItem(STORAGE_KEYS[strategy]);
|
|
287
|
+
return isInputMethod(value) ? value : null;
|
|
288
|
+
} catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
var whatInput = new WhatInput();
|
|
294
|
+
var what_input_default = whatInput;
|
|
295
|
+
|
|
296
|
+
// scripts/umd-entry.ts
|
|
297
|
+
__whatInput = what_input_default;
|
|
298
|
+
})();
|
|
299
|
+
return __whatInput
|
|
300
|
+
},
|
|
301
|
+
)
|