Skip to content

Commit 5fe0736

Browse files
committed
feat: use Enter to select the first url item
1 parent dc11d6d commit 5fe0736

File tree

1 file changed

+47
-21
lines changed
  • src/pages/app/components/Limit/LimitModify/Sop/Step2

1 file changed

+47
-21
lines changed

src/pages/app/components/Limit/LimitModify/Sop/Step2/SiteInput.tsx

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import Flex from '@pages/components/Flex'
55
import { selectAllSites } from '@service/site-service'
66
import { cleanCond } from '@util/limit'
77
import { extractHostname, isBrowserUrl } from '@util/pattern'
8-
import { ElMessage, ElSelectV2, ElText, type SelectV2Instance } from 'element-plus'
9-
import { computed, defineComponent, ref, type StyleValue } from 'vue'
8+
import { ElMessage, ElSelectV2, ElText, useNamespace, type SelectV2Instance } from 'element-plus'
9+
import { computed, defineComponent, onMounted, ref, type StyleValue } from 'vue'
1010

1111
type Props = {
1212
onAdd: (url: string) => string | undefined
@@ -27,54 +27,80 @@ const fetchAllHosts = async () => {
2727
return Array.from(hostSet)
2828
}
2929

30-
const useUrlSelect = () => {
30+
const useUrlSelect = ({ onAdd }: Props) => {
3131
const { data: allHosts } = useRequest(fetchAllHosts)
3232
const [input, onFilter] = useDebounceState('', 50)
3333
const inputUrl = computed(() => {
34-
const inputVal = input.value
35-
return inputVal ? cleanCond(inputVal) : undefined
34+
const clean = cleanCond(input.value)
35+
if (!clean) return {}
36+
const slashIdx = clean.indexOf('/')
37+
return slashIdx === -1 ? { full: clean } : { full: clean, domain: clean.substring(0, slashIdx) }
3638
})
3739

3840
const options = computed(() => {
39-
const urlVal = inputUrl.value
41+
const { full, domain } = inputUrl.value
4042
const result: string[] = []
41-
if (urlVal) {
42-
result.push(urlVal)
43-
allHosts.value?.forEach(host => host.includes(urlVal) && host !== urlVal && result.push(host))
43+
if (full) {
44+
result.push(full)
45+
domain && result.push(domain)
46+
allHosts.value?.forEach(host => host.includes(full) && host !== full && host !== domain && result.push(host))
4447
} else {
4548
allHosts.value?.forEach(h => result.push(h))
4649
}
4750
return result.map(value => ({ value, label: value }))
4851
})
4952

50-
return { options, onFilter }
51-
}
52-
53-
const SiteInput = defineComponent<Props>(props => {
54-
const { options, onFilter } = useUrlSelect()
55-
const selectEl = ref<SelectV2Instance>()
53+
const selectInst = ref<SelectV2Instance>()
5654

5755
const warnAndFocus = (msg: string) => {
5856
ElMessage.warning(msg)
59-
selectEl.value?.focus()
57+
selectInst.value?.focus()
6058
}
6159

62-
const handleAdd = (url: string) => {
63-
const errMsg = props.onAdd(url)
60+
const onSelected = (url: string) => {
61+
const errMsg = onAdd(url)
6462
if (errMsg) {
6563
return warnAndFocus(errMsg)
6664
} else {
67-
selectEl.value?.handleClear()
65+
selectInst.value?.handleClear()
6866
}
6967
}
7068

69+
const selectNs = useNamespace('select')
70+
71+
onMounted(() => {
72+
const el = (selectInst.value?.$el as HTMLDivElement)
73+
if (!el) return
74+
const input = el.querySelector('input')
75+
input?.addEventListener('keyup', ev => {
76+
if (ev.code !== 'Enter') return
77+
console.log(`.${selectNs.be('dropdown', 'item')}.is-hovering`)
78+
const hovered = el.querySelector(`.${selectNs.be('dropdown', 'item')}.is-hovering`)
79+
const first = options.value[0]?.value
80+
if (!hovered && first) {
81+
onSelected(first)
82+
ev.stopImmediatePropagation()
83+
}
84+
})
85+
})
86+
87+
return {
88+
options, onFilter, onSelected,
89+
selectInst,
90+
}
91+
}
92+
93+
const SiteInput = defineComponent<Props>(props => {
94+
const { options, onFilter, onSelected, selectInst } = useUrlSelect(props)
95+
7196
return () => (
7297
<Flex width="100%" column gap={5}>
7398
<ElSelectV2
7499
id='site-input' // used for e2e tests
75-
onChange={handleAdd}
76-
ref={selectEl} options={options.value}
100+
onChange={onSelected}
101+
ref={selectInst} options={options.value}
77102
filterable filterMethod={onFilter}
103+
teleported={false} // not teleported, need to find hovered item
78104
placeholder="e.g. www.demo.com, *.demo.com, demo.com/blog/*, demo.com/**, +www.demo.com/blog/list"
79105
/>
80106
<ElText style={{ textAlign: 'start', width: '100%', paddingInlineStart: '10px' } satisfies StyleValue}>

0 commit comments

Comments
 (0)