Browse Source

fix: tab focus issue in shared form and expanded form

pull/7298/head
Ramesh Mane 8 months ago
parent
commit
44754e1e9b
  1. 17
      packages/nc-gui/components/cell/Currency.vue
  2. 2
      packages/nc-gui/components/cell/DatePicker.vue
  3. 7
      packages/nc-gui/components/cell/Decimal.vue
  4. 6
      packages/nc-gui/components/cell/Duration.vue
  5. 6
      packages/nc-gui/components/cell/Email.vue
  6. 7
      packages/nc-gui/components/cell/Float.vue
  7. 7
      packages/nc-gui/components/cell/Integer.vue
  8. 19
      packages/nc-gui/components/cell/Percent.vue
  9. 7
      packages/nc-gui/components/cell/PhoneNumber.vue
  10. 17
      packages/nc-gui/components/cell/Text.vue
  11. 3
      packages/nc-gui/components/cell/TextArea.vue
  12. 6
      packages/nc-gui/components/cell/Url.vue
  13. 23
      packages/nc-gui/components/smartsheet/DivDataCell.vue

17
packages/nc-gui/components/cell/Currency.vue

@ -1,6 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import { ColumnInj, EditColumnInj, EditModeInj, IsExpandedFormOpenInj, computed, inject, parseProp, useVModel } from '#imports' import {
ColumnInj,
EditColumnInj,
EditModeInj,
IsExpandedFormOpenInj,
IsFormInj,
computed,
inject,
parseProp,
useVModel,
} from '#imports'
interface Props { interface Props {
modelValue: number | null | undefined modelValue: number | null | undefined
@ -57,7 +67,10 @@ const currency = computed(() => {
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
const submitCurrency = () => { const submitCurrency = () => {
if (lastSaved.value !== vModel.value) { if (lastSaved.value !== vModel.value) {

2
packages/nc-gui/components/cell/DatePicker.vue

@ -241,7 +241,7 @@ const clickHandler = () => {
<a-date-picker <a-date-picker
v-model:value="localState" v-model:value="localState"
:picker="picker" :picker="picker"
tabindex="0" :tabindex="0"
:bordered="false" :bordered="false"
class="!w-full !py-1 !border-none" class="!w-full !py-1 !border-none"
:class="{ 'nc-null': modelValue === null && showNull, '!px-2': isExpandedFormOpen, '!px-0': !isExpandedFormOpen }" :class="{ 'nc-null': modelValue === null && showNull, '!px-2': isExpandedFormOpen, '!px-0': !isExpandedFormOpen }"

7
packages/nc-gui/components/cell/Decimal.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports' import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, IsFormInj, inject, useVModel } from '#imports'
interface Props { interface Props {
// when we set a number, then it is number type // when we set a number, then it is number type
@ -63,6 +63,8 @@ const precision = computed(() => {
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const isForm = inject(IsFormInj)!
// Handle the arrow keys as its default behavior is to increment/decrement the value // Handle the arrow keys as its default behavior is to increment/decrement the value
const onKeyDown = (e: any) => { const onKeyDown = (e: any) => {
if (e.key === 'ArrowDown') { if (e.key === 'ArrowDown') {
@ -80,7 +82,8 @@ const onKeyDown = (e: any) => {
} }
} }
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
watch(isExpandedFormOpen, () => { watch(isExpandedFormOpen, () => {
if (!isExpandedFormOpen.value) { if (!isExpandedFormOpen.value) {

6
packages/nc-gui/components/cell/Duration.vue

@ -5,6 +5,7 @@ import {
EditColumnInj, EditColumnInj,
EditModeInj, EditModeInj,
IsExpandedFormOpenInj, IsExpandedFormOpenInj,
IsFormInj,
computed, computed,
convertDurationToSeconds, convertDurationToSeconds,
convertMS2Duration, convertMS2Duration,
@ -83,7 +84,10 @@ const submitDuration = () => {
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
</script> </script>
<template> <template>

6
packages/nc-gui/components/cell/Email.vue

@ -4,6 +4,7 @@ import {
EditColumnInj, EditColumnInj,
EditModeInj, EditModeInj,
IsExpandedFormOpenInj, IsExpandedFormOpenInj,
IsFormInj,
IsSurveyFormInj, IsSurveyFormInj,
computed, computed,
inject, inject,
@ -50,7 +51,10 @@ const validEmail = computed(() => vModel.value && validateEmail(vModel.value))
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
watch( watch(
() => editEnabled.value, () => editEnabled.value,

7
packages/nc-gui/components/cell/Float.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports' import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, IsFormInj, inject, useVModel } from '#imports'
interface Props { interface Props {
// when we set a number, then it is number type // when we set a number, then it is number type
@ -40,7 +40,10 @@ const vModel = computed({
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
</script> </script>
<template> <template>

7
packages/nc-gui/components/cell/Integer.vue

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports' import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, IsFormInj, inject, useVModel } from '#imports'
interface Props { interface Props {
// when we set a number, then it is number type // when we set a number, then it is number type
@ -48,7 +48,10 @@ const vModel = computed({
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
function onKeyDown(e: any) { function onKeyDown(e: any) {
const cmdOrCtrl = isMac() ? e.metaKey : e.ctrlKey const cmdOrCtrl = isMac() ? e.metaKey : e.ctrlKey

19
packages/nc-gui/components/cell/Percent.vue

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, inject, useVModel } from '#imports' import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, IsFormInj, inject, useVModel } from '#imports'
interface Props { interface Props {
modelValue?: number | string | null modelValue?: number | string | null
@ -35,7 +35,10 @@ const vModel = computed({
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
const cellFocused = ref(false) const cellFocused = ref(false)
@ -84,18 +87,22 @@ const onMouseleave = () => {
} }
const onTabPress = (e: KeyboardEvent) => { const onTabPress = (e: KeyboardEvent) => {
if (e.shiftKey) { if (e.shiftKey && (isExpandedFormOpen.value || isForm.value)) {
e.preventDefault() e.preventDefault()
// Shift + Tab does not work for percent cell // Shift + Tab does not work for percent cell
// so we manually focus on the last form item // so we manually focus on the last form item
const focusesNcCellIndex = Array.from(
const focusesNcCellIndex = Array.from(document.querySelectorAll('.nc-expanded-form-row .nc-data-cell')).findIndex((el) => { document.querySelectorAll(`${isExpandedFormOpen.value ? '.nc-expanded-form-row' : '.nc-form-wrapper'} .nc-data-cell`),
).findIndex((el) => {
return el.querySelector('.nc-filter-value-select') === wrapperRef.value return el.querySelector('.nc-filter-value-select') === wrapperRef.value
}) })
if (focusesNcCellIndex >= 0) { if (focusesNcCellIndex >= 0) {
const nodes = document.querySelectorAll('.nc-expanded-form-row .nc-data-cell') const nodes = document.querySelectorAll(
`${isExpandedFormOpen.value ? '.nc-expanded-form-row' : '.nc-form-wrapper'} .nc-data-cell`,
)
for (let i = focusesNcCellIndex - 1; i >= 0; i--) { for (let i = focusesNcCellIndex - 1; i >= 0; i--) {
const lastFormItem = nodes[i].querySelector('[tabindex="0"]') as HTMLElement const lastFormItem = nodes[i].querySelector('[tabindex="0"]') as HTMLElement
if (lastFormItem) { if (lastFormItem) {

7
packages/nc-gui/components/cell/PhoneNumber.vue

@ -1,7 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import isMobilePhone from 'validator/lib/isMobilePhone' import isMobilePhone from 'validator/lib/isMobilePhone'
import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, IsSurveyFormInj, computed, inject } from '#imports' import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, IsFormInj, IsSurveyFormInj, computed, inject } from '#imports'
interface Props { interface Props {
modelValue: string | null | number | undefined modelValue: string | null | number | undefined
@ -42,7 +42,10 @@ const validEmail = computed(() => vModel.value && isMobilePhone(vModel.value))
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
watch( watch(
() => editEnabled.value, () => editEnabled.value,

17
packages/nc-gui/components/cell/Text.vue

@ -1,6 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import type { VNodeRef } from '@vue/runtime-core' import type { VNodeRef } from '@vue/runtime-core'
import { EditColumnInj, EditModeInj, IsExpandedFormOpenInj, ReadonlyInj, RowHeightInj, inject, ref, useVModel } from '#imports' import {
EditColumnInj,
EditModeInj,
IsExpandedFormOpenInj,
IsFormInj,
ReadonlyInj,
RowHeightInj,
inject,
ref,
useVModel,
} from '#imports'
interface Props { interface Props {
modelValue?: string | null modelValue?: string | null
@ -24,7 +34,10 @@ const vModel = useVModel(props, 'modelValue', emits)
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && !isForm.value && (el as HTMLInputElement)?.focus()
</script> </script>
<template> <template>

3
packages/nc-gui/components/cell/TextArea.vue

@ -55,7 +55,8 @@ const position = ref<
const isDragging = ref(false) const isDragging = ref(false)
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLTextAreaElement)?.focus() const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && isForm.value && (el as HTMLTextAreaElement)?.focus()
const height = computed(() => { const height = computed(() => {
if (isExpandedFormOpen.value) return 36 * 4 if (isExpandedFormOpen.value) return 36 * 4

6
packages/nc-gui/components/cell/Url.vue

@ -6,6 +6,7 @@ import {
EditColumnInj, EditColumnInj,
EditModeInj, EditModeInj,
IsExpandedFormOpenInj, IsExpandedFormOpenInj,
IsFormInj,
IsSurveyFormInj, IsSurveyFormInj,
computed, computed,
inject, inject,
@ -70,7 +71,10 @@ const { cellUrlOptions } = useCellUrlConfig(url)
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))! const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const focus: VNodeRef = (el) => !isExpandedFormOpen.value && !isEditColumn.value && (el as HTMLInputElement)?.focus() const isForm = inject(IsFormInj)!
const focus: VNodeRef = (el) =>
!isExpandedFormOpen.value && !isEditColumn.value && isForm.value && (el as HTMLInputElement)?.focus()
watch( watch(
() => editEnabled.value, () => editEnabled.value,

23
packages/nc-gui/components/smartsheet/DivDataCell.vue

@ -4,10 +4,31 @@ import { CurrentCellInj, ref } from '#imports'
const el = ref() const el = ref()
provide(CurrentCellInj, el) provide(CurrentCellInj, el)
const isExpandedFormOpen = inject(IsExpandedFormOpenInj, ref(false))!
const isForm = inject(IsFormInj)!
const onTabPress = () => {
if (!isExpandedFormOpen.value && !isForm.value) return
// Find the focused element
const focusedElement = document.activeElement
if (focusedElement) {
// Check if the focused element is a descendant of the wrapper
const closestWrapper = focusedElement.closest('.nc-data-cell')
// Scroll it into view
if (closestWrapper === el.value) {
el.value?.scrollIntoView({ block: 'center' })
}
}
}
</script> </script>
<template> <template>
<div ref="el" class="select-none nc-data-cell"> <div ref="el" class="select-none nc-data-cell" @keydown.tab="onTabPress">
<slot /> <slot />
</div> </div>
</template> </template>

Loading…
Cancel
Save