what-input 5.2.12 → 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 CHANGED
@@ -2,21 +2,66 @@
2
2
 
3
3
  **A global utility for tracking the current input method (mouse, keyboard or touch).**
4
4
 
5
- ## _What Input_ is now v5
5
+ ## _What Input_ is now v6
6
6
 
7
- Now with more information and less opinion!
7
+ Rebuilt for the modern web: Pointer Events, `KeyboardEvent.key`, TypeScript, native ES modules, and an `EventTarget` API. The outputs are the same as v5, so it's a drop-in upgrade for existing sites. See the [changelog](#changelog) for the few things that changed.
8
8
 
9
- _What Input_ adds data attributes to the `window` based on the type of input being used. It also exposes a simple API that can be used for scripting interactions.
9
+ _What Input_ adds data attributes to the `<html>` element based on the type of input being used. It also exposes a simple API that can be used for scripting interactions.
10
10
 
11
11
  ## How it works
12
12
 
13
- _What Input_ uses event bubbling on the `window` to watch for mouse, keyboard and touch events (via `mousedown`, `keydown` and `touchstart`). It then sets or updates a `data-whatinput` attribute.
13
+ _What Input_ listens on the `window` (in the capture phase, so local `stopPropagation()` calls don't hide anything) for:
14
14
 
15
- Pointer Events are supported but note that `pen` inputs are remapped to `touch`.
15
+ - `pointerdown` – a direct interaction. `pointerType` decides whether it's `mouse` or `touch` (`pen` is reported as `touch`).
16
+ - `keydown` / `keyup` – a direct `keyboard` interaction, unless the key is on the ignore list (modifiers by default).
17
+ - `pointermove` / `wheel` – an _indirect_ signal that a mouse is present.
18
+ - `focusin` / `focusout` – which element currently has focus.
16
19
 
17
- _What Input_ also exposes a tiny API that allows the developer to ask for the current input, set custom ignore keys, and set and remove custom callback functions.
20
+ It then sets or updates these attributes on `<html>`:
18
21
 
19
- _What Input does not make assumptions about the input environment before the page is interacted with._ However, the `mousemove` and `pointermove` events are used to set a `data-whatintent="mouse"` attribute to indicate that a mouse is being used _indirectly_.
22
+ | Attribute | Values | Updated by |
23
+ | ------------------ | ------------------------------------------- | ------------------------------------------------------ |
24
+ | `data-whatinput` | `initial`, `mouse`, `keyboard`, `touch` | `pointerdown`, `keydown`, `keyup` |
25
+ | `data-whatintent` | `initial`, `mouse`, `keyboard`, `touch` | everything above plus `pointermove` and `wheel` |
26
+ | `data-whatelement` | the focused element's tag name, e.g. `a` | `focusin` / `focusout` |
27
+ | `data-whatclasses` | the focused element's classes, e.g. `a,b,c` | `focusin` / `focusout` (only when the element has any) |
28
+
29
+ _What Input does not make assumptions about the input environment before the page is interacted with._ However, the `pointermove` and `wheel` events are used to set `data-whatintent="mouse"` to indicate that a mouse is being used _indirectly_.
30
+
31
+ ### Interacting with forms
32
+
33
+ Since interacting with a form _always_ requires use of the keyboard, _What Input_ uses the `data-whatintent` attribute to display a "buffered" version of input events while `<input>`s, `<select>`s, `<textarea>`s, `contenteditable` elements, [form-associated custom elements](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals) and `<button>`s inside a `<form>` are being interacted with (i.e. a mouse user's `data-whatintent` will be preserved as `mouse` while typing). `data-whatinput` always reflects the actual last input.
34
+
35
+ Checkboxes and radio buttons are toggled rather than typed into, so pressing a key on one _does_ switch the intent to `keyboard`.
36
+
37
+ The same buffering can be opted into for any other element by adding a `data-whatfreeze` attribute to it or to a container. This is handy for custom controls that are operated with the arrow keys, like a slider or a video scrubber, where pressing a key is not a change of intent:
38
+
39
+ ```html
40
+ <div class="scrubber" data-whatfreeze>
41
+ <div class="scrubber-handle" role="slider" tabindex="0" ...></div>
42
+ </div>
43
+ ```
44
+
45
+ ### Device hint
46
+
47
+ Before anyone interacts with the page, `data-whatinput` and `data-whatintent` are `initial` on purpose. When a best guess is still useful (sizing hit targets on first paint, say), the `data-whathint` attribute carries what the device's _primary_ pointer suggests, read from the [`pointer` interaction media feature](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer):
48
+
49
+ | `data-whathint` | Media query | Typically |
50
+ | --------------- | ------------------- | ---------------------------- |
51
+ | `touch` | `(pointer: coarse)` | phones, tablets |
52
+ | `mouse` | `(pointer: fine)` | desktops, laptops, trackpads |
53
+ | `unknown` | neither | keyboard-only devices, TVs |
54
+
55
+ The hint follows the device live (a mouse paired with a tablet, a keyboard detached from one) and is never persisted. It is only a hint: an iPad with a trackpad still reports `touch`, and a touch-screen laptop reports `mouse`. `data-whatinput` and `data-whatintent` never use it.
56
+
57
+ ### Isn't this what `:focus-visible` is for?
58
+
59
+ Partly. [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible) is a great default for focus rings and you should use it. _What Input_ is still useful when you want to:
60
+
61
+ - style anything other than focus (hover affordances, hit targets, tooltips) based on how the page is being used;
62
+ - know the input method from JavaScript;
63
+ - tell `mouse` and `touch` apart;
64
+ - remember the input method across page loads so the first render is already right.
20
65
 
21
66
  ## Demo
22
67
 
@@ -24,35 +69,31 @@ Check out the demo to see _What Input_ in action.
24
69
 
25
70
  https://ten1seven.github.io/what-input
26
71
 
27
- ### Interacting with Forms
28
-
29
- Since interacting with a form _always_ requires use of the keyboard, _What Input_ uses the `data-whatintent` attribute to display a "buffered" version of input events while form `<input>`s, `<select>`s, and `<textarea>`s are being interacted with (i.e. mouse user's `data-whatintent` will be preserved as `mouse` while typing).
30
-
31
72
  ## Installing
32
73
 
33
- Download the file directly.
34
-
35
- Install via Yarn:
74
+ Install via npm (or your package manager of choice):
36
75
 
37
76
  ```shell
38
- yarn add what-input
77
+ npm install what-input
39
78
  ```
40
79
 
41
- Install via NPM:
80
+ Or load it from a CDN:
42
81
 
43
- ```shell
44
- npm install what-input
82
+ ```html
83
+ <script src="https://unpkg.com/what-input@6"></script>
45
84
  ```
46
85
 
86
+ Or download `dist/what-input.js` and include it directly.
87
+
47
88
  ## Usage
48
89
 
49
- Include the script directly in your project.
90
+ Include the script directly in your project. It exposes a global `whatInput`.
50
91
 
51
92
  ```html
52
93
  <script src="path/to/what-input.js"></script>
53
94
  ```
54
95
 
55
- Or require with a script loader.
96
+ Or import it. The package ships as an ES module (`dist/what-input.mjs`), as a UMD build (`dist/what-input.js`, which also covers CommonJS and AMD) and with TypeScript declarations.
56
97
 
57
98
  ```javascript
58
99
  import 'what-input'
@@ -63,28 +104,16 @@ import whatInput from 'what-input'
63
104
 
64
105
  // or
65
106
 
66
- require('what-input')
67
-
68
- // or
69
-
70
- var whatInput = require('what-input')
71
-
72
- // or
73
-
74
- requirejs.config({
75
- paths: {
76
- whatInput: 'path/to/what-input',
77
- },
78
- })
79
-
80
- require(['whatInput'], function () {})
107
+ const whatInput = require('what-input')
81
108
  ```
82
109
 
83
110
  _What Input_ will start doing its thing while you do yours.
84
111
 
85
- ### Default Behavior
112
+ > **Bundlers:** importing the module has the side effect of starting _What Input_. The package declares `"sideEffects": true` so a bare `import 'what-input'` is never tree-shaken away.
113
+
114
+ ### Default behavior
86
115
 
87
- #### Persisting Input/Intent Across Pages
116
+ #### Persisting input/intent across pages
88
117
 
89
118
  By default, _What Input_ uses [session storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage) to persist the input and intent values across pages. The benefit is that once a visitor has interacted with the page, subsequent pages won't have to wait for interactions to know the input method.
90
119
 
@@ -110,7 +139,7 @@ Session storage can be cleared at any time with:
110
139
  whatInput.clearStorage()
111
140
  ```
112
141
 
113
- ### Basic Styling
142
+ ### Basic styling
114
143
 
115
144
  ```css
116
145
  /*
@@ -123,13 +152,27 @@ whatInput.clearStorage()
123
152
  }
124
153
  ```
125
154
 
126
- **Note:** If you remove outlines with `outline: none;`, be sure to provide clear visual `:focus` styles so the user can see which element they are on at any time for greater accessibility. Visit [W3C's WCAG 2.0 2.4.7 Guideline](https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-focus-visible.html) to learn more.
155
+ A more modern take pairs _What Input_ with `:focus-visible` and only reaches for the data attributes where the browser heuristic isn't enough:
156
+
157
+ ```css
158
+ :focus-visible {
159
+ outline: 2px solid currentColor;
160
+ outline-offset: 2px;
161
+ }
162
+
163
+ /* bigger hit areas while a touch screen is being used */
164
+ [data-whatintent='touch'] .toolbar button {
165
+ min-block-size: 44px;
166
+ }
167
+ ```
168
+
169
+ **Note:** If you remove outlines with `outline: none;`, be sure to provide clear visual `:focus` styles so the user can see which element they are on at any time for greater accessibility. Visit [W3C's WCAG 2.2 2.4.7 Guideline](https://www.w3.org/WAI/WCAG22/Understanding/focus-visible.html) to learn more.
127
170
 
128
171
  ### Scripting
129
172
 
130
- #### Current Input
173
+ #### Current input
131
174
 
132
- Ask _What Input_ what the current input method is. This works best if asked after the events _What Input_ is bound to (`mousedown`, `keydown` and `touchstart`).
175
+ Ask _What Input_ what the current input method is. This works best if asked after the events _What Input_ is bound to (`pointerdown` and `keydown`).
133
176
 
134
177
  ```javascript
135
178
  whatInput.ask() // returns `mouse`, `keyboard` or `touch`
@@ -143,7 +186,7 @@ myButton.addEventListener('click', () => {
143
186
  })
144
187
  ```
145
188
 
146
- If it's necessary to know if `mousemove` is being used, use the `'intent'` option. For example:
189
+ If it's necessary to know if `pointermove` is being used, use the `'intent'` option. For example:
147
190
 
148
191
  ```javascript
149
192
  /*
@@ -161,47 +204,61 @@ whatInput.ask() // returns `keyboard` because the keyboard was the last direct p
161
204
  whatInput.ask('intent') // returns `mouse` because mouse movement was the most recent action detected
162
205
  ```
163
206
 
164
- ### Current Element
207
+ Since `click` events are `PointerEvent`s in current browsers, a single click handler can also read `event.pointerType` directly: it's `mouse`, `pen` or `touch`, and empty when the click came from the keyboard.
208
+
209
+ #### Device hint
210
+
211
+ ```javascript
212
+ whatInput.ask('hint') // returns `mouse`, `touch` or `unknown`
213
+ ```
214
+
215
+ #### Current element
165
216
 
166
217
  Ask _What Input_ the currently focused DOM element.
167
218
 
168
219
  ```javascript
169
- whatInput.element() // returns a string, like `input` or null
220
+ whatInput.element() // returns a string, like `input`, or null
170
221
  ```
171
222
 
172
- #### Ignore Keys
223
+ #### Ignore keys
173
224
 
174
- Set a custom array of [keycodes](http://keycode.info/) that will be ignored (will not switch over to `keyboard`) when pressed. _A custom list will overwrite the default values._
225
+ Set a custom list of keys that will be ignored (will not switch over to `keyboard`) when pressed. Keys can be [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values) values, [`KeyboardEvent.code`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values) values or legacy [keycodes](https://www.toptal.com/developers/keycode). _A custom list will overwrite the default values._
175
226
 
176
227
  ```javascript
177
228
  /*
178
229
  * default ignored keys:
179
- * 16, // shift
180
- * 17, // control
181
- * 18, // alt
182
- * 91, // Windows key / left Apple cmd
183
- * 93 // Windows menu / right Apple cmd
230
+ * 'Shift'
231
+ * 'Control'
232
+ * 'Alt'
233
+ * 'Meta' // Windows key / Apple cmd
234
+ * 'ContextMenu' // Windows menu key
184
235
  */
185
236
 
186
- whatInput.ignoreKeys([1, 2, 3])
237
+ whatInput.ignoreKeys(['Shift', 'CapsLock', 'F11'])
238
+
239
+ // legacy keycodes still work
240
+ whatInput.ignoreKeys([16, 20, 122])
187
241
  ```
188
242
 
189
- #### Specific Keys
243
+ #### Specific keys
190
244
 
191
- Set a custom array of [keycodes](http://keycode.info/) that will trigger the keyboard pressed intent (will not switch to `keyboard` unless these keys are pressed). _This overrides ignoreKeys._
245
+ Set a custom list of keys that will trigger the keyboard pressed intent (will not switch to `keyboard` unless these keys are pressed). _This overrides ignoreKeys._
192
246
 
193
247
  ```javascript
194
248
  // only listen to tab keyboard press
195
- whatInput.specificKeys([9])
249
+ whatInput.specificKeys(['Tab'])
250
+
251
+ // go back to using the ignore list
252
+ whatInput.specificKeys([])
196
253
  ```
197
254
 
198
- #### Custom Callbacks
255
+ #### Custom callbacks
199
256
 
200
257
  Fire a function when the input or intent changes.
201
258
 
202
259
  ```javascript
203
260
  // create a function to be fired
204
- var myFunction = function (type) {
261
+ const myFunction = (type) => {
205
262
  console.log(type)
206
263
  }
207
264
 
@@ -211,16 +268,148 @@ whatInput.registerOnChange(myFunction, 'intent')
211
268
  // fire `myFunction` when the input changes
212
269
  whatInput.registerOnChange(myFunction, 'input')
213
270
 
271
+ // fire `myFunction` when the device hint changes
272
+ whatInput.registerOnChange(myFunction, 'hint')
273
+
214
274
  // remove custom event
215
275
  whatInput.unRegisterOnChange(myFunction)
216
276
  ```
217
277
 
278
+ #### Events
279
+
280
+ `whatInput` is an [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget). It dispatches `input`, `intent` and `hint` [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)s whose `detail` is the new value, so all the usual listener options (`once`, `signal`, ...) are available.
281
+
282
+ ```javascript
283
+ whatInput.addEventListener('intent', (event) => {
284
+ console.log(event.detail) // `mouse`, `keyboard` or `touch`
285
+ })
286
+
287
+ // listen until a component unmounts
288
+ const controller = new AbortController()
289
+
290
+ whatInput.addEventListener('input', update, { signal: controller.signal })
291
+
292
+ controller.abort()
293
+ ```
294
+
295
+ In browsers that ship the [Observable API](https://developer.mozilla.org/en-US/docs/Web/API/Observable), `whatInput.when('intent')` works too, for free.
296
+
297
+ #### Tearing down
298
+
299
+ Stop listening, remove the `data-what*` attributes and drop every callback. Mostly useful in tests and when an app is unmounted.
300
+
301
+ ```javascript
302
+ whatInput.destroy()
303
+ ```
304
+
305
+ ### TypeScript
306
+
307
+ Types ship with the package.
308
+
309
+ ```typescript
310
+ import whatInput, { type InputMethod, type Strategy } from 'what-input'
311
+
312
+ const current: InputMethod = whatInput.ask('intent')
313
+ ```
314
+
315
+ ### Server-side rendering
316
+
317
+ _What Input_ can be imported in Node, workers and other environments without a DOM. It won't observe anything, `ask()` always answers `initial` and `element()` always answers `null`.
318
+
319
+ ### Shadow DOM
320
+
321
+ _What Input_ reports focus inside open shadow roots and knows when a keypress lands in a field inside one. The attributes still live on `<html>`, and selectors in the main document don't reach into a shadow tree, so style from inside the component instead. `:host-context()` works in Chromium and Safari; for every browser, mirror the state onto the host with the events:
322
+
323
+ ```javascript
324
+ class MyField extends HTMLElement {
325
+ connectedCallback() {
326
+ this.controller = new AbortController()
327
+
328
+ whatInput.addEventListener(
329
+ 'intent',
330
+ (event) => this.setAttribute('data-whatintent', event.detail),
331
+ { signal: this.controller.signal },
332
+ )
333
+ }
334
+
335
+ disconnectedCallback() {
336
+ this.controller.abort()
337
+ }
338
+ }
339
+ ```
340
+
341
+ ```css
342
+ /* inside the shadow root */
343
+ :host([data-whatintent='mouse']) :focus {
344
+ outline: none;
345
+ }
346
+ ```
347
+
348
+ ### Testing
349
+
350
+ The state only changes in response to real events, which is also the easiest way to drive it in tests. In a DOM test environment that implements `PointerEvent` (jsdom 22+, happy-dom, every browser):
351
+
352
+ ```javascript
353
+ window.dispatchEvent(new PointerEvent('pointerdown', { pointerType: 'touch' }))
354
+ whatInput.ask() // `touch`
355
+
356
+ window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab' }))
357
+ whatInput.ask() // `keyboard`
358
+ ```
359
+
360
+ Or mock the module entirely:
361
+
362
+ ```javascript
363
+ vi.mock('what-input', () => ({ default: { ask: () => 'touch' } }))
364
+ ```
365
+
218
366
  ## Compatibility
219
367
 
220
- _What Input_ works in all modern browsers.
368
+ _What Input_ v6 works in all evergreen browsers: Chrome and Edge 90+, Firefox 90+ and Safari 15+ (2021 and newer). It relies on Pointer Events, `AbortSignal` support in `addEventListener()`, `EventTarget` subclassing and class private fields, none of which are polyfilled.
369
+
370
+ If you need to support older browsers, stay on [v5](https://github.com/ten1seven/what-input/tree/v5.2.12).
371
+
372
+ ## Contributing
373
+
374
+ ```shell
375
+ npm install # install dependencies
376
+ npm run dev # run the demo with hot reloading
377
+ npm test # build the library and run the tests
378
+ npm run lint # prettier and type checks
379
+ npm run build # build the library and the demo site
380
+ ```
221
381
 
222
382
  ## Changelog
223
383
 
384
+ ### v6.0.0
385
+
386
+ A rewrite in TypeScript on modern browser APIs. The data attributes, the session storage keys, the API and the `dist/what-input.js` file path are unchanged, so for most sites this is a drop-in upgrade.
387
+
388
+ - **Breaking:** Drops support for Internet Explorer and other legacy browsers. The build targets ES2022 and is no longer transpiled.
389
+ - **Breaking:** Detection is built on Pointer Events only. The `mousedown`, `mousemove`, `touchstart`, `touchend`, `MSPointerDown`, `MSPointerMove`, `mousewheel` and `DOMMouseScroll` listeners (and the 200ms touch-versus-mouse buffer they required) are gone.
390
+ - **Breaking:** `clearStorage()` now removes only _What Input_'s own `what-input` and `what-intent` keys instead of wiping the entire session storage.
391
+ - **Breaking:** `pointerdown` now updates the intent as well as the input, even while a form field has focus. Only keyboard use inside form fields is buffered.
392
+ - **Breaking:** `unRegisterOnChange(fn)` removes `fn` from both the `input` and `intent` lists.
393
+ - **Breaking:** The `InputMethod` type no longer includes `pointer`, which was never actually reported.
394
+ - **Breaking:** Requires Node 20+ for development. The build uses esbuild, the demo uses Vite and the tests use Vitest; Gulp, Webpack, Babel, Sass and Yarn are gone.
395
+ - **Added:** A `data-whathint` attribute, `ask('hint')` and a `hint` event report what the device's primary pointer suggests (`mouse`, `touch` or `unknown`) from the `pointer` interaction media feature, before any interaction and live as devices are attached or removed. The existing attributes never use it.
396
+ - **Added:** A `data-whatfreeze` attribute opts any element (or container) into the same intent buffering that form fields get, for custom controls driven by the arrow keys ([#123](https://github.com/ten1seven/what-input/issues/123)).
397
+ - **Added:** An ES module build (`dist/what-input.mjs`) with a proper `exports` map, `module` and `unpkg` fields. The UMD build (`dist/what-input.js`) and the minified build remain for `<script>` tags, CommonJS and AMD.
398
+ - **Added:** `whatInput` is an `EventTarget` and dispatches `input` and `intent` events.
399
+ - **Added:** `whatInput.destroy()` tears everything down (listeners are bound with an `AbortController`).
400
+ - **Added:** `ignoreKeys()` and `specificKeys()` accept `KeyboardEvent.key` and `KeyboardEvent.code` strings alongside legacy keycodes. The defaults are now key names.
401
+ - **Added:** Typing inside `contenteditable` elements and form-associated custom elements no longer changes the intent, just like form fields.
402
+ - **Fixed:** Pressing a key on a checkbox or radio button switches the intent to `keyboard`; they are toggled, not typed into ([#128](https://github.com/ten1seven/what-input/issues/128)).
403
+ - **Fixed:** Long-presses in Firefox for Android no longer flash `data-whatintent="mouse"`, because the emulated mouse events are no longer listened to ([#94](https://github.com/ten1seven/what-input/issues/94)).
404
+ - **Added:** Focus inside open shadow roots is reported for the inner element (via `composedPath()`), and the active-element check follows shadow roots when deciding whether a keypress is text entry.
405
+ - **Added:** Persisted session storage values are validated before they are used.
406
+ - **Changed:** Type declarations are generated from the source and shipped in `dist/`.
407
+ - **Changed:** `pointerdown` and `keydown` are observed in the capture phase on `window`, so `whatInput.ask()` is already up to date inside any element's own event handler, even one that calls `preventDefault()` or `stopPropagation()` ([#80](https://github.com/ten1seven/what-input/issues/80)).
408
+ - **Changed:** When the script runs after `DOMContentLoaded` (dynamic `import()`, late-loaded scripts) the initial state is published immediately instead of never.
409
+ - **Changed:** An interaction that happens before `DOMContentLoaded` is no longer overwritten by the persisted value.
410
+ - **Fixed:** `data-whatclasses` separates _all_ classes with commas (`a,b,c`); previously only the first space was replaced.
411
+ - **Fixed:** `data-whatclasses` is removed when focus moves to an element without classes.
412
+
224
413
  ### v5.2.12
225
414
 
226
415
  - **Fixed:** Improved detection and respect for of `data-whatpersist` before `DOMContentLoaded`. Fix via [FanFataL](https://github.com/FanFataL).
@@ -310,7 +499,7 @@ _What Input_ works in all modern browsers.
310
499
 
311
500
  ## Acknowledgments
312
501
 
313
- Special thanks to [Viget](http://viget.com/) for their encouragement and commitment to open source projects. Visit [code.viget.com](http://code.viget.com/) to see more projects from [Viget](http://viget.com).
502
+ Special thanks to [Viget](https://viget.com/) for their encouragement and commitment to open source projects. Visit [code.viget.com](https://code.viget.com/) to see more projects from [Viget](https://viget.com).
314
503
 
315
504
  Thanks to [mAAdhaTTah](https://github.com/mAAdhaTTah) for the initial conversion to Webpack. Thanks to [greypants](https://github.com/greypants) for adding TypeScript definitions.
316
505
 
@@ -0,0 +1,88 @@
1
+ /**
2
+ * What Input?
3
+ *
4
+ * A global utility for tracking the current input method (mouse, keyboard or
5
+ * touch). It writes `data-whatinput`, `data-whatintent`, `data-whatelement`
6
+ * and `data-whatclasses` attributes to the `<html>` element and exposes a
7
+ * small API for scripting against the same information.
8
+ */
9
+ /** The input methods What Input can report. */
10
+ export type InputMethod = 'initial' | 'mouse' | 'keyboard' | 'touch';
11
+ /**
12
+ * `input` is the last *direct* interaction (`pointerdown`, `keydown`).
13
+ * `intent` also includes *indirect* signals (`pointermove`, `wheel`) and is
14
+ * preserved while typing into form fields.
15
+ */
16
+ export type Strategy = 'input' | 'intent';
17
+ /**
18
+ * What the device's *primary* pointer suggests before (or regardless of) any
19
+ * interaction, read from the `pointer` interaction media feature. It is a
20
+ * hint only: `data-whatinput` and `data-whatintent` never use it.
21
+ */
22
+ export type Hint = 'mouse' | 'touch' | 'unknown';
23
+ /** A callback registered with `registerOnChange()`. */
24
+ export type ChangeCallback = (type: InputMethod) => void;
25
+ /** A callback registered with `registerOnChange(callback, 'hint')`. */
26
+ export type HintCallback = (hint: Hint) => void;
27
+ type Callback = ChangeCallback | HintCallback;
28
+ /**
29
+ * A key to ignore or require. Strings are matched against `KeyboardEvent.key`
30
+ * and `KeyboardEvent.code` (`'Shift'`, `'Tab'`, `'KeyA'`); numbers are matched
31
+ * against the legacy `KeyboardEvent.keyCode` for backwards compatibility.
32
+ */
33
+ export type KeyMatcher = string | number;
34
+ /** The events dispatched by the `whatInput` EventTarget. */
35
+ export interface WhatInputEventMap {
36
+ input: CustomEvent<InputMethod>;
37
+ intent: CustomEvent<InputMethod>;
38
+ hint: CustomEvent<Hint>;
39
+ }
40
+ declare class WhatInput extends EventTarget {
41
+ #private;
42
+ constructor();
43
+ /**
44
+ * The current input method.
45
+ *
46
+ * - `'input'` (default): the same value as the `data-whatinput` attribute
47
+ * - `'intent'`: the same value as the `data-whatintent` attribute
48
+ * - `'hint'`: the same value as the `data-whathint` attribute
49
+ */
50
+ ask(strategy?: Strategy): InputMethod;
51
+ ask(strategy: 'hint'): Hint;
52
+ /** The tag name of the currently focused element, or `null`. */
53
+ element(): string | null;
54
+ /**
55
+ * Replaces the list of keys that are ignored (do not switch to `keyboard`)
56
+ * when pressed. Defaults to the modifier keys.
57
+ */
58
+ ignoreKeys(keys: readonly KeyMatcher[]): void;
59
+ /**
60
+ * Replaces the list of keys that are the *only* keys that switch to
61
+ * `keyboard`. When set, this overrides `ignoreKeys()`. Pass an empty array
62
+ * to restore the `ignoreKeys()` behavior.
63
+ */
64
+ specificKeys(keys: readonly KeyMatcher[]): void;
65
+ /** Fires `callback` whenever the input (default), intent or hint changes. */
66
+ registerOnChange(callback: ChangeCallback, strategy?: Strategy): void;
67
+ registerOnChange(callback: HintCallback, strategy: 'hint'): void;
68
+ /** Removes a callback added with `registerOnChange()`. */
69
+ unRegisterOnChange(callback: Callback): void;
70
+ /** Removes the persisted input and intent from session storage. */
71
+ clearStorage(): void;
72
+ /**
73
+ * Stops listening, removes the `data-what*` attributes from `<html>` and
74
+ * drops every registered callback. Useful for tests and app teardown.
75
+ */
76
+ destroy(): void;
77
+ }
78
+ /** Typed listeners for the `input`, `intent` and `hint` events (types only). */
79
+ interface WhatInput {
80
+ addEventListener<K extends keyof WhatInputEventMap>(type: K, listener: ((this: WhatInput, event: WhatInputEventMap[K]) => void) | null, options?: boolean | AddEventListenerOptions): void;
81
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void;
82
+ removeEventListener<K extends keyof WhatInputEventMap>(type: K, listener: ((this: WhatInput, event: WhatInputEventMap[K]) => void) | null, options?: boolean | EventListenerOptions): void;
83
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | EventListenerOptions): void;
84
+ }
85
+ export type { WhatInput };
86
+ /** The shared What Input instance. It starts observing as soon as it is imported. */
87
+ declare const whatInput: WhatInput;
88
+ export default whatInput;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * What Input?
3
+ *
4
+ * A global utility for tracking the current input method (mouse, keyboard or
5
+ * touch). It writes `data-whatinput`, `data-whatintent`, `data-whatelement`
6
+ * and `data-whatclasses` attributes to the `<html>` element and exposes a
7
+ * small API for scripting against the same information.
8
+ */
9
+ /** The input methods What Input can report. */
10
+ export type InputMethod = 'initial' | 'mouse' | 'keyboard' | 'touch';
11
+ /**
12
+ * `input` is the last *direct* interaction (`pointerdown`, `keydown`).
13
+ * `intent` also includes *indirect* signals (`pointermove`, `wheel`) and is
14
+ * preserved while typing into form fields.
15
+ */
16
+ export type Strategy = 'input' | 'intent';
17
+ /**
18
+ * What the device's *primary* pointer suggests before (or regardless of) any
19
+ * interaction, read from the `pointer` interaction media feature. It is a
20
+ * hint only: `data-whatinput` and `data-whatintent` never use it.
21
+ */
22
+ export type Hint = 'mouse' | 'touch' | 'unknown';
23
+ /** A callback registered with `registerOnChange()`. */
24
+ export type ChangeCallback = (type: InputMethod) => void;
25
+ /** A callback registered with `registerOnChange(callback, 'hint')`. */
26
+ export type HintCallback = (hint: Hint) => void;
27
+ type Callback = ChangeCallback | HintCallback;
28
+ /**
29
+ * A key to ignore or require. Strings are matched against `KeyboardEvent.key`
30
+ * and `KeyboardEvent.code` (`'Shift'`, `'Tab'`, `'KeyA'`); numbers are matched
31
+ * against the legacy `KeyboardEvent.keyCode` for backwards compatibility.
32
+ */
33
+ export type KeyMatcher = string | number;
34
+ /** The events dispatched by the `whatInput` EventTarget. */
35
+ export interface WhatInputEventMap {
36
+ input: CustomEvent<InputMethod>;
37
+ intent: CustomEvent<InputMethod>;
38
+ hint: CustomEvent<Hint>;
39
+ }
40
+ declare class WhatInput extends EventTarget {
41
+ #private;
42
+ constructor();
43
+ /**
44
+ * The current input method.
45
+ *
46
+ * - `'input'` (default): the same value as the `data-whatinput` attribute
47
+ * - `'intent'`: the same value as the `data-whatintent` attribute
48
+ * - `'hint'`: the same value as the `data-whathint` attribute
49
+ */
50
+ ask(strategy?: Strategy): InputMethod;
51
+ ask(strategy: 'hint'): Hint;
52
+ /** The tag name of the currently focused element, or `null`. */
53
+ element(): string | null;
54
+ /**
55
+ * Replaces the list of keys that are ignored (do not switch to `keyboard`)
56
+ * when pressed. Defaults to the modifier keys.
57
+ */
58
+ ignoreKeys(keys: readonly KeyMatcher[]): void;
59
+ /**
60
+ * Replaces the list of keys that are the *only* keys that switch to
61
+ * `keyboard`. When set, this overrides `ignoreKeys()`. Pass an empty array
62
+ * to restore the `ignoreKeys()` behavior.
63
+ */
64
+ specificKeys(keys: readonly KeyMatcher[]): void;
65
+ /** Fires `callback` whenever the input (default), intent or hint changes. */
66
+ registerOnChange(callback: ChangeCallback, strategy?: Strategy): void;
67
+ registerOnChange(callback: HintCallback, strategy: 'hint'): void;
68
+ /** Removes a callback added with `registerOnChange()`. */
69
+ unRegisterOnChange(callback: Callback): void;
70
+ /** Removes the persisted input and intent from session storage. */
71
+ clearStorage(): void;
72
+ /**
73
+ * Stops listening, removes the `data-what*` attributes from `<html>` and
74
+ * drops every registered callback. Useful for tests and app teardown.
75
+ */
76
+ destroy(): void;
77
+ }
78
+ /** Typed listeners for the `input`, `intent` and `hint` events (types only). */
79
+ interface WhatInput {
80
+ addEventListener<K extends keyof WhatInputEventMap>(type: K, listener: ((this: WhatInput, event: WhatInputEventMap[K]) => void) | null, options?: boolean | AddEventListenerOptions): void;
81
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void;
82
+ removeEventListener<K extends keyof WhatInputEventMap>(type: K, listener: ((this: WhatInput, event: WhatInputEventMap[K]) => void) | null, options?: boolean | EventListenerOptions): void;
83
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | EventListenerOptions): void;
84
+ }
85
+ export type { WhatInput };
86
+ /** The shared What Input instance. It starts observing as soon as it is imported. */
87
+ declare const whatInput: WhatInput;
88
+ export default whatInput;