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.
@@ -1,482 +0,0 @@
1
- module.exports = (() => {
2
- /*
3
- * bail out if there is no document or window
4
- * (i.e. in a node/non-DOM environment)
5
- *
6
- * Return a stubbed API instead
7
- */
8
- if (typeof document === 'undefined' || typeof window === 'undefined') {
9
- return {
10
- // always return "initial" because no interaction will ever be detected
11
- ask: () => 'initial',
12
-
13
- // always return null
14
- element: () => null,
15
-
16
- // no-op
17
- ignoreKeys: () => {},
18
-
19
- // no-op
20
- specificKeys: () => {},
21
-
22
- // no-op
23
- registerOnChange: () => {},
24
-
25
- // no-op
26
- unRegisterOnChange: () => {}
27
- }
28
- }
29
-
30
- /*
31
- * variables
32
- */
33
-
34
- // cache document.documentElement
35
- const docElem = document.documentElement
36
-
37
- // currently focused dom element
38
- let currentElement = null
39
-
40
- // last used input type
41
- let currentInput = 'initial'
42
-
43
- // last used input intent
44
- let currentIntent = currentInput
45
-
46
- // UNIX timestamp of current event
47
- let currentTimestamp = Date.now()
48
-
49
- // check for a `data-whatpersist` attribute on either the `html` or `body` elements, defaults to `true`
50
- let shouldPersist = 'false'
51
-
52
- // form input types
53
- const formInputs = ['button', 'input', 'select', 'textarea']
54
-
55
- // empty array for holding callback functions
56
- const functionList = []
57
-
58
- // list of modifier keys commonly used with the mouse and
59
- // can be safely ignored to prevent false keyboard detection
60
- let ignoreMap = [
61
- 16, // shift
62
- 17, // control
63
- 18, // alt
64
- 91, // Windows key / left Apple cmd
65
- 93 // Windows menu / right Apple cmd
66
- ]
67
-
68
- let specificMap = []
69
-
70
- // mapping of events to input types
71
- const inputMap = {
72
- keydown: 'keyboard',
73
- keyup: 'keyboard',
74
- mousedown: 'mouse',
75
- mousemove: 'mouse',
76
- MSPointerDown: 'pointer',
77
- MSPointerMove: 'pointer',
78
- pointerdown: 'pointer',
79
- pointermove: 'pointer',
80
- touchstart: 'touch',
81
- touchend: 'touch'
82
- }
83
-
84
- // boolean: true if the page is being scrolled
85
- let isScrolling = false
86
-
87
- // store current mouse position
88
- const mousePos = {
89
- x: null,
90
- y: null
91
- }
92
-
93
- // map of IE 10 pointer events
94
- const pointerMap = {
95
- 2: 'touch',
96
- 3: 'touch', // treat pen like touch
97
- 4: 'mouse'
98
- }
99
-
100
- // check support for passive event listeners
101
- let supportsPassive = false
102
-
103
- try {
104
- const opts = Object.defineProperty({}, 'passive', {
105
- get: () => {
106
- supportsPassive = true
107
- }
108
- })
109
-
110
- window.addEventListener('test', null, opts)
111
- } catch (e) {
112
- // fail silently
113
- }
114
-
115
- /*
116
- * set up
117
- */
118
-
119
- const setUp = () => {
120
- // add correct mouse wheel event mapping to `inputMap`
121
- inputMap[detectWheel()] = 'mouse'
122
-
123
- addListeners()
124
- }
125
-
126
- /*
127
- * events
128
- */
129
-
130
- const addListeners = () => {
131
- // `pointermove`, `MSPointerMove`, `mousemove` and mouse wheel event binding
132
- // can only demonstrate potential, but not actual, interaction
133
- // and are treated separately
134
- const options = supportsPassive ? { passive: true, capture: true } : true
135
-
136
- document.addEventListener('DOMContentLoaded', setPersist, true)
137
-
138
- // pointer events (mouse, pen, touch)
139
- if (window.PointerEvent) {
140
- window.addEventListener('pointerdown', setInput, true)
141
- window.addEventListener('pointermove', setIntent, true)
142
- } else if (window.MSPointerEvent) {
143
- window.addEventListener('MSPointerDown', setInput, true)
144
- window.addEventListener('MSPointerMove', setIntent, true)
145
- } else {
146
- // mouse events
147
- window.addEventListener('mousedown', setInput, true)
148
- window.addEventListener('mousemove', setIntent, true)
149
-
150
- // touch events
151
- if ('ontouchstart' in window) {
152
- window.addEventListener('touchstart', setInput, options)
153
- window.addEventListener('touchend', setInput, true)
154
- }
155
- }
156
-
157
- // mouse wheel
158
- window.addEventListener(detectWheel(), setIntent, options)
159
-
160
- // keyboard events
161
- window.addEventListener('keydown', setInput, true)
162
- window.addEventListener('keyup', setInput, true)
163
-
164
- // focus events
165
- window.addEventListener('focusin', setElement, true)
166
- window.addEventListener('focusout', clearElement, true)
167
- }
168
-
169
- // checks if input persistence should happen and
170
- // get saved state from session storage if true (defaults to `false`)
171
- const setPersist = () => {
172
- shouldPersist = !(
173
- docElem.getAttribute('data-whatpersist') ||
174
- document.body.getAttribute('data-whatpersist') === 'false'
175
- )
176
-
177
- if (shouldPersist) {
178
- // check for session variables and use if available
179
- try {
180
- if (window.sessionStorage.getItem('what-input')) {
181
- currentInput = window.sessionStorage.getItem('what-input')
182
- }
183
-
184
- if (window.sessionStorage.getItem('what-intent')) {
185
- currentIntent = window.sessionStorage.getItem('what-intent')
186
- }
187
- } catch (e) {
188
- // fail silently
189
- }
190
- }
191
-
192
- // always run these so at least `initial` state is set
193
- doUpdate('input')
194
- doUpdate('intent')
195
- }
196
-
197
- // checks conditions before updating new input
198
- const setInput = event => {
199
- const eventKey = event.which
200
- let value = inputMap[event.type]
201
-
202
- if (value === 'pointer') {
203
- value = pointerType(event)
204
- }
205
-
206
- const ignoreMatch =
207
- !specificMap.length && ignoreMap.indexOf(eventKey) === -1
208
-
209
- const specificMatch =
210
- specificMap.length && specificMap.indexOf(eventKey) !== -1
211
-
212
- let shouldUpdate =
213
- (value === 'keyboard' && eventKey && (ignoreMatch || specificMatch)) ||
214
- value === 'mouse' ||
215
- value === 'touch'
216
-
217
- // prevent touch detection from being overridden by event execution order
218
- if (validateTouch(value)) {
219
- shouldUpdate = false
220
- }
221
-
222
- if (shouldUpdate && currentInput !== value) {
223
- currentInput = value
224
-
225
- persistInput('input', currentInput)
226
- doUpdate('input')
227
- }
228
-
229
- if (shouldUpdate && currentIntent !== value) {
230
- // preserve intent for keyboard interaction with form fields
231
- const activeElem = document.activeElement
232
- const notFormInput =
233
- activeElem &&
234
- activeElem.nodeName &&
235
- (formInputs.indexOf(activeElem.nodeName.toLowerCase()) === -1 ||
236
- (activeElem.nodeName.toLowerCase() === 'button' &&
237
- !checkClosest(activeElem, 'form')))
238
-
239
- if (notFormInput) {
240
- currentIntent = value
241
-
242
- persistInput('intent', currentIntent)
243
- doUpdate('intent')
244
- }
245
- }
246
- }
247
-
248
- // updates the doc and `inputTypes` array with new input
249
- const doUpdate = which => {
250
- docElem.setAttribute(
251
- 'data-what' + which,
252
- which === 'input' ? currentInput : currentIntent
253
- )
254
-
255
- fireFunctions(which)
256
- }
257
-
258
- // updates input intent for `mousemove` and `pointermove`
259
- const setIntent = event => {
260
- let value = inputMap[event.type]
261
-
262
- if (value === 'pointer') {
263
- value = pointerType(event)
264
- }
265
-
266
- // test to see if `mousemove` happened relative to the screen to detect scrolling versus mousemove
267
- detectScrolling(event)
268
-
269
- // only execute if scrolling isn't happening
270
- if (
271
- ((!isScrolling && !validateTouch(value)) ||
272
- ((isScrolling && event.type === 'wheel') ||
273
- event.type === 'mousewheel' ||
274
- event.type === 'DOMMouseScroll')) &&
275
- currentIntent !== value
276
- ) {
277
- currentIntent = value
278
-
279
- persistInput('intent', currentIntent)
280
- doUpdate('intent')
281
- }
282
- }
283
-
284
- const setElement = event => {
285
- if (!event.target.nodeName) {
286
- // If nodeName is undefined, clear the element
287
- // This can happen if click inside an <svg> element.
288
- clearElement()
289
- return
290
- }
291
-
292
- currentElement = event.target.nodeName.toLowerCase()
293
- docElem.setAttribute('data-whatelement', currentElement)
294
-
295
- if (event.target.classList && event.target.classList.length) {
296
- docElem.setAttribute(
297
- 'data-whatclasses',
298
- event.target.classList.toString().replace(' ', ',')
299
- )
300
- }
301
- }
302
-
303
- const clearElement = () => {
304
- currentElement = null
305
-
306
- docElem.removeAttribute('data-whatelement')
307
- docElem.removeAttribute('data-whatclasses')
308
- }
309
-
310
- const persistInput = (which, value) => {
311
- if (shouldPersist) {
312
- try {
313
- window.sessionStorage.setItem('what-' + which, value)
314
- } catch (e) {
315
- // fail silently
316
- }
317
- }
318
- }
319
-
320
- /*
321
- * utilities
322
- */
323
-
324
- const pointerType = event => {
325
- if (typeof event.pointerType === 'number') {
326
- return pointerMap[event.pointerType]
327
- } else {
328
- // treat pen like touch
329
- return event.pointerType === 'pen' ? 'touch' : event.pointerType
330
- }
331
- }
332
-
333
- // prevent touch detection from being overridden by event execution order
334
- const validateTouch = value => {
335
- const timestamp = Date.now()
336
-
337
- const touchIsValid =
338
- value === 'mouse' &&
339
- currentInput === 'touch' &&
340
- timestamp - currentTimestamp < 200
341
-
342
- currentTimestamp = timestamp
343
-
344
- return touchIsValid
345
- }
346
-
347
- // detect version of mouse wheel event to use
348
- // via https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event
349
- const detectWheel = () => {
350
- let wheelType = null
351
-
352
- // Modern browsers support "wheel"
353
- if ('onwheel' in document.createElement('div')) {
354
- wheelType = 'wheel'
355
- } else {
356
- // Webkit and IE support at least "mousewheel"
357
- // or assume that remaining browsers are older Firefox
358
- wheelType =
359
- document.onmousewheel !== undefined ? 'mousewheel' : 'DOMMouseScroll'
360
- }
361
-
362
- return wheelType
363
- }
364
-
365
- // runs callback functions
366
- const fireFunctions = type => {
367
- for (let i = 0, len = functionList.length; i < len; i++) {
368
- if (functionList[i].type === type) {
369
- functionList[i].fn.call(
370
- this,
371
- type === 'input' ? currentInput : currentIntent
372
- )
373
- }
374
- }
375
- }
376
-
377
- // finds matching element in an object
378
- const objPos = match => {
379
- for (let i = 0, len = functionList.length; i < len; i++) {
380
- if (functionList[i].fn === match) {
381
- return i
382
- }
383
- }
384
- }
385
-
386
- const detectScrolling = event => {
387
- if (mousePos.x !== event.screenX || mousePos.y !== event.screenY) {
388
- isScrolling = false
389
-
390
- mousePos.x = event.screenX
391
- mousePos.y = event.screenY
392
- } else {
393
- isScrolling = true
394
- }
395
- }
396
-
397
- // manual version of `closest()`
398
- const checkClosest = (elem, tag) => {
399
- const ElementPrototype = window.Element.prototype
400
-
401
- if (!ElementPrototype.matches) {
402
- ElementPrototype.matches =
403
- ElementPrototype.msMatchesSelector ||
404
- ElementPrototype.webkitMatchesSelector
405
- }
406
-
407
- if (!ElementPrototype.closest) {
408
- do {
409
- if (elem.matches(tag)) {
410
- return elem
411
- }
412
-
413
- elem = elem.parentElement || elem.parentNode
414
- } while (elem !== null && elem.nodeType === 1)
415
-
416
- return null
417
- } else {
418
- return elem.closest(tag)
419
- }
420
- }
421
-
422
- /*
423
- * init
424
- */
425
-
426
- // don't start script unless browser cuts the mustard
427
- // (also passes if polyfills are used)
428
- if ('addEventListener' in window && Array.prototype.indexOf) {
429
- setUp()
430
- }
431
-
432
- /*
433
- * api
434
- */
435
-
436
- return {
437
- // returns string: the current input type
438
- // opt: 'intent'|'input'
439
- // 'input' (default): returns the same value as the `data-whatinput` attribute
440
- // 'intent': includes `data-whatintent` value if it's different than `data-whatinput`
441
- ask: opt => {
442
- return opt === 'intent' ? currentIntent : currentInput
443
- },
444
-
445
- // returns string: the currently focused element or null
446
- element: () => {
447
- return currentElement
448
- },
449
-
450
- // overwrites ignored keys with provided array
451
- ignoreKeys: arr => {
452
- ignoreMap = arr
453
- },
454
-
455
- // overwrites specific char keys to update on
456
- specificKeys: arr => {
457
- specificMap = arr
458
- },
459
-
460
- // attach functions to input and intent "events"
461
- // funct: function to fire on change
462
- // eventType: 'input'|'intent'
463
- registerOnChange: (fn, eventType) => {
464
- functionList.push({
465
- fn: fn,
466
- type: eventType || 'input'
467
- })
468
- },
469
-
470
- unRegisterOnChange: fn => {
471
- const position = objPos(fn)
472
-
473
- if (position || position === 0) {
474
- functionList.splice(position, 1)
475
- }
476
- },
477
-
478
- clearStorage: () => {
479
- window.sessionStorage.clear()
480
- }
481
- }
482
- })()
@@ -1,49 +0,0 @@
1
- *,
2
- *::before,
3
- *::after {
4
- box-sizing: border-box;
5
- }
6
-
7
- html {
8
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
9
- }
10
-
11
- body {
12
- color: #555;
13
- font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
14
- margin: 0;
15
- padding: 0;
16
- }
17
-
18
- a,
19
- button,
20
- input,
21
- select,
22
- textarea {
23
- @include a11y-focus;
24
- }
25
-
26
- a {
27
- color: #337ab7;
28
- text-decoration: none;
29
-
30
- @include hover {
31
- text-decoration: underline;
32
- }
33
- }
34
-
35
- h1 {
36
- border-bottom: 1px solid #eee;
37
- font-size: 36px;
38
- font-weight: 500;
39
- margin: 20px 0 10px;
40
- padding-bottom: 9px;
41
- }
42
-
43
- p {
44
- margin: ($unit * 2) 0;
45
-
46
- @media (min-width: 800px) {
47
- margin: ($unit * 3) 0;
48
- }
49
- }