Skip to content

Commit

Permalink
Improve keyboard navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
dnknth committed Feb 21, 2024
1 parent 83d1566 commit e6de333
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 17 deletions.
6 changes: 5 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@
}
button, .btn, [type="button"] {
@apply border-none px-3 py-2 rounded text-back dark:text-front font-medium;
@apply px-3 py-2 rounded text-back dark:text-front font-medium outline-none;
}
button.btn {
@apply border-solid border-back border-2 focus:border-primary dark:focus:border-front;
}
select {
Expand Down
2 changes: 1 addition & 1 deletion src/components/SearchResults.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<popover :open="show" @update:open="results = []">
<popover :open="show" @update:open="results = []" @select="done(results[$event].dn)">
<li v-for="item in results" :key="item.dn" @click="done(item.dn)"
:title="label == 'dn' ? '' : trim(item.dn)" role="menuitem">
{{ item[label] }}
Expand Down
2 changes: 1 addition & 1 deletion src/components/editor/AttributeRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<i class="fa fa-trash ml-2 relative -top-0.5 control" @click="updateValue(index, '')"></i>
</span>
</span>
<input v-else :value="values[index]" :id="attr + '-' + index" :type="type"
<input v-else :value="values[index]" :id="attr + '-' + index" :type="type" autocomplete="off"
class="w-[90%] glyph outline-none bg-back border-x-0 border-t-0 border-b border-solid border-front/20 focus:border-primary px-1"
:class="{ structural: isStructural(val), auto: defaultValue, illegal: (illegal && !empty) || duplicate(index) }"
:placeholder="placeholder" :disabled="disabled" :title="time ? dateString(val) : ''"
Expand Down
2 changes: 1 addition & 1 deletion src/components/editor/AttributeSearch.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<popover :open="show" @update:open="results = []">
<popover :open="show" @update:open="results = []" @select="done(results[$event].name)">
<li v-for="item in results" :key="item.oid" @click="done(item.name)"
:title="item.oid" role="menuitem">
{{ item.name }}
Expand Down
6 changes: 3 additions & 3 deletions src/components/editor/EntryEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@
<div class="w-1/4"></div>
<div class="w-3/4 pl-4">
<div class="w-[90%] space-x-3">
<button type="submit" class="btn bg-primary/70"
<button type="submit" class="btn bg-primary/70" tabindex="0"
accesskey="s" :disabled="invalid.length != 0">Submit</button>
<button type="reset" v-if="!entry.meta.isNew" accesskey="r"
class="btn bg-secondary">Reset</button>
<button class="btn float-right bg-secondary" accesskey="a"
tabindex="0" class="btn bg-secondary">Reset</button>
<button class="btn float-right bg-secondary" accesskey="a" tabindex="0"
v-if="!entry.meta.isNew" @click.prevent="modal = 'add-attribute';">
Add attribute…
</button>
Expand Down
4 changes: 2 additions & 2 deletions src/components/ui/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@

<div v-show="!hideFooter" class="ui-modal-footer flex justify-end w-full p-4 space-x-3">
<slot name="footer">
<button id="ui-modal-cancel" @click="onCancel" type="button" :class="cancelClasses">
<button id="ui-modal-cancel" @click="onCancel" type="button" class="btn" :class="cancelClasses" tabindex="0">
<slot name="modal-cancel">{{ cancelTitle }}</slot>
</button>
<button id="ui-modal-ok" @click.stop="onOk" type="button" :class="okClasses">
<button id="ui-modal-ok" @click.stop="onOk" type="button" class="btn" :class="okClasses" tabindex="0">
<slot name="modal-ok">{{ okTitle }}</slot>
</button>
</slot>
Expand Down
75 changes: 67 additions & 8 deletions src/components/ui/Popover.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,93 @@
<transition name="fade" @after-enter="emit('opened')" @after-leave="emit('closed')">
<div v-if="open"
class="ui-popover absolute z-10 border border-front/70 rounded min-w-max text-front bg-back list-none">
<ul class="bg-front/5 dark:bg-front/10 py-2" @click="close">
<ul class="bg-front/5 dark:bg-front/10 py-2" ref="items" @click="close">
<slot></slot>
</ul>
</div>
</transition>
</template>

<script setup>
import { onMounted } from 'vue';
import { useEventListener } from '@vueuse/core';
import { onMounted, ref, watch } from 'vue';
import { useEventListener, useMouseInElement } from '@vueuse/core';
const props = defineProps({ open: Boolean }),
emit = defineEmits(['opened', 'closed', 'update:open']);
emit = defineEmits(['opened', 'closed', 'update:open', 'select']),
items = ref(null),
selected = ref(null),
{ isOutside } = useMouseInElement(items);
function close() {
selected.value = undefined;
if (props.open) emit('update:open');
}
function move(offset) {
const maxpos = items.value.children.length - 1;
if (selected.value == null) {
selected.value = offset > 0 ? 0 : maxpos;
}
else {
selected.value += offset;
if (selected.value > maxpos) selected.value = 0;
else if (selected.value < 0) selected.value = maxpos;
}
}
function scroll(e) {
if (!props.open || !items.value) return;
switch (e.key) {
case 'Esc':
case 'Escape':
close();
break;
case 'ArrowDown':
move(1);
e.preventDefault();
break;
case 'ArrowUp':
move(-1);
e.preventDefault();
break;
case 'Enter':
emit('select', selected.value);
e.preventDefault();
break;
}
}
onMounted(() => {
useEventListener(document, 'keydown', e => {
if (e.key == 'Esc' || e.key == 'Escape') close();
});
useEventListener(document, 'keydown', scroll);
useEventListener(document, 'click', close);
});
watch(selected, (pos) => {
if (!props.open || !items.value) return;
for (let child of items.value.children) {
child.classList.remove('selected');
}
if (pos != null) items.value.children[pos].classList.add('selected');
});
watch(isOutside, (outside) => {
for (let child of items.value.children) {
if (outside) {
child.classList.remove('hover:bg-primary/40');
}
else {
selected.value = null;
child.classList.add('hover:bg-primary/40');
}
}
});
</script>

<style>
.ui-popover [role=menuitem] {
@apply cursor-pointer px-4 hover:bg-primary/40;
@apply cursor-pointer px-4;
}
.ui-popover [role=menuitem].selected {
@apply bg-primary/40;
}
</style>

0 comments on commit e6de333

Please sign in to comment.