@stonecrop/utilities 0.13.12 → 0.13.14
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/package.json +1 -1
- package/dist/assets/sample_data/coa.json +0 -2362
- package/dist/assets/sample_data/financials.json +0 -252
- package/dist/assets/sample_data/forecast.json +0 -2792
- package/dist/assets/sample_data/forecast_items.json +0 -126
- package/dist/assets/sample_data/http_logs.json +0 -252
- package/dist/assets/sample_data/inbox.json +0 -355
- package/dist/assets/sample_data/parts.json +0 -1322
- package/dist/assets/sample_data/repos.json +0 -1142
- package/dist/composables/keyboard.js +0 -473
- package/dist/composables/visibility/index.js +0 -47
- package/dist/index.js +0 -8
- package/dist/naming-conventions.js +0 -135
- package/dist/sql-introspection.js +0 -260
- package/dist/src/naming-conventions.d.ts +0 -107
- package/dist/src/naming-conventions.d.ts.map +0 -1
- package/dist/src/naming-conventions.js +0 -135
- package/dist/src/sql-introspection.d.ts +0 -111
- package/dist/src/sql-introspection.d.ts.map +0 -1
- package/dist/src/sql-introspection.js +0 -260
- package/dist/src/tsdoc-metadata.json +0 -11
- package/dist/src/workflow-scaffolder.d.ts +0 -77
- package/dist/src/workflow-scaffolder.d.ts.map +0 -1
- package/dist/src/workflow-scaffolder.js +0 -194
- package/dist/tests/setup.d.ts +0 -2
- package/dist/tests/setup.d.ts.map +0 -1
- package/dist/tests/setup.js +0 -4
- package/dist/types/index.js +0 -0
- package/dist/utilities.umd.cjs +0 -2
- package/dist/utilities.umd.cjs.map +0 -1
- package/dist/workflow-scaffolder.js +0 -194
|
@@ -1,473 +0,0 @@
|
|
|
1
|
-
import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
2
|
-
import { useFocusWithin } from '@vueuse/core';
|
|
3
|
-
import { useElementVisibility } from './visibility';
|
|
4
|
-
// helper functions
|
|
5
|
-
const isVisible = (element) => {
|
|
6
|
-
let isVisible = useElementVisibility(element).value;
|
|
7
|
-
isVisible = isVisible && element.offsetHeight > 0;
|
|
8
|
-
return isVisible;
|
|
9
|
-
};
|
|
10
|
-
const isFocusable = (element) => {
|
|
11
|
-
return element.tabIndex >= 0;
|
|
12
|
-
};
|
|
13
|
-
// navigation functions
|
|
14
|
-
const getUpCell = (event) => {
|
|
15
|
-
const $target = event.target;
|
|
16
|
-
return _getUpCell($target);
|
|
17
|
-
};
|
|
18
|
-
const _getUpCell = (element) => {
|
|
19
|
-
let $upCell;
|
|
20
|
-
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;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
else if (element instanceof HTMLTableRowElement) {
|
|
31
|
-
const $prevRow = element.previousElementSibling;
|
|
32
|
-
if ($prevRow) {
|
|
33
|
-
$upCell = $prevRow;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// handle other contexts
|
|
38
|
-
}
|
|
39
|
-
if ($upCell && (!isFocusable($upCell) || !isVisible($upCell))) {
|
|
40
|
-
return _getUpCell($upCell);
|
|
41
|
-
}
|
|
42
|
-
return $upCell;
|
|
43
|
-
};
|
|
44
|
-
const getTopCell = (event) => {
|
|
45
|
-
const $target = event.target;
|
|
46
|
-
let $topCell;
|
|
47
|
-
if ($target instanceof HTMLTableCellElement) {
|
|
48
|
-
const $table = $target.parentElement?.parentElement;
|
|
49
|
-
if ($table) {
|
|
50
|
-
const $firstRow = $table.firstElementChild;
|
|
51
|
-
const $navCell = $firstRow?.children[$target.cellIndex];
|
|
52
|
-
if ($navCell) {
|
|
53
|
-
$topCell = $navCell;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
else if ($target instanceof HTMLTableRowElement) {
|
|
58
|
-
const $table = $target.parentElement;
|
|
59
|
-
if ($table) {
|
|
60
|
-
const $firstRow = $table.firstElementChild;
|
|
61
|
-
if ($firstRow) {
|
|
62
|
-
$topCell = $firstRow;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
// handle other contexts
|
|
68
|
-
}
|
|
69
|
-
if ($topCell && (!isFocusable($topCell) || !isVisible($topCell))) {
|
|
70
|
-
return _getDownCell($topCell);
|
|
71
|
-
}
|
|
72
|
-
return $topCell;
|
|
73
|
-
};
|
|
74
|
-
const getDownCell = (event) => {
|
|
75
|
-
const $target = event.target;
|
|
76
|
-
return _getDownCell($target);
|
|
77
|
-
};
|
|
78
|
-
const _getDownCell = (element) => {
|
|
79
|
-
let $downCell;
|
|
80
|
-
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;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
else if (element instanceof HTMLTableRowElement) {
|
|
91
|
-
const $nextRow = element.nextElementSibling;
|
|
92
|
-
if ($nextRow) {
|
|
93
|
-
$downCell = $nextRow;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
// handle other contexts
|
|
98
|
-
}
|
|
99
|
-
if ($downCell && (!isFocusable($downCell) || !isVisible($downCell))) {
|
|
100
|
-
return _getDownCell($downCell);
|
|
101
|
-
}
|
|
102
|
-
return $downCell;
|
|
103
|
-
};
|
|
104
|
-
const getBottomCell = (event) => {
|
|
105
|
-
const $target = event.target;
|
|
106
|
-
let $bottomCell;
|
|
107
|
-
if ($target instanceof HTMLTableCellElement) {
|
|
108
|
-
const $table = $target.parentElement?.parentElement;
|
|
109
|
-
if ($table) {
|
|
110
|
-
const $lastRow = $table.lastElementChild;
|
|
111
|
-
const $navCell = $lastRow?.children[$target.cellIndex];
|
|
112
|
-
if ($navCell) {
|
|
113
|
-
$bottomCell = $navCell;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else if ($target instanceof HTMLTableRowElement) {
|
|
118
|
-
const $table = $target.parentElement;
|
|
119
|
-
if ($table) {
|
|
120
|
-
const $lastRow = $table.lastElementChild;
|
|
121
|
-
if ($lastRow) {
|
|
122
|
-
$bottomCell = $lastRow;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
// handle other contexts
|
|
128
|
-
}
|
|
129
|
-
if ($bottomCell && (!isFocusable($bottomCell) || !isVisible($bottomCell))) {
|
|
130
|
-
return _getUpCell($bottomCell);
|
|
131
|
-
}
|
|
132
|
-
return $bottomCell;
|
|
133
|
-
};
|
|
134
|
-
const getPrevCell = (event) => {
|
|
135
|
-
const $target = event.target;
|
|
136
|
-
return _getPrevCell($target);
|
|
137
|
-
};
|
|
138
|
-
const _getPrevCell = (element) => {
|
|
139
|
-
let $prevCell;
|
|
140
|
-
if (element.previousElementSibling) {
|
|
141
|
-
$prevCell = element.previousElementSibling;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
const $prevRow = element.parentElement?.previousElementSibling;
|
|
145
|
-
$prevCell = $prevRow?.lastElementChild;
|
|
146
|
-
}
|
|
147
|
-
if ($prevCell && (!isFocusable($prevCell) || !isVisible($prevCell))) {
|
|
148
|
-
return _getPrevCell($prevCell);
|
|
149
|
-
}
|
|
150
|
-
return $prevCell;
|
|
151
|
-
};
|
|
152
|
-
const getNextCell = (event) => {
|
|
153
|
-
const $target = event.target;
|
|
154
|
-
return _getNextCell($target);
|
|
155
|
-
};
|
|
156
|
-
const _getNextCell = (element) => {
|
|
157
|
-
let $nextCell;
|
|
158
|
-
if (element.nextElementSibling) {
|
|
159
|
-
$nextCell = element.nextElementSibling;
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
const $nextRow = element.parentElement?.nextElementSibling;
|
|
163
|
-
$nextCell = $nextRow?.firstElementChild;
|
|
164
|
-
}
|
|
165
|
-
if ($nextCell && (!isFocusable($nextCell) || !isVisible($nextCell))) {
|
|
166
|
-
return _getNextCell($nextCell);
|
|
167
|
-
}
|
|
168
|
-
return $nextCell;
|
|
169
|
-
};
|
|
170
|
-
const getFirstCell = (event) => {
|
|
171
|
-
const $target = event.target;
|
|
172
|
-
const $parent = $target.parentElement;
|
|
173
|
-
const $firstCell = $parent?.firstElementChild;
|
|
174
|
-
if ($firstCell && (!isFocusable($firstCell) || !isVisible($firstCell))) {
|
|
175
|
-
return _getNextCell($firstCell);
|
|
176
|
-
}
|
|
177
|
-
return $firstCell;
|
|
178
|
-
};
|
|
179
|
-
const getLastCell = (event) => {
|
|
180
|
-
const $target = event.target;
|
|
181
|
-
const $parent = $target.parentElement;
|
|
182
|
-
const $lastCell = $parent?.lastElementChild;
|
|
183
|
-
if ($lastCell && (!isFocusable($lastCell) || !isVisible($lastCell))) {
|
|
184
|
-
return _getPrevCell($lastCell);
|
|
185
|
-
}
|
|
186
|
-
return $lastCell;
|
|
187
|
-
};
|
|
188
|
-
const modifierKeys = ['alt', 'control', 'shift', 'meta'];
|
|
189
|
-
const eventKeyMap = {
|
|
190
|
-
ArrowUp: 'up',
|
|
191
|
-
ArrowDown: 'down',
|
|
192
|
-
ArrowLeft: 'left',
|
|
193
|
-
ArrowRight: 'right',
|
|
194
|
-
};
|
|
195
|
-
/**
|
|
196
|
-
* Default keypress handlers for keyboard navigation
|
|
197
|
-
* @public
|
|
198
|
-
*/
|
|
199
|
-
export const defaultKeypressHandlers = {
|
|
200
|
-
'keydown.up': (event) => {
|
|
201
|
-
const $upCell = getUpCell(event);
|
|
202
|
-
if ($upCell) {
|
|
203
|
-
event.preventDefault();
|
|
204
|
-
event.stopPropagation();
|
|
205
|
-
$upCell.focus();
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
'keydown.down': (event) => {
|
|
209
|
-
const $downCell = getDownCell(event);
|
|
210
|
-
if ($downCell) {
|
|
211
|
-
event.preventDefault();
|
|
212
|
-
event.stopPropagation();
|
|
213
|
-
$downCell.focus();
|
|
214
|
-
}
|
|
215
|
-
},
|
|
216
|
-
'keydown.left': (event) => {
|
|
217
|
-
const $prevCell = getPrevCell(event);
|
|
218
|
-
// prevent default edit-cell behaviour on first cell
|
|
219
|
-
event.preventDefault();
|
|
220
|
-
event.stopPropagation();
|
|
221
|
-
if ($prevCell) {
|
|
222
|
-
$prevCell.focus();
|
|
223
|
-
}
|
|
224
|
-
},
|
|
225
|
-
'keydown.right': (event) => {
|
|
226
|
-
const $nextCell = getNextCell(event);
|
|
227
|
-
// prevent default edit-cell behaviour on last cell
|
|
228
|
-
event.preventDefault();
|
|
229
|
-
event.stopPropagation();
|
|
230
|
-
if ($nextCell) {
|
|
231
|
-
$nextCell.focus();
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
'keydown.control.up': (event) => {
|
|
235
|
-
const $topCell = getTopCell(event);
|
|
236
|
-
if ($topCell) {
|
|
237
|
-
event.preventDefault();
|
|
238
|
-
event.stopPropagation();
|
|
239
|
-
$topCell.focus();
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
'keydown.control.down': (event) => {
|
|
243
|
-
const $bottomCell = getBottomCell(event);
|
|
244
|
-
if ($bottomCell) {
|
|
245
|
-
event.preventDefault();
|
|
246
|
-
event.stopPropagation();
|
|
247
|
-
$bottomCell.focus();
|
|
248
|
-
}
|
|
249
|
-
},
|
|
250
|
-
'keydown.control.left': (event) => {
|
|
251
|
-
const $firstCell = getFirstCell(event);
|
|
252
|
-
if ($firstCell) {
|
|
253
|
-
event.preventDefault();
|
|
254
|
-
event.stopPropagation();
|
|
255
|
-
$firstCell.focus();
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
'keydown.control.right': (event) => {
|
|
259
|
-
const $lastCell = getLastCell(event);
|
|
260
|
-
if ($lastCell) {
|
|
261
|
-
event.preventDefault();
|
|
262
|
-
event.stopPropagation();
|
|
263
|
-
$lastCell.focus();
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
'keydown.end': (event) => {
|
|
267
|
-
const $lastCell = getLastCell(event);
|
|
268
|
-
if ($lastCell) {
|
|
269
|
-
event.preventDefault();
|
|
270
|
-
event.stopPropagation();
|
|
271
|
-
$lastCell.focus();
|
|
272
|
-
}
|
|
273
|
-
},
|
|
274
|
-
'keydown.enter': (event) => {
|
|
275
|
-
const $target = event.target;
|
|
276
|
-
if ($target instanceof HTMLTableCellElement) {
|
|
277
|
-
event.preventDefault();
|
|
278
|
-
event.stopPropagation();
|
|
279
|
-
const $downCell = getDownCell(event);
|
|
280
|
-
if ($downCell) {
|
|
281
|
-
$downCell.focus();
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
// handle other contexts
|
|
286
|
-
}
|
|
287
|
-
},
|
|
288
|
-
'keydown.shift.enter': (event) => {
|
|
289
|
-
const $target = event.target;
|
|
290
|
-
if ($target instanceof HTMLTableCellElement) {
|
|
291
|
-
event.preventDefault();
|
|
292
|
-
event.stopPropagation();
|
|
293
|
-
const $upCell = getUpCell(event);
|
|
294
|
-
if ($upCell) {
|
|
295
|
-
$upCell.focus();
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
else {
|
|
299
|
-
// handle other contexts
|
|
300
|
-
}
|
|
301
|
-
},
|
|
302
|
-
'keydown.home': (event) => {
|
|
303
|
-
const $firstCell = getFirstCell(event);
|
|
304
|
-
if ($firstCell) {
|
|
305
|
-
event.preventDefault();
|
|
306
|
-
event.stopPropagation();
|
|
307
|
-
$firstCell.focus();
|
|
308
|
-
}
|
|
309
|
-
},
|
|
310
|
-
'keydown.tab': (event) => {
|
|
311
|
-
const $nextCell = getNextCell(event);
|
|
312
|
-
if ($nextCell) {
|
|
313
|
-
event.preventDefault();
|
|
314
|
-
event.stopPropagation();
|
|
315
|
-
$nextCell.focus();
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
'keydown.shift.tab': (event) => {
|
|
319
|
-
const $prevCell = getPrevCell(event);
|
|
320
|
-
if ($prevCell) {
|
|
321
|
-
event.preventDefault();
|
|
322
|
-
event.stopPropagation();
|
|
323
|
-
$prevCell.focus();
|
|
324
|
-
}
|
|
325
|
-
},
|
|
326
|
-
};
|
|
327
|
-
/**
|
|
328
|
-
* Keyboard navigation composable
|
|
329
|
-
* @param options - Keyboard navigation options
|
|
330
|
-
* @public
|
|
331
|
-
*/
|
|
332
|
-
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
|
-
const getSelectorsFromOption = (option) => {
|
|
349
|
-
// assumes that option.selectors is provided
|
|
350
|
-
const $parent = getParentElement(option);
|
|
351
|
-
let selectors = [];
|
|
352
|
-
if (typeof option.selectors === 'string') {
|
|
353
|
-
selectors = $parent
|
|
354
|
-
? Array.from($parent.querySelectorAll(option.selectors))
|
|
355
|
-
: Array.from(document.querySelectorAll(option.selectors));
|
|
356
|
-
}
|
|
357
|
-
else if (Array.isArray(option.selectors)) {
|
|
358
|
-
for (const element of option.selectors) {
|
|
359
|
-
if (element instanceof HTMLElement) {
|
|
360
|
-
selectors.push(element);
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
selectors.push(element.$el);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
else if (option.selectors instanceof HTMLElement) {
|
|
368
|
-
selectors.push(option.selectors);
|
|
369
|
-
}
|
|
370
|
-
else if (option.selectors?.value) {
|
|
371
|
-
if (Array.isArray(option.selectors.value)) {
|
|
372
|
-
for (const element of option.selectors.value) {
|
|
373
|
-
if (element instanceof HTMLElement) {
|
|
374
|
-
selectors.push(element);
|
|
375
|
-
}
|
|
376
|
-
else {
|
|
377
|
-
selectors.push(element.$el);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
selectors.push(option.selectors.value);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return selectors;
|
|
386
|
-
};
|
|
387
|
-
const getSelectors = (option) => {
|
|
388
|
-
const $parent = getParentElement(option);
|
|
389
|
-
let selectors = [];
|
|
390
|
-
if (option.selectors) {
|
|
391
|
-
selectors = getSelectorsFromOption(option);
|
|
392
|
-
}
|
|
393
|
-
else if ($parent) {
|
|
394
|
-
// TODO: what should happen if no parent or selectors are provided?
|
|
395
|
-
const $children = Array.from($parent.children);
|
|
396
|
-
selectors = $children.filter(selector => {
|
|
397
|
-
// ignore elements not in the tab order or are not visible
|
|
398
|
-
return isFocusable(selector) && isVisible(selector);
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
return selectors;
|
|
402
|
-
};
|
|
403
|
-
const getEventListener = (option) => {
|
|
404
|
-
return (event) => {
|
|
405
|
-
const activeKey = eventKeyMap[event.key] || event.key.toLowerCase();
|
|
406
|
-
if (modifierKeys.includes(activeKey))
|
|
407
|
-
return; // ignore modifier key presses
|
|
408
|
-
const handlers = option.handlers || defaultKeypressHandlers;
|
|
409
|
-
for (const key of Object.keys(handlers)) {
|
|
410
|
-
const [eventType, ...keys] = key.split('.');
|
|
411
|
-
if (eventType !== 'keydown') {
|
|
412
|
-
continue;
|
|
413
|
-
}
|
|
414
|
-
if (keys.includes(activeKey)) {
|
|
415
|
-
const listener = handlers[key];
|
|
416
|
-
// check if the handler has modifiers, and if the modifier is active;
|
|
417
|
-
// 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);
|
|
421
|
-
return event.getModifierState(modifierKey);
|
|
422
|
-
});
|
|
423
|
-
if (hasModifier.length > 0) {
|
|
424
|
-
if (isModifierActive) {
|
|
425
|
-
for (const modifier of modifierKeys) {
|
|
426
|
-
if (keys.includes(modifier)) {
|
|
427
|
-
// docs: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/getModifierState
|
|
428
|
-
const modifierKey = modifier.charAt(0).toUpperCase() + modifier.slice(1);
|
|
429
|
-
if (event.getModifierState(modifierKey)) {
|
|
430
|
-
listener(event);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
else {
|
|
437
|
-
if (!isModifierActive) {
|
|
438
|
-
listener(event);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
};
|
|
444
|
-
};
|
|
445
|
-
const watchStopHandlers = [];
|
|
446
|
-
onMounted(() => {
|
|
447
|
-
for (const option of options) {
|
|
448
|
-
const $parent = getParentElement(option);
|
|
449
|
-
const selectors = getSelectors(option);
|
|
450
|
-
const listener = getEventListener(option);
|
|
451
|
-
const listenerElements = $parent
|
|
452
|
-
? [$parent] // watch for focus recursively within the parent element
|
|
453
|
-
: selectors; // watch for focus on each selector element TODO: too much JS?
|
|
454
|
-
for (const element of listenerElements) {
|
|
455
|
-
const { focused } = useFocusWithin(ref(element));
|
|
456
|
-
const stopHandler = watch(focused, value => {
|
|
457
|
-
if (value) {
|
|
458
|
-
element.addEventListener('keydown', listener);
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
element.removeEventListener('keydown', listener);
|
|
462
|
-
}
|
|
463
|
-
});
|
|
464
|
-
watchStopHandlers.push(stopHandler);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
});
|
|
468
|
-
onBeforeUnmount(() => {
|
|
469
|
-
for (const stopHandler of watchStopHandlers) {
|
|
470
|
-
stopHandler();
|
|
471
|
-
}
|
|
472
|
-
});
|
|
473
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { defaultWindow, unrefElement, useEventListener, } from '@vueuse/core';
|
|
2
|
-
import { ref, watch } from 'vue';
|
|
3
|
-
/**
|
|
4
|
-
* Tracks the visibility of an element within the viewport.
|
|
5
|
-
*
|
|
6
|
-
* Compatibility version to get Stonecrop keyboard navigation to work. This function is a copy of the
|
|
7
|
-
* `useElementVisibility` function from VueUse v9.13.0, with the `IntersectionObserver` API removed.
|
|
8
|
-
*
|
|
9
|
-
* This version uses the `getBoundingClientRect` method to determine if an element is visible
|
|
10
|
-
* in the viewport. This is less performant than the `IntersectionObserver` API, but it is
|
|
11
|
-
* more compatible.
|
|
12
|
-
*
|
|
13
|
-
* Note: the newer versions of the VueUse dependencies imported here are sufficient for this composable.
|
|
14
|
-
* (Last verified: v10.9.0 on May 2, 2024)
|
|
15
|
-
*
|
|
16
|
-
* @see https://v9-13-0.vueuse.org/core/useElementVisibility
|
|
17
|
-
* @param element - Element to track visibility for
|
|
18
|
-
* @param options - Configuration options (window, scrollTarget)
|
|
19
|
-
*/
|
|
20
|
-
export function useElementVisibility(element, { window = defaultWindow, scrollTarget } = {}) {
|
|
21
|
-
const elementIsVisible = ref(false);
|
|
22
|
-
const testBounding = () => {
|
|
23
|
-
if (!window)
|
|
24
|
-
return;
|
|
25
|
-
const document = window.document;
|
|
26
|
-
const el = unrefElement(element);
|
|
27
|
-
if (!el) {
|
|
28
|
-
elementIsVisible.value = false;
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
const rect = el.getBoundingClientRect();
|
|
32
|
-
elementIsVisible.value =
|
|
33
|
-
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
|
|
34
|
-
rect.left <= (window.innerWidth || document.documentElement.clientWidth) &&
|
|
35
|
-
rect.bottom >= 0 &&
|
|
36
|
-
rect.right >= 0;
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
watch(() => unrefElement(element), () => testBounding(), { immediate: true, flush: 'post' });
|
|
40
|
-
if (window) {
|
|
41
|
-
useEventListener(scrollTarget || window, 'scroll', testBounding, {
|
|
42
|
-
capture: false,
|
|
43
|
-
passive: true,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
return elementIsVisible;
|
|
47
|
-
}
|
package/dist/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { defaultKeypressHandlers, useKeyboardNav } from './composables/keyboard';
|
|
2
|
-
/**
|
|
3
|
-
* Install all utility components
|
|
4
|
-
* @param _app - Vue app instance
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
function install(_app /* options */) { }
|
|
8
|
-
export { defaultKeypressHandlers, install, useKeyboardNav };
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Naming Convention Utilities
|
|
3
|
-
* Converts between SQL snake_case and JavaScript camelCase naming conventions
|
|
4
|
-
* @packageDocumentation
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Converts snake_case to camelCase
|
|
8
|
-
* @param snakeCase - Snake case string
|
|
9
|
-
* @returns Camel case string
|
|
10
|
-
* @public
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* snakeToCamel('user_email') // 'userEmail'
|
|
14
|
-
* snakeToCamel('created_at') // 'createdAt'
|
|
15
|
-
* snakeToCamel('user_id') // 'userId'
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export function snakeToCamel(snakeCase) {
|
|
19
|
-
return snakeCase.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Converts camelCase to snake_case
|
|
23
|
-
* @param camelCase - Camel case string
|
|
24
|
-
* @returns Snake case string
|
|
25
|
-
* @public
|
|
26
|
-
* @example
|
|
27
|
-
* ```typescript
|
|
28
|
-
* camelToSnake('userEmail') // 'user_email'
|
|
29
|
-
* camelToSnake('createdAt') // 'created_at'
|
|
30
|
-
* camelToSnake('userId') // 'user_id'
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
|
-
export function camelToSnake(camelCase) {
|
|
34
|
-
return camelCase.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Converts snake_case to Title Case label
|
|
38
|
-
* @param snakeCase - Snake case string
|
|
39
|
-
* @returns Title case label
|
|
40
|
-
* @public
|
|
41
|
-
* @example
|
|
42
|
-
* ```typescript
|
|
43
|
-
* snakeToLabel('user_email') // 'User Email'
|
|
44
|
-
* snakeToLabel('first_name') // 'First Name'
|
|
45
|
-
* snakeToLabel('created_at') // 'Created At'
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
export function snakeToLabel(snakeCase) {
|
|
49
|
-
return snakeCase
|
|
50
|
-
.split('_')
|
|
51
|
-
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
52
|
-
.join(' ');
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Converts camelCase to Title Case label
|
|
56
|
-
* @param camelCase - Camel case string
|
|
57
|
-
* @returns Title case label
|
|
58
|
-
* @public
|
|
59
|
-
* @example
|
|
60
|
-
* ```typescript
|
|
61
|
-
* camelToLabel('userEmail') // 'User Email'
|
|
62
|
-
* camelToLabel('firstName') // 'First Name'
|
|
63
|
-
* camelToLabel('createdAt') // 'Created At'
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
export function camelToLabel(camelCase) {
|
|
67
|
-
// Insert space before capital letters and capitalize first letter
|
|
68
|
-
const withSpaces = camelCase.replace(/([A-Z])/g, ' $1').trim();
|
|
69
|
-
return withSpaces.charAt(0).toUpperCase() + withSpaces.slice(1);
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Converts SQL column name to Stonecrop field naming convention
|
|
73
|
-
* Handles special cases like ID suffixes
|
|
74
|
-
* @param sqlName - SQL column name (snake_case)
|
|
75
|
-
* @returns Field name and label
|
|
76
|
-
* @public
|
|
77
|
-
* @example
|
|
78
|
-
* ```typescript
|
|
79
|
-
* convertSQLName('user_email')
|
|
80
|
-
* // { fieldname: 'userEmail', label: 'User Email', originalName: 'user_email' }
|
|
81
|
-
*
|
|
82
|
-
* convertSQLName('user_id')
|
|
83
|
-
* // { fieldname: 'userId', label: 'User', originalName: 'user_id' }
|
|
84
|
-
*
|
|
85
|
-
* convertSQLName('created_at')
|
|
86
|
-
* // { fieldname: 'createdAt', label: 'Created At', originalName: 'created_at' }
|
|
87
|
-
* ```
|
|
88
|
-
*/
|
|
89
|
-
export function convertSQLName(sqlName) {
|
|
90
|
-
const fieldname = snakeToCamel(sqlName);
|
|
91
|
-
// Generate label - special handling for _id suffix
|
|
92
|
-
let label;
|
|
93
|
-
if (sqlName.endsWith('_id')) {
|
|
94
|
-
// Remove _id suffix for label: user_id -> User
|
|
95
|
-
const withoutId = sqlName.slice(0, -3);
|
|
96
|
-
label = snakeToLabel(withoutId);
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
label = snakeToLabel(sqlName);
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
fieldname,
|
|
103
|
-
label,
|
|
104
|
-
originalName: sqlName,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
/**
|
|
108
|
-
* Batch converts multiple SQL column names
|
|
109
|
-
* @param sqlNames - Array of SQL column names
|
|
110
|
-
* @returns Array of name conversions
|
|
111
|
-
* @public
|
|
112
|
-
*/
|
|
113
|
-
export function convertSQLNames(sqlNames) {
|
|
114
|
-
return sqlNames.map(convertSQLName);
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Creates a bidirectional mapping between SQL and Stonecrop names
|
|
118
|
-
* @param sqlNames - Array of SQL column names
|
|
119
|
-
* @returns Mapping object with both directions
|
|
120
|
-
* @public
|
|
121
|
-
*/
|
|
122
|
-
export function createNameMapping(sqlNames) {
|
|
123
|
-
const conversions = convertSQLNames(sqlNames);
|
|
124
|
-
const sqlToFieldname = new Map();
|
|
125
|
-
const fieldnameToSQL = new Map();
|
|
126
|
-
for (const conversion of conversions) {
|
|
127
|
-
sqlToFieldname.set(conversion.originalName, conversion.fieldname);
|
|
128
|
-
fieldnameToSQL.set(conversion.fieldname, conversion.originalName);
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
sqlToFieldname,
|
|
132
|
-
fieldnameToSQL,
|
|
133
|
-
conversions,
|
|
134
|
-
};
|
|
135
|
-
}
|