Skip to content

Commit f970a70

Browse files
authored
Merge pull request #34 from DKhalil/patch-1
feat: allow continuation of expander menu
2 parents 6c915ae + 7cb2f3c commit f970a70

File tree

3 files changed

+85
-4
lines changed

3 files changed

+85
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ The returned fragment should be consisted of filtered `[role=option]` items to b
8080
- `key`: The matched key; for example: `:`.
8181
- `item`: The selected item. This would be one of the `[role=option]`. Use this to work out the `value`.
8282
- `value`: A null value placeholder to replace the query. To replace the text query, simply re-assign this value.
83+
- `continue`: A boolean value to specify whether to continue autocompletion after inserting a value. Defaults to `false`. If set to `true`, will not add a space after inserted value and will keep firing the `text-expander-change` event.
8384
8485
```js
8586
const expander = document.querySelector('text-expander')

src/text-expander-element.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,18 @@ class TextExpander {
120120
const beginning = this.input.value.substring(0, match.position - match.key.length)
121121
const remaining = this.input.value.substring(match.position + match.text.length)
122122

123-
const detail = {item, key: match.key, value: null}
123+
const detail = {item, key: match.key, value: null, continue: false}
124124
const canceled = !this.expander.dispatchEvent(new CustomEvent('text-expander-value', {cancelable: true, detail}))
125125
if (canceled) return
126126

127127
if (!detail.value) return
128-
const suffix = this.expander.getAttribute('suffix') ?? ' '
128+
129+
let suffix = this.expander.getAttribute('suffix') ?? ' '
130+
131+
if (detail.continue) {
132+
suffix = ''
133+
}
134+
129135
const value = `${detail.value}${suffix}`
130136

131137
this.input.value = beginning + value + remaining
@@ -139,8 +145,11 @@ class TextExpander {
139145

140146
this.input.selectionStart = cursor
141147
this.input.selectionEnd = cursor
142-
this.lookBackIndex = cursor
143-
this.match = null
148+
149+
if (!detail.continue) {
150+
this.lookBackIndex = cursor
151+
this.match = null
152+
}
144153

145154
this.expander.dispatchEvent(
146155
new CustomEvent('text-expander-committed', {cancelable: false, detail: {input: this.input}})

test/text-expander-element-test.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,77 @@ describe('text-expander element', function () {
9292

9393
assert.deepEqual(receivedText, expectedText)
9494
})
95+
96+
it('dispatches value event after selecting item and closes', async function () {
97+
const expander = document.querySelector('text-expander')
98+
const input = expander.querySelector('textarea')
99+
const menu = document.createElement('ul')
100+
const item = document.createElement('li')
101+
item.setAttribute('role', 'option')
102+
menu.appendChild(item)
103+
104+
expander.addEventListener('text-expander-change', event => {
105+
const {provide} = event.detail
106+
provide(Promise.resolve({matched: true, fragment: menu}))
107+
})
108+
109+
expander.addEventListener('text-expander-value', event => {
110+
event.detail.value = ':1'
111+
})
112+
113+
input.focus()
114+
triggerInput(input, ':')
115+
await waitForAnimationFrame()
116+
assert.exists(expander.querySelector('ul'))
117+
118+
const result = once(expander, 'text-expander-value')
119+
expander.querySelector('li').click()
120+
const event = await result
121+
assert.equal(false, event.detail.continue)
122+
123+
assert.equal(input.value, ':1 ')
124+
125+
await waitForAnimationFrame()
126+
assert.isNull(expander.querySelector('ul'))
127+
})
128+
129+
it('dispatches value event after selecting item and keeps menu open', async function () {
130+
const expander = document.querySelector('text-expander')
131+
const input = expander.querySelector('textarea')
132+
const menu = document.createElement('ul')
133+
const item = document.createElement('li')
134+
item.setAttribute('role', 'option')
135+
menu.appendChild(item)
136+
137+
expander.addEventListener('text-expander-change', event => {
138+
const {provide} = event.detail
139+
// eslint-disable-next-line no-console
140+
console.log('ASDFSDF', event.detail)
141+
provide(Promise.resolve({matched: true, fragment: menu}))
142+
})
143+
144+
expander.addEventListener('text-expander-value', event => {
145+
event.detail.value = ':1'
146+
event.detail.continue = true
147+
})
148+
149+
input.focus()
150+
triggerInput(input, ':')
151+
await waitForAnimationFrame()
152+
assert.exists(expander.querySelector('ul'))
153+
154+
const result = once(expander, 'text-expander-value')
155+
expander.querySelector('li').click()
156+
const event = await result
157+
assert.equal(true, event.detail.continue)
158+
159+
triggerInput(input, '#1', true)
160+
161+
assert.equal(input.value, ':1#1')
162+
163+
await waitForAnimationFrame()
164+
assert.exists(expander.querySelector('ul'))
165+
})
95166
})
96167

97168
describe('multi-word scenarios', function () {

0 commit comments

Comments
 (0)