@stonecrop/utilities 0.13.4 → 0.13.5

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 +1 @@
1
- {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/composables/keyboard.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAuM3E;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,gBA6HrC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,yBAAyB,EAAE,QA2IlE"}
1
+ {"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/composables/keyboard.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAmN3E;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,gBA+HrC,CAAA;AAoBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,yBAAyB,EAAE,QA+HlE"}
@@ -3,63 +3,66 @@ import { useFocusWithin } from '@vueuse/core';
3
3
  import { useElementVisibility } from './visibility';
4
4
  // helper functions
5
5
  const isVisible = (element) => {
6
- let isVisible = useElementVisibility(element).value;
7
- isVisible = isVisible && element.offsetHeight > 0;
8
- return isVisible;
6
+ let visible = useElementVisibility(element).value;
7
+ visible = visible && element.offsetHeight > 0;
8
+ return visible;
9
9
  };
10
10
  const isFocusable = (element) => {
11
11
  return element.tabIndex >= 0;
12
12
  };
13
13
  // navigation functions
14
14
  const getUpCell = (event) => {
15
- const $target = event.target;
16
- return _getUpCell($target);
15
+ if (!(event.target instanceof HTMLElement))
16
+ return undefined;
17
+ return getUpCellEl(event.target);
17
18
  };
18
- const _getUpCell = (element) => {
19
+ const getUpCellEl = (element) => {
19
20
  let $upCell;
20
21
  if (element instanceof HTMLTableCellElement) {
21
- const $prevRow = element.parentElement?.previousElementSibling;
22
- if ($prevRow) {
23
- const $prevRowCells = Array.from($prevRow.children);
24
- const $prevCell = $prevRowCells[element.cellIndex];
25
- if ($prevCell) {
26
- $upCell = $prevCell;
22
+ const $prevSibling = element.parentElement?.previousElementSibling;
23
+ if ($prevSibling instanceof HTMLTableRowElement) {
24
+ const $prevRowCells = Array.from($prevSibling.children);
25
+ const $cellEl = $prevRowCells[element.cellIndex];
26
+ if ($cellEl instanceof HTMLElement) {
27
+ $upCell = $cellEl;
27
28
  }
28
29
  }
29
30
  }
30
31
  else if (element instanceof HTMLTableRowElement) {
31
- const $prevRow = element.previousElementSibling;
32
- if ($prevRow) {
33
- $upCell = $prevRow;
32
+ const $prevSibling = element.previousElementSibling;
33
+ if ($prevSibling instanceof HTMLTableRowElement) {
34
+ $upCell = $prevSibling;
34
35
  }
35
36
  }
36
37
  else {
37
38
  // handle other contexts
38
39
  }
39
40
  if ($upCell && (!isFocusable($upCell) || !isVisible($upCell))) {
40
- return _getUpCell($upCell);
41
+ return getUpCellEl($upCell);
41
42
  }
42
43
  return $upCell;
43
44
  };
44
45
  const getTopCell = (event) => {
46
+ if (!(event.target instanceof HTMLElement))
47
+ return undefined;
45
48
  const $target = event.target;
46
49
  let $topCell;
47
50
  if ($target instanceof HTMLTableCellElement) {
48
51
  const $table = $target.parentElement?.parentElement;
49
52
  if ($table) {
50
53
  const $firstRow = $table.firstElementChild;
51
- const $navCell = $firstRow?.children[$target.cellIndex];
52
- if ($navCell) {
53
- $topCell = $navCell;
54
+ const $navEl = $firstRow?.children[$target.cellIndex];
55
+ if ($navEl instanceof HTMLElement) {
56
+ $topCell = $navEl;
54
57
  }
55
58
  }
56
59
  }
57
60
  else if ($target instanceof HTMLTableRowElement) {
58
- const $table = $target.parentElement;
59
- if ($table) {
60
- const $firstRow = $table.firstElementChild;
61
- if ($firstRow) {
62
- $topCell = $firstRow;
61
+ const $parent = $target.parentElement;
62
+ if ($parent) {
63
+ const $firstEl = $parent.firstElementChild;
64
+ if ($firstEl instanceof HTMLTableRowElement) {
65
+ $topCell = $firstEl;
63
66
  }
64
67
  }
65
68
  }
@@ -67,59 +70,62 @@ const getTopCell = (event) => {
67
70
  // handle other contexts
68
71
  }
69
72
  if ($topCell && (!isFocusable($topCell) || !isVisible($topCell))) {
70
- return _getDownCell($topCell);
73
+ return getDownCellEl($topCell);
71
74
  }
72
75
  return $topCell;
73
76
  };
74
77
  const getDownCell = (event) => {
75
- const $target = event.target;
76
- return _getDownCell($target);
78
+ if (!(event.target instanceof HTMLElement))
79
+ return undefined;
80
+ return getDownCellEl(event.target);
77
81
  };
78
- const _getDownCell = (element) => {
82
+ const getDownCellEl = (element) => {
79
83
  let $downCell;
80
84
  if (element instanceof HTMLTableCellElement) {
81
- const $nextRow = element.parentElement?.nextElementSibling;
82
- if ($nextRow) {
83
- const $nextRowCells = Array.from($nextRow.children);
84
- const $nextCell = $nextRowCells[element.cellIndex];
85
- if ($nextCell) {
86
- $downCell = $nextCell;
85
+ const $nextSibling = element.parentElement?.nextElementSibling;
86
+ if ($nextSibling) {
87
+ const $nextRowCells = Array.from($nextSibling.children);
88
+ const $cellEl = $nextRowCells[element.cellIndex];
89
+ if ($cellEl instanceof HTMLElement) {
90
+ $downCell = $cellEl;
87
91
  }
88
92
  }
89
93
  }
90
94
  else if (element instanceof HTMLTableRowElement) {
91
- const $nextRow = element.nextElementSibling;
92
- if ($nextRow) {
93
- $downCell = $nextRow;
95
+ const $nextSibling = element.nextElementSibling;
96
+ if ($nextSibling instanceof HTMLTableRowElement) {
97
+ $downCell = $nextSibling;
94
98
  }
95
99
  }
96
100
  else {
97
101
  // handle other contexts
98
102
  }
99
103
  if ($downCell && (!isFocusable($downCell) || !isVisible($downCell))) {
100
- return _getDownCell($downCell);
104
+ return getDownCellEl($downCell);
101
105
  }
102
106
  return $downCell;
103
107
  };
104
108
  const getBottomCell = (event) => {
109
+ if (!(event.target instanceof HTMLElement))
110
+ return undefined;
105
111
  const $target = event.target;
106
112
  let $bottomCell;
107
113
  if ($target instanceof HTMLTableCellElement) {
108
114
  const $table = $target.parentElement?.parentElement;
109
115
  if ($table) {
110
116
  const $lastRow = $table.lastElementChild;
111
- const $navCell = $lastRow?.children[$target.cellIndex];
112
- if ($navCell) {
113
- $bottomCell = $navCell;
117
+ const $navEl = $lastRow?.children[$target.cellIndex];
118
+ if ($navEl instanceof HTMLElement) {
119
+ $bottomCell = $navEl;
114
120
  }
115
121
  }
116
122
  }
117
123
  else if ($target instanceof HTMLTableRowElement) {
118
- const $table = $target.parentElement;
119
- if ($table) {
120
- const $lastRow = $table.lastElementChild;
121
- if ($lastRow) {
122
- $bottomCell = $lastRow;
124
+ const $parent = $target.parentElement;
125
+ if ($parent) {
126
+ const $lastEl = $parent.lastElementChild;
127
+ if ($lastEl instanceof HTMLTableRowElement) {
128
+ $bottomCell = $lastEl;
123
129
  }
124
130
  }
125
131
  }
@@ -127,61 +133,75 @@ const getBottomCell = (event) => {
127
133
  // handle other contexts
128
134
  }
129
135
  if ($bottomCell && (!isFocusable($bottomCell) || !isVisible($bottomCell))) {
130
- return _getUpCell($bottomCell);
136
+ return getUpCellEl($bottomCell);
131
137
  }
132
138
  return $bottomCell;
133
139
  };
134
140
  const getPrevCell = (event) => {
135
- const $target = event.target;
136
- return _getPrevCell($target);
141
+ if (!(event.target instanceof HTMLElement))
142
+ return undefined;
143
+ return getPrevCellEl(event.target);
137
144
  };
138
- const _getPrevCell = (element) => {
145
+ const getPrevCellEl = (element) => {
139
146
  let $prevCell;
140
- if (element.previousElementSibling) {
141
- $prevCell = element.previousElementSibling;
147
+ const $prevSibling = element.previousElementSibling;
148
+ if ($prevSibling instanceof HTMLElement) {
149
+ $prevCell = $prevSibling;
142
150
  }
143
151
  else {
144
152
  const $prevRow = element.parentElement?.previousElementSibling;
145
- $prevCell = $prevRow?.lastElementChild;
153
+ const $lastEl = $prevRow?.lastElementChild;
154
+ if ($lastEl instanceof HTMLElement) {
155
+ $prevCell = $lastEl;
156
+ }
146
157
  }
147
158
  if ($prevCell && (!isFocusable($prevCell) || !isVisible($prevCell))) {
148
- return _getPrevCell($prevCell);
159
+ return getPrevCellEl($prevCell);
149
160
  }
150
161
  return $prevCell;
151
162
  };
152
163
  const getNextCell = (event) => {
153
- const $target = event.target;
154
- return _getNextCell($target);
164
+ if (!(event.target instanceof HTMLElement))
165
+ return undefined;
166
+ return getNextCellEl(event.target);
155
167
  };
156
- const _getNextCell = (element) => {
168
+ const getNextCellEl = (element) => {
157
169
  let $nextCell;
158
- if (element.nextElementSibling) {
159
- $nextCell = element.nextElementSibling;
170
+ const $nextSibling = element.nextElementSibling;
171
+ if ($nextSibling instanceof HTMLElement) {
172
+ $nextCell = $nextSibling;
160
173
  }
161
174
  else {
162
175
  const $nextRow = element.parentElement?.nextElementSibling;
163
- $nextCell = $nextRow?.firstElementChild;
176
+ const $firstEl = $nextRow?.firstElementChild;
177
+ if ($firstEl instanceof HTMLElement) {
178
+ $nextCell = $firstEl;
179
+ }
164
180
  }
165
181
  if ($nextCell && (!isFocusable($nextCell) || !isVisible($nextCell))) {
166
- return _getNextCell($nextCell);
182
+ return getNextCellEl($nextCell);
167
183
  }
168
184
  return $nextCell;
169
185
  };
170
186
  const getFirstCell = (event) => {
171
- const $target = event.target;
172
- const $parent = $target.parentElement;
173
- const $firstCell = $parent?.firstElementChild;
187
+ if (!(event.target instanceof HTMLElement))
188
+ return undefined;
189
+ const $parent = event.target.parentElement;
190
+ const $firstEl = $parent?.firstElementChild;
191
+ const $firstCell = $firstEl instanceof HTMLElement ? $firstEl : null;
174
192
  if ($firstCell && (!isFocusable($firstCell) || !isVisible($firstCell))) {
175
- return _getNextCell($firstCell);
193
+ return getNextCellEl($firstCell);
176
194
  }
177
195
  return $firstCell;
178
196
  };
179
197
  const getLastCell = (event) => {
180
- const $target = event.target;
181
- const $parent = $target.parentElement;
182
- const $lastCell = $parent?.lastElementChild;
198
+ if (!(event.target instanceof HTMLElement))
199
+ return undefined;
200
+ const $parent = event.target.parentElement;
201
+ const $lastEl = $parent?.lastElementChild;
202
+ const $lastCell = $lastEl instanceof HTMLElement ? $lastEl : null;
183
203
  if ($lastCell && (!isFocusable($lastCell) || !isVisible($lastCell))) {
184
- return _getPrevCell($lastCell);
204
+ return getPrevCellEl($lastCell);
185
205
  }
186
206
  return $lastCell;
187
207
  };
@@ -272,6 +292,8 @@ export const defaultKeypressHandlers = {
272
292
  }
273
293
  },
274
294
  'keydown.enter': (event) => {
295
+ if (!(event.target instanceof HTMLElement))
296
+ return;
275
297
  const $target = event.target;
276
298
  if ($target instanceof HTMLTableCellElement) {
277
299
  event.preventDefault();
@@ -286,6 +308,8 @@ export const defaultKeypressHandlers = {
286
308
  }
287
309
  },
288
310
  'keydown.shift.enter': (event) => {
311
+ if (!(event.target instanceof HTMLElement))
312
+ return;
289
313
  const $target = event.target;
290
314
  if ($target instanceof HTMLTableCellElement) {
291
315
  event.preventDefault();
@@ -324,27 +348,31 @@ export const defaultKeypressHandlers = {
324
348
  }
325
349
  },
326
350
  };
351
+ /**
352
+ * Gets the parent element from a keyboard navigation option.
353
+ * @internal
354
+ */
355
+ function getParentElement(option) {
356
+ let $parent = null;
357
+ if (option.parent) {
358
+ if (typeof option.parent === 'string') {
359
+ $parent = document.querySelector(option.parent);
360
+ }
361
+ else if (option.parent instanceof HTMLElement) {
362
+ $parent = option.parent;
363
+ }
364
+ else {
365
+ $parent = option.parent.value;
366
+ }
367
+ }
368
+ return $parent;
369
+ }
327
370
  /**
328
371
  * Keyboard navigation composable
329
372
  * @param options - Keyboard navigation options
330
373
  * @public
331
374
  */
332
375
  export function useKeyboardNav(options) {
333
- const getParentElement = (option) => {
334
- let $parent = null;
335
- if (option.parent) {
336
- if (typeof option.parent === 'string') {
337
- $parent = document.querySelector(option.parent);
338
- }
339
- else if (option.parent instanceof HTMLElement) {
340
- $parent = option.parent;
341
- }
342
- else {
343
- $parent = option.parent.value;
344
- }
345
- }
346
- return $parent;
347
- };
348
376
  const getSelectorsFromOption = (option) => {
349
377
  // assumes that option.selectors is provided
350
378
  const $parent = getParentElement(option);
@@ -360,6 +388,7 @@ export function useKeyboardNav(options) {
360
388
  selectors.push(element);
361
389
  }
362
390
  else {
391
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Vue component $el is typed as any; shape guaranteed by VNode contract
363
392
  selectors.push(element.$el);
364
393
  }
365
394
  }
@@ -374,6 +403,7 @@ export function useKeyboardNav(options) {
374
403
  selectors.push(element);
375
404
  }
376
405
  else {
406
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- Vue component $el is typed as any; shape guaranteed by VNode contract
377
407
  selectors.push(element.$el);
378
408
  }
379
409
  }
@@ -392,7 +422,7 @@ export function useKeyboardNav(options) {
392
422
  }
393
423
  else if ($parent) {
394
424
  // TODO: what should happen if no parent or selectors are provided?
395
- const $children = Array.from($parent.children);
425
+ const $children = Array.from($parent.children).filter((el) => el instanceof HTMLElement);
396
426
  selectors = $children.filter(selector => {
397
427
  // ignore elements not in the tab order or are not visible
398
428
  return isFocusable(selector) && isVisible(selector);
@@ -415,9 +445,9 @@ export function useKeyboardNav(options) {
415
445
  const listener = handlers[key];
416
446
  // check if the handler has modifiers, and if the modifier is active;
417
447
  // this is to ensure exact key-press matches
418
- const hasModifier = keys.filter(key => modifierKeys.includes(key));
419
- const isModifierActive = modifierKeys.some(key => {
420
- const modifierKey = key.charAt(0).toUpperCase() + key.slice(1);
448
+ const hasModifier = keys.filter(k => modifierKeys.includes(k));
449
+ const isModifierActive = modifierKeys.some(mk => {
450
+ const modifierKey = mk.charAt(0).toUpperCase() + mk.slice(1);
421
451
  return event.getModifierState(modifierKey);
422
452
  });
423
453
  if (hasModifier.length > 0) {