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

feat: Auto-focus and select file name for create new spec modal #22284

Merged
merged 11 commits into from Jun 16, 2022
11 changes: 11 additions & 0 deletions packages/app/src/specs/CreateSpecModal.cy.tsx
Expand Up @@ -44,6 +44,17 @@ describe('<CreateSpecModal />', () => {
cy.get(modalSelector).should('be.visible')

cy.percySnapshot()
}),
astone123 marked this conversation as resolved.
Show resolved Hide resolved
it('focuses text input and selects file name by default', () => {
cy.focused().as('specNameInput')

// focused should yield the input element since it should be auto-focused
cy.get('@specNameInput').invoke('val').should('equal', 'cypress/e2e/ComponentName.cy.js')

// only the file name should be focused, so backspacing should erase the whole file name
cy.get('@specNameInput').type('{backspace}')

cy.get('@specNameInput').invoke('val').should('equal', 'cypress/e2e/.cy.js')
})

describe('dismissing', () => {
Expand Down
26 changes: 25 additions & 1 deletion packages/app/src/specs/generators/EmptyGenerator.vue
Expand Up @@ -4,6 +4,7 @@
<div class="p-24px w-720px">
<Input
v-model="specFile"
:input-ref="inputRefFn"
:placeholder="t('createSpec.e2e.importEmptySpec.inputPlaceholder')"
:aria-label="t('createSpec.e2e.importEmptySpec.inputPlaceholder')"
:has-error="hasError"
Expand Down Expand Up @@ -123,7 +124,7 @@
</template>

<script setup lang="ts">
import { ref, watch, computed } from 'vue'
import { ref, watch, computed, onMounted } from 'vue'
import { useI18n } from '@packages/frontend-shared/src/locales/i18n'
import Input from '@packages/frontend-shared/src/components/Input.vue'
import Button from '@packages/frontend-shared/src/components/Button.vue'
Expand Down Expand Up @@ -180,6 +181,10 @@ const emits = defineEmits<{

const { title } = useVModels(props, emits)

const inputRef = ref<HTMLInputElement>()

const inputRefFn = () => inputRef

const specFile = ref(props.specFileName)

const matches = useMutation(EmptyGenerator_MatchSpecFileDocument)
Expand All @@ -190,6 +195,25 @@ const hasError = computed(() => !isValidSpecFile.value && !!specFile.value)

const result = ref<GeneratorSuccessFileFragment | null>(null)

function getFileNameIndexes (inputValue: string, match: RegExpMatchArray): number[] {
return [match.index || 0, inputValue.indexOf(match[0]) + match[0].length]
}

onMounted(() => {
// Focus text input and try to pre-select file name
inputRef.value?.focus()

const fileNameRegex = /[ \w-]+(?=\.)/
ZachJW34 marked this conversation as resolved.
Show resolved Hide resolved
const inputValue = inputRef.value?.value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is inputRef?.value.value the same as props.specFileName? If so, we should grab it there - better not to rely on a DOM element for the source of truth. I could be wrong about this, though.


We have multiple inputRef.value? calls - seems like we should just do

onMounted(() => {
  if (!inputRef?.value) {
    return
  }

  // the stuff
})

That way, we don't need to keep checking. If inputRef isn't defined for any reason, it seems we don't want to do any of the other behavior here, anyway.

const match = inputValue?.match(fileNameRegex)

if (inputValue && match) {
const [startSelectionIndex, endSelectionIndex] = getFileNameIndexes(inputValue, match)
astone123 marked this conversation as resolved.
Show resolved Hide resolved

inputRef.value?.setSelectionRange(startSelectionIndex, endSelectionIndex)
}
})

whenever(result, () => {
title.value = t('createSpec.successPage.header')
emits('updateTitle', t('createSpec.successPage.header'))
Expand Down