Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nc fix/tab focus #7280

Merged
merged 5 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/nc-gui/components/cell/Checkbox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,16 @@ useSelectedCellKeyupListener(active, (e) => {

<template>
<div
class="flex cursor-pointer w-full h-full items-center"
class="flex cursor-pointer w-full h-full items-center focus:outline-transparent"
:class="{
'w-full flex-start pl-2': isForm || isGallery || isExpandedFormOpen,
'w-full justify-center': !isForm && !isGallery && !isExpandedFormOpen,
'nc-cell-hover-show': !vModel && !readOnly,
'opacity-0': readOnly && !vModel,
}"
tabindex="0"
@click="onClick(false, $event)"
@keydown.enter.stop="onClick(false, $event)"
>
<div
class="items-center"
Expand Down
2 changes: 1 addition & 1 deletion packages/nc-gui/components/cell/Currency.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ onMounted(() => {
:ref="focus"
v-model="vModel"
type="number"
class="w-full h-full text-sm border-none rounded-md outline-none"
class="w-full h-full text-sm border-none rounded-md outline-none focus:outline-transparent focus:ring-0"
:placeholder="isEditColumn ? $t('labels.optional') : ''"
@blur="submitCurrency"
@keydown.down.stop
Expand Down
2 changes: 2 additions & 0 deletions packages/nc-gui/components/cell/DatePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ const clickHandler = () => {
<a-date-picker
v-model:value="localState"
:picker="picker"
tabindex="0"
:bordered="false"
class="!w-full !px-1 !border-none"
:class="{ 'nc-null': modelValue === null && showNull }"
Expand All @@ -249,6 +250,7 @@ const clickHandler = () => {
:open="isOpen"
@click="clickHandler"
@update:open="updateOpen"
@keydown.enter="open = !open"
>
<template #suffixIcon></template>
</a-date-picker>
Expand Down
1 change: 1 addition & 0 deletions packages/nc-gui/components/cell/DateTimePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ const isColDisabled = computed(() => {
:open="isOpen"
@click="clickHandler"
@ok="okHandler"
@keydown.enter="open = !open"
>
<template #suffixIcon></template>
</a-date-picker>
Expand Down
51 changes: 30 additions & 21 deletions packages/nc-gui/components/cell/MultiSelect.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<script lang="ts" setup>
import { onUnmounted } from '@vue/runtime-core'
import { message } from 'ant-design-vue'
import tinycolor from 'tinycolor2'
import type { Select as AntSelect } from 'ant-design-vue'
import type { SelectOptionType, SelectOptionsType } from 'nocodb-sdk'
import {
ActiveCellInj,
CellClickHookInj,
ColumnInj,
EditColumnInj,
EditModeInj,
Expand Down Expand Up @@ -53,14 +51,14 @@ const isEditable = inject(EditModeInj, ref(false))

const activeCell = inject(ActiveCellInj, ref(false))

const isForm = inject(IsFormInj, ref(false))

// use both ActiveCellInj or EditModeInj to determine the active state
// since active will be false in case of form view
const active = computed(() => activeCell.value || isEditable.value)
const active = computed(() => activeCell.value || isEditable.value || isForm.value)

const isPublic = inject(IsPublicInj, ref(false))

const isForm = inject(IsFormInj, ref(false))

const isEditColumn = inject(EditColumnInj, ref(false))

const rowHeight = inject(RowHeightInj, ref(undefined))
Expand All @@ -71,6 +69,8 @@ const aselect = ref<typeof AntSelect>()

const isOpen = ref(false)

const isFocusing = ref(false)

const isKanban = inject(IsKanbanInj, ref(false))

const searchVal = ref<string | null>()
Expand Down Expand Up @@ -180,9 +180,7 @@ watch(isOpen, (n, _o) => {
if (!n) searchVal.value = ''

if (editAllowed.value) {
if (!n) {
aselect.value?.$el?.querySelector('input')?.blur()
} else {
if (n) {
aselect.value?.$el?.querySelector('input')?.focus()
}
}
Expand Down Expand Up @@ -299,22 +297,11 @@ const onTagClick = (e: Event, onClose: Function) => {
}
}

const cellClickHook = inject(CellClickHookInj, null)

const toggleMenu = () => {
if (cellClickHook) return
isOpen.value = editAllowed.value && !isOpen.value
}
if (isFocusing.value) return

const cellClickHookHandler = () => {
isOpen.value = editAllowed.value && !isOpen.value
}
onMounted(() => {
cellClickHook?.on(cellClickHookHandler)
})
onUnmounted(() => {
cellClickHook?.on(cellClickHookHandler)
})

const handleClose = (e: MouseEvent) => {
// close dropdown if clicked outside of dropdown
Expand All @@ -341,6 +328,26 @@ const selectedOpts = computed(() => {
return selectedOptions
}, [])
})

const onKeyDown = (e: KeyboardEvent) => {
// Tab
if (e.key === 'Tab') {
isOpen.value = false
return
}

e.stopPropagation()
}

const onFocus = () => {
isFocusing.value = true

setTimeout(() => {
isFocusing.value = false
}, 250)

isOpen.value = true
}
</script>

<template>
Expand Down Expand Up @@ -403,7 +410,9 @@ const selectedOpts = computed(() => {
:class="{ 'caret-transparent': !hasEditRoles }"
:dropdown-class-name="`nc-dropdown-multi-select-cell !min-w-200px ${isOpen ? 'active' : ''}`"
@search="search"
@keydown.stop
@keydown="onKeyDown"
@focus="onFocus"
@blur="isOpen = false"
>
<template #suffixIcon>
<GeneralIcon icon="arrowDown" class="text-gray-700 nc-select-expand-btn" />
Expand Down
48 changes: 47 additions & 1 deletion packages/nc-gui/components/cell/Percent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ const isEditColumn = inject(EditColumnInj, ref(false))

const _vModel = useVModel(props, 'modelValue', emits)

const wrapperRef = ref<HTMLElement>()

const vModel = computed({
get: () => _vModel.value,
set: (value) => {
Expand Down Expand Up @@ -56,6 +58,18 @@ const onBlur = () => {

const onFocus = () => {
cellFocused.value = true
editEnabled.value = true
expandedEditEnabled.value = true
}

const onWrapperFocus = () => {
cellFocused.value = true
editEnabled.value = true
expandedEditEnabled.value = true

nextTick(() => {
wrapperRef.value?.querySelector('input')?.focus()
})
}

const onMouseover = () => {
Expand All @@ -67,10 +81,41 @@ const onMouseleave = () => {
expandedEditEnabled.value = false
}
}

const onTabPress = (e: KeyboardEvent) => {
if (e.shiftKey) {
e.preventDefault()

// Shift + Tab does not work for percent cell
// so we manually focus on the last form item

const focusesNcCellIndex = Array.from(document.querySelectorAll('.nc-expanded-form-row .nc-data-cell')).findIndex((el) => {
return el.querySelector('.nc-filter-value-select') === wrapperRef.value
})

if (focusesNcCellIndex >= 0) {
const nodes = document.querySelectorAll('.nc-expanded-form-row .nc-data-cell')
for (let i = focusesNcCellIndex - 1; i >= 0; i--) {
const lastFormItem = nodes[i].querySelector('[tabindex="0"]') as HTMLElement
if (lastFormItem) {
lastFormItem.focus()
break
}
}
}
}
}
</script>

<template>
<div class="nc-filter-value-select w-full" @mouseover="onMouseover" @mouseleave="onMouseleave">
<div
ref="wrapperRef"
tabindex="0"
class="nc-filter-value-select w-full focus:outline-transparent"
@mouseover="onMouseover"
@mouseleave="onMouseleave"
@focus="onWrapperFocus"
>
<input
v-if="(!isExpandedFormOpen && editEnabled) || (isExpandedFormOpen && expandedEditEnabled)"
:ref="focus"
Expand All @@ -86,6 +131,7 @@ const onMouseleave = () => {
@keydown.right.stop
@keydown.up.stop
@keydown.delete.stop
@keydown.tab="onTabPress"
@selectstart.capture.stop
@mousedown.stop
/>
Expand Down
23 changes: 23 additions & 0 deletions packages/nc-gui/components/cell/Rating.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,37 @@ useSelectedCellKeyupListener(inject(ActiveCellInj, ref(false)), (e: KeyboardEven
vModel.value = +e.key === +vModel.value ? 0 : +e.key
}
})

const onKeyPress = (e: KeyboardEvent) => {
if (/^\d$/.test(e.key)) {
e.stopPropagation()
vModel.value = +e.key === +vModel.value ? 0 : +e.key
}
}

const rateDomRef = ref()

// Remove tabindex from rate inputs set by antd
watch(rateDomRef, () => {
if (!rateDomRef.value) return

const rateInputs = rateDomRef.value.$el.querySelectorAll('div[role="radio"]')
if (!rateInputs) return

for (let i = 0; i < rateInputs.length; i++) {
rateInputs[i].setAttribute('tabindex', '-1')
}
})
</script>

<template>
<a-rate
ref="rateDomRef"
v-model:value="vModel"
:disabled="readonly"
:count="ratingMeta.max"
:style="`color: ${ratingMeta.color}; padding: 0px 5px`"
@keydown="onKeyPress"
>
<template #character>
<MdiStar v-if="ratingMeta.icon.full === 'mdi-star'" class="text-sm" />
Expand Down