henry-search 1.0.2 → 1.0.4

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.
@@ -0,0 +1 @@
1
+ export const INSTANT_SEARCH_INDEX_NAME = "archived_performances"
@@ -0,0 +1,13 @@
1
+ import { toValue } from 'vue'
2
+
3
+ const FOCUSABLE_SELECTOR = `:not([tabindex^="-"]):not([disabled]):is(a[href],audio[controls],button,details summary,input,map area[href],select,svg a[xlink\:href],[tabindex],textarea,video[controls])`
4
+
5
+ export default function focusableElements(element, includeSelf = true) {
6
+ element = toValue(element)
7
+ const elements = [...element.querySelectorAll(FOCUSABLE_SELECTOR)]
8
+ if (includeSelf && element.matches(FOCUSABLE_SELECTOR)) {
9
+ elements.unshift(element)
10
+ }
11
+
12
+ return elements
13
+ }
@@ -0,0 +1,105 @@
1
+ import { toValue, onMounted } from 'vue'
2
+
3
+ import focusableElements from './FocusableElements.js'
4
+
5
+ /**
6
+ * Default key filters. These should be functions that 'filter out' what
7
+ * elements should be considered when a key is hit.
8
+ */
9
+ const KEY_FILTERS = {
10
+ ArrowRight: elements => elements.filter(({ x, top, bottom }) => x > 0 && top < 0 && bottom > 0),
11
+ ArrowLeft: elements => elements.filter(({ x, top, bottom }) => x < 0 && top < 0 && bottom > 0),
12
+ ArrowDown: elements => elements.filter(({ y, left, right }) => y > 0 && left < 0 && right > 0),
13
+ ArrowUp: elements => elements.filter(({ y, left, right }) => y < 0 && left < 0 && right > 0),
14
+ Home: elements => elements.length && elements.slice(0, 1),
15
+ End: elements => elements.length && elements.slice(-1),
16
+ }
17
+
18
+ /**
19
+ * Retrieves where the element is drawn on screen (client rects).
20
+ * Adds in x and y for the center of the element.
21
+ */
22
+ const getElementRects = el => {
23
+ const rects = el.getClientRects()[0]
24
+
25
+ if (!rects || !rects.left) {
26
+ return null
27
+ }
28
+
29
+ return {
30
+ bottom: rects.bottom,
31
+ height: rects.height,
32
+ left: rects.left,
33
+ right: rects.right,
34
+ top: rects.top,
35
+ width: rects.width,
36
+ x: rects.left + rects.width / 2,
37
+ y: rects.top + rects.height / 2,
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Calls getElementRects for every element in nodeList, and adjust the
43
+ * values to be relative to origin for simpler follow up math. Also
44
+ * calculates the distance between the two elements' centers.
45
+ */
46
+ const augmentElementRects = (nodeList, origin) => {
47
+ const elements = []
48
+ origin = getElementRects(origin)
49
+
50
+ if (!origin) {
51
+ return elements
52
+ }
53
+
54
+ nodeList.forEach(el => {
55
+ const rects = getElementRects(el)
56
+ if (rects === null) {
57
+ return
58
+ }
59
+
60
+ rects.bottom -= origin.y
61
+ rects.left -= origin.x
62
+ rects.right -= origin.x
63
+ rects.top -= origin.y
64
+ rects.x -= origin.x
65
+ rects.y -= origin.y
66
+
67
+ const distance = Math.sqrt(rects.x * rects.x + rects.y * rects.y)
68
+
69
+ elements.push({ el, ...rects, distance })
70
+ })
71
+
72
+ return elements
73
+ }
74
+
75
+ /**
76
+ * useDirectionalKeys() takes any number of rootElements that it searches for
77
+ * focusable elements and handles directional arrow moves between. Also
78
+ * supports Home and End.
79
+ */
80
+ export default function useDirectionalKeys (element) {
81
+ const findTarget = (el, key) => {
82
+ const elements = augmentElementRects(focusableElements(element), el)
83
+ if (key in KEY_FILTERS) {
84
+ return KEY_FILTERS[key](elements).reduce(
85
+ (closest, el) => {
86
+ return el.distance < closest.distance ? el : closest
87
+ },
88
+ { distance: Infinity }
89
+ )
90
+ }
91
+ return null
92
+ }
93
+
94
+ const handler = evt => {
95
+ const newTarget = findTarget(evt.target, evt.key)
96
+
97
+ if (newTarget?.el) {
98
+ evt.preventDefault()
99
+ evt.stopPropagation()
100
+ newTarget.el.focus()
101
+ }
102
+ }
103
+
104
+ element.addEventListener('keydown', handler)
105
+ }
@@ -0,0 +1,52 @@
1
+ import { ref, toValue, watchEffect } from 'vue'
2
+
3
+ export default function focusWithArrows(
4
+ elements,
5
+ {
6
+ includeHomeEnd = true,
7
+ } = {}
8
+ ) {
9
+
10
+ const KEY_BEHAVIORS = {
11
+ ArrowLeft: i => Math.max(0, i - 1),
12
+ ArrowRight: i => Math.min(handledElements.length - 1, i + 1),
13
+ }
14
+
15
+ if (includeHomeEnd) {
16
+ KEY_BEHAVIORS.Home = () => 0
17
+ KEY_BEHAVIORS.End = () => handledElements.length - 1
18
+ }
19
+
20
+ const focus = ref(null)
21
+
22
+ const handleKeydown = event => {
23
+ if (event.key in KEY_BEHAVIORS) {
24
+ event.preventDefault()
25
+ const i = handledElements.indexOf(event.target)
26
+
27
+ focus.value = handledElements[KEY_BEHAVIORS[event.key](i)]
28
+ focus.value.focus()
29
+ }
30
+ }
31
+
32
+ const handledElements = []
33
+
34
+ watchEffect(() => {
35
+ (toValue(elements) || [])
36
+ .filter(elem => !handledElements.includes(elem))
37
+ .forEach(elem => {
38
+ elem.addEventListener('keydown', handleKeydown)
39
+ elem.addEventListener('focus', event => {
40
+ focus.value = event.target
41
+ event.target.addEventListener('blur', () => focus.value = null, { once: true })
42
+ })
43
+ handledElements.push(elem)
44
+
45
+ if (document.activeElement === elem) {
46
+ focus.value = elem
47
+ }
48
+ })
49
+ })
50
+
51
+ return focus
52
+ }
@@ -0,0 +1,15 @@
1
+ export default function formatDate(unix_timestamp, detail = false) {
2
+ // multiplied by 1000 so that the argument is in milliseconds, not seconds
3
+ const date = new Date(unix_timestamp * 1000)
4
+ const days = ["Sun", "Mon", "Tues", "Weds", "Thurs", "Fri", "Sat"]
5
+ const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
6
+ const hour = date.getHours() + 1 > 12 ? date.getHours() - 11 : date.getHours() + 1
7
+ const amPm = date.getHours() + 1 > 12 ? "pm" : "am"
8
+ const minutes = "0" + date.getMinutes()
9
+
10
+ if (detail) {
11
+ return `${days[date.getDate()]}, ${(months[date.getMonth()]).substring(0, 3)} ${date.getDate()}, ${hour}:${minutes.substr(-2)}${amPm} EDT`
12
+ } else {
13
+ return `${date.getMonth() + 1}-${date.getDate() + 1}-${date.getFullYear()}`
14
+ }
15
+ }
@@ -0,0 +1,10 @@
1
+ export default function slugify(str) {
2
+ return String(str)
3
+ .normalize('NFKD') // split accented characters into their base characters and diacritical marks
4
+ .replace(/[\u0300-\u036f]/g, '') // remove all the accents, which happen to be all in the \u03xx UNICODE block.
5
+ .trim() // trim leading or trailing whitespace
6
+ .toLowerCase() // convert to lowercase
7
+ .replace(/[^a-z0-9 -]/g, '') // remove non-alphanumeric characters
8
+ .replace(/\s+/g, '-') // replace spaces with hyphens
9
+ .replace(/-+/g, '-'); // remove consecutive hyphens
10
+ }
package/src/main.js CHANGED
@@ -5,6 +5,8 @@ import { createApp } from 'vue'
5
5
  // createApp(App).mount('#app')
6
6
 
7
7
  import Search from './components/Search.vue'
8
+ import SearchDetail from './components/SearchDetail.vue'
9
+ import SearchHistory from './components/SearchHistory.vue'
8
10
 
9
11
  export default {
10
12
 
@@ -16,4 +18,4 @@ export default {
16
18
 
17
19
  }
18
20
 
19
- export { Search }
21
+ export { Search, SearchDetail, SearchHistory }