@api-client/ui 0.5.16 → 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/instructions/lit-best-practices.instructions.md +1 -0
- package/build/src/elements/code-editor/code-editor.d.ts +1 -1
- package/build/src/elements/code-editor/code-editor.d.ts.map +1 -1
- package/build/src/elements/code-editor/code-editor.js.map +1 -1
- package/build/src/elements/code-editor/internals/CodeEditor.d.ts +11 -1
- package/build/src/elements/code-editor/internals/CodeEditor.d.ts.map +1 -1
- package/build/src/elements/code-editor/internals/CodeEditor.js +50 -2
- package/build/src/elements/code-editor/internals/CodeEditor.js.map +1 -1
- package/build/src/elements/code-editor/internals/CodeEditor.styles.d.ts.map +1 -1
- package/build/src/elements/code-editor/internals/CodeEditor.styles.js +8 -2
- package/build/src/elements/code-editor/internals/CodeEditor.styles.js.map +1 -1
- package/build/src/elements/code-editor/internals/types.d.ts +4 -0
- package/build/src/elements/code-editor/internals/types.d.ts.map +1 -1
- package/build/src/elements/code-editor/internals/types.js.map +1 -1
- package/demo/elements/code-editor/CodeEditorDemo.ts +8 -0
- package/package.json +1 -1
- package/src/elements/code-editor/code-editor.ts +6 -1
- package/src/elements/code-editor/internals/CodeEditor.styles.ts +8 -2
- package/src/elements/code-editor/internals/CodeEditor.ts +46 -2
- package/src/elements/code-editor/internals/types.ts +5 -0
- package/test/elements/autocomplete/autocomplete-input.spec.ts +71 -70
- package/test/elements/code-editor/code-editor.accessibility.test.ts +325 -0
- package/test/elements/code-editor/code-editor.test.ts +576 -0
|
@@ -27,9 +27,11 @@ import {
|
|
|
27
27
|
import type { FunctionSchema } from '@pawel-up/jexl/schemas/types.js'
|
|
28
28
|
import { getTypeStringFromSchema } from '@pawel-up/jexl/schemas/utils.js'
|
|
29
29
|
import { functionLinter } from './Linter.js'
|
|
30
|
-
import type { FunctionInsertEvent, Suggestion, SuggestionInsertEvent } from './types.js'
|
|
30
|
+
import type { FunctionInsertEvent, Suggestion, SuggestionInsertEvent, FunctionDocumentationEvent } from './types.js'
|
|
31
31
|
import { SuggestionMatchDecorator } from './SuggestionMatchDecorator.js'
|
|
32
32
|
|
|
33
|
+
import '../../../md/button/ui-button.js'
|
|
34
|
+
|
|
33
35
|
/**
|
|
34
36
|
* A CodeMirror 6 based editor component that supports function autocomplete and suggestion placeholders.
|
|
35
37
|
*
|
|
@@ -42,6 +44,7 @@ import { SuggestionMatchDecorator } from './SuggestionMatchDecorator.js'
|
|
|
42
44
|
*
|
|
43
45
|
* @fires function-insert - When a function is inserted
|
|
44
46
|
* @fires suggestion-insert - When a suggestion is inserted
|
|
47
|
+
* @fires function-documentation - When documentation is requested for a function
|
|
45
48
|
* @fires input - When the editor content changes
|
|
46
49
|
* @fires change - When the editor loses focus and content has changed
|
|
47
50
|
*/
|
|
@@ -143,6 +146,12 @@ export default class CodeEditor extends LitElement {
|
|
|
143
146
|
@property({ type: String })
|
|
144
147
|
accessor language = 'javascript'
|
|
145
148
|
|
|
149
|
+
/**
|
|
150
|
+
* Whether to show documentation links/buttons in function tooltips and autocomplete
|
|
151
|
+
*/
|
|
152
|
+
@property({ type: Boolean, attribute: 'show-documentation' })
|
|
153
|
+
accessor showDocumentation = false
|
|
154
|
+
|
|
146
155
|
@query('.editor-container')
|
|
147
156
|
private accessor editorContainer!: HTMLDivElement
|
|
148
157
|
|
|
@@ -231,6 +240,9 @@ export default class CodeEditor extends LitElement {
|
|
|
231
240
|
}
|
|
232
241
|
if (update.focusChanged) {
|
|
233
242
|
this.handleFocusChange(update.view.hasFocus)
|
|
243
|
+
} else if (update.view.hasFocus !== this.isEditorFocus) {
|
|
244
|
+
// If focus state changed without focusChanged event, update manually
|
|
245
|
+
this.handleFocusChange(update.view.hasFocus)
|
|
234
246
|
}
|
|
235
247
|
}),
|
|
236
248
|
this.createPlaceholderPlugin(),
|
|
@@ -405,7 +417,7 @@ export default class CodeEditor extends LitElement {
|
|
|
405
417
|
* Creates a styled HTML element to display function documentation.
|
|
406
418
|
* This is used for both hover tooltips and autocomplete info panels.
|
|
407
419
|
*/
|
|
408
|
-
|
|
420
|
+
protected createFunctionInfoElement(fn: FunctionSchema): HTMLElement {
|
|
409
421
|
const container = document.createElement('div')
|
|
410
422
|
container.className = 'function-info' // for styling
|
|
411
423
|
|
|
@@ -466,6 +478,27 @@ export default class CodeEditor extends LitElement {
|
|
|
466
478
|
container.appendChild(returnsContainer)
|
|
467
479
|
}
|
|
468
480
|
|
|
481
|
+
// Add documentation button if showDocumentation is enabled
|
|
482
|
+
if (this.showDocumentation) {
|
|
483
|
+
const docContainer = document.createElement('div')
|
|
484
|
+
docContainer.className = 'documentation'
|
|
485
|
+
|
|
486
|
+
const docButton = document.createElement('ui-button')
|
|
487
|
+
docButton.type = 'button'
|
|
488
|
+
docButton.className = 'documentation-button'
|
|
489
|
+
docButton.textContent = 'Show documentation'
|
|
490
|
+
docButton.setAttribute('aria-label', `Show documentation for ${fn.name} function`)
|
|
491
|
+
|
|
492
|
+
docButton.addEventListener('click', (event) => {
|
|
493
|
+
event.preventDefault()
|
|
494
|
+
event.stopPropagation()
|
|
495
|
+
this.dispatchFunctionDocumentation(fn)
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
docContainer.appendChild(docButton)
|
|
499
|
+
container.appendChild(docContainer)
|
|
500
|
+
}
|
|
501
|
+
|
|
469
502
|
return container
|
|
470
503
|
}
|
|
471
504
|
|
|
@@ -554,6 +587,17 @@ export default class CodeEditor extends LitElement {
|
|
|
554
587
|
this.dispatchEvent(event)
|
|
555
588
|
}
|
|
556
589
|
|
|
590
|
+
/**
|
|
591
|
+
* Dispatch function documentation event
|
|
592
|
+
*/
|
|
593
|
+
private dispatchFunctionDocumentation(functionSchema: FunctionSchema): void {
|
|
594
|
+
const event = new CustomEvent<FunctionDocumentationEvent>('function-documentation', {
|
|
595
|
+
detail: { functionSchema },
|
|
596
|
+
bubbles: true,
|
|
597
|
+
})
|
|
598
|
+
this.dispatchEvent(event)
|
|
599
|
+
}
|
|
600
|
+
|
|
557
601
|
/**
|
|
558
602
|
* Focus the editor
|
|
559
603
|
*/
|
|
@@ -26,3 +26,8 @@ export interface SuggestionInsertEvent {
|
|
|
26
26
|
/** The position where the suggestion was inserted */
|
|
27
27
|
position: number
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
export interface FunctionDocumentationEvent {
|
|
31
|
+
/** The function schema for which documentation is requested */
|
|
32
|
+
functionSchema: FunctionSchema
|
|
33
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import { fixture, expect, html, oneEvent, nextFrame, aTimeout, assert } from '@open-wc/testing'
|
|
1
|
+
import { fixture, assert, html, oneEvent, nextFrame, aTimeout } from '@open-wc/testing'
|
|
3
2
|
import sinon from 'sinon'
|
|
4
3
|
|
|
5
4
|
import { AutocompleteInput } from '../../../src/elements/autocomplete/autocomplete-input.js'
|
|
@@ -67,10 +66,10 @@ describe('AutocompleteInput', () => {
|
|
|
67
66
|
const input = getSlottedInput(el)
|
|
68
67
|
const suggestions = getSlottedSuggestions(el)
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
assert.ok(input)
|
|
70
|
+
assert.equal(input?.id, 'test-input')
|
|
71
|
+
assert.ok(suggestions)
|
|
72
|
+
assert.equal(suggestions?.popover, 'manual')
|
|
74
73
|
})
|
|
75
74
|
|
|
76
75
|
it('generates an ID for the input if not provided and sets up anchor names', async () => {
|
|
@@ -86,20 +85,20 @@ describe('AutocompleteInput', () => {
|
|
|
86
85
|
const input = getSlottedInput(el)!
|
|
87
86
|
const suggestions = getSlottedSuggestions(el)!
|
|
88
87
|
|
|
89
|
-
|
|
88
|
+
assert.match(input.id, /^autocomplete-input-/)
|
|
90
89
|
// @ts-expect-error _inputId is a protected member
|
|
91
90
|
const internalInputId = el.inputId
|
|
92
|
-
|
|
91
|
+
assert.equal(input.style.getPropertyValue('anchor-name'), `--${internalInputId}`, 'input has anchor name')
|
|
93
92
|
const anchorValue = getComputedStyle(suggestions).getPropertyValue('position-anchor')
|
|
94
|
-
|
|
93
|
+
assert.equal(anchorValue, `--${internalInputId}`, 'suggestions element has position-anchor')
|
|
95
94
|
})
|
|
96
95
|
|
|
97
96
|
it('popover is initially closed', async () => {
|
|
98
97
|
const el = await basicFixture()
|
|
99
98
|
await el.updateComplete
|
|
100
99
|
const suggestions = getSlottedSuggestions(el)
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
assert.isFalse(suggestions?.matches(':popover-open'))
|
|
101
|
+
assert.isFalse(el.opened)
|
|
103
102
|
})
|
|
104
103
|
})
|
|
105
104
|
|
|
@@ -113,8 +112,8 @@ describe('AutocompleteInput', () => {
|
|
|
113
112
|
input.focus()
|
|
114
113
|
await nextFrame() // Allow focus event to propagate and popover to open
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
assert.isTrue(suggestions.matches(':popover-open'))
|
|
116
|
+
assert.isTrue(el.opened)
|
|
118
117
|
})
|
|
119
118
|
|
|
120
119
|
it('does not open on input focus without suggestions', async () => {
|
|
@@ -126,7 +125,7 @@ describe('AutocompleteInput', () => {
|
|
|
126
125
|
input.focus()
|
|
127
126
|
await nextFrame()
|
|
128
127
|
|
|
129
|
-
|
|
128
|
+
assert.isFalse(suggestions.matches(':popover-open'))
|
|
130
129
|
})
|
|
131
130
|
|
|
132
131
|
it('does not open on input focus if suggestions element is missing', async () => {
|
|
@@ -137,7 +136,7 @@ describe('AutocompleteInput', () => {
|
|
|
137
136
|
input.focus()
|
|
138
137
|
await nextFrame()
|
|
139
138
|
// No suggestions ref, so opened should be false
|
|
140
|
-
|
|
139
|
+
assert.isFalse(el.opened)
|
|
141
140
|
})
|
|
142
141
|
|
|
143
142
|
it('closes on input blur', async () => {
|
|
@@ -148,15 +147,15 @@ describe('AutocompleteInput', () => {
|
|
|
148
147
|
|
|
149
148
|
input.focus()
|
|
150
149
|
await nextFrame()
|
|
151
|
-
|
|
150
|
+
assert.isTrue(suggestions.matches(':popover-open'))
|
|
152
151
|
|
|
153
152
|
input.blur()
|
|
154
153
|
// Blur handler uses requestAnimationFrame
|
|
155
154
|
await aTimeout(0) // Wait for rAF
|
|
156
155
|
await nextFrame() // Wait for potential re-render
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
assert.isFalse(suggestions.matches(':popover-open'))
|
|
158
|
+
assert.isFalse(el.opened)
|
|
160
159
|
})
|
|
161
160
|
|
|
162
161
|
it('closes on Escape key', async () => {
|
|
@@ -167,12 +166,12 @@ describe('AutocompleteInput', () => {
|
|
|
167
166
|
|
|
168
167
|
input.focus()
|
|
169
168
|
await nextFrame()
|
|
170
|
-
|
|
169
|
+
assert.isTrue(suggestions.matches(':popover-open'))
|
|
171
170
|
|
|
172
171
|
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, composed: true }))
|
|
173
172
|
await nextFrame()
|
|
174
173
|
|
|
175
|
-
|
|
174
|
+
assert.isFalse(suggestions.matches(':popover-open'))
|
|
176
175
|
})
|
|
177
176
|
})
|
|
178
177
|
|
|
@@ -195,7 +194,7 @@ describe('AutocompleteInput', () => {
|
|
|
195
194
|
it('shows all items for empty query', () => {
|
|
196
195
|
input.value = ''
|
|
197
196
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }))
|
|
198
|
-
items.forEach((item) =>
|
|
197
|
+
items.forEach((item) => assert.isFalse(item.hidden))
|
|
199
198
|
})
|
|
200
199
|
|
|
201
200
|
it('filters items based on data-value', async () => {
|
|
@@ -203,9 +202,9 @@ describe('AutocompleteInput', () => {
|
|
|
203
202
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }))
|
|
204
203
|
await nextFrame()
|
|
205
204
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
205
|
+
assert.isFalse(items[0].hidden) // Apple
|
|
206
|
+
assert.isTrue(items[1].hidden) // Banana
|
|
207
|
+
assert.isTrue(items[2].hidden) // Cherry
|
|
209
208
|
})
|
|
210
209
|
|
|
211
210
|
it('filters items based on textContent if data-value is not present or does not match', async () => {
|
|
@@ -218,9 +217,9 @@ describe('AutocompleteInput', () => {
|
|
|
218
217
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }))
|
|
219
218
|
await nextFrame()
|
|
220
219
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
assert.isFalse(items[0].hidden) // Pineapple (via textContent)
|
|
221
|
+
assert.isTrue(items[1].hidden) // Banana
|
|
222
|
+
assert.isTrue(items[2].hidden) // Cherry
|
|
224
223
|
})
|
|
225
224
|
|
|
226
225
|
it('filters items based on data-index fields', async () => {
|
|
@@ -228,9 +227,9 @@ describe('AutocompleteInput', () => {
|
|
|
228
227
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }))
|
|
229
228
|
await nextFrame()
|
|
230
229
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
230
|
+
assert.isTrue(items[0].hidden) // Apple
|
|
231
|
+
assert.isTrue(items[1].hidden) // Banana
|
|
232
|
+
assert.isFalse(items[2].hidden) // Cherry
|
|
234
233
|
})
|
|
235
234
|
|
|
236
235
|
it('is case-insensitive', async () => {
|
|
@@ -238,9 +237,9 @@ describe('AutocompleteInput', () => {
|
|
|
238
237
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }))
|
|
239
238
|
await nextFrame()
|
|
240
239
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
assert.isTrue(items[0].hidden) // Apple
|
|
241
|
+
assert.isFalse(items[1].hidden) // Banana
|
|
242
|
+
assert.isTrue(items[2].hidden) // Cherry
|
|
244
243
|
})
|
|
245
244
|
|
|
246
245
|
it('closes popover if no items match', async () => {
|
|
@@ -249,8 +248,8 @@ describe('AutocompleteInput', () => {
|
|
|
249
248
|
await nextFrame()
|
|
250
249
|
await aTimeout(0) // filterSuggestions might call closeSuggestions, which might be async
|
|
251
250
|
|
|
252
|
-
items.forEach((item) =>
|
|
253
|
-
|
|
251
|
+
items.forEach((item) => assert.isTrue(item.hidden))
|
|
252
|
+
assert.isFalse(suggestionsBox.matches(':popover-open'))
|
|
254
253
|
})
|
|
255
254
|
})
|
|
256
255
|
|
|
@@ -258,6 +257,7 @@ describe('AutocompleteInput', () => {
|
|
|
258
257
|
let el: AutocompleteInput
|
|
259
258
|
let input: HTMLInputElement
|
|
260
259
|
let suggestionsBox: MdListbox
|
|
260
|
+
let notifySelectSpy: sinon.SinonSpy
|
|
261
261
|
|
|
262
262
|
beforeEach(async () => {
|
|
263
263
|
el = await basicFixture()
|
|
@@ -268,7 +268,7 @@ describe('AutocompleteInput', () => {
|
|
|
268
268
|
// We spy on its methods.
|
|
269
269
|
sinon.spy(suggestionsBox, 'highlightNext')
|
|
270
270
|
sinon.spy(suggestionsBox, 'highlightPrevious')
|
|
271
|
-
sinon.spy(suggestionsBox, 'notifySelect')
|
|
271
|
+
notifySelectSpy = sinon.spy(suggestionsBox, 'notifySelect')
|
|
272
272
|
})
|
|
273
273
|
|
|
274
274
|
afterEach(() => {
|
|
@@ -276,14 +276,14 @@ describe('AutocompleteInput', () => {
|
|
|
276
276
|
})
|
|
277
277
|
|
|
278
278
|
it('ArrowDown highlights next item and opens popover if closed', async () => {
|
|
279
|
-
|
|
279
|
+
assert.isFalse(suggestionsBox.matches(':popover-open'))
|
|
280
280
|
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true, composed: true }))
|
|
281
281
|
// handleKeydown uses rAF if popover was closed
|
|
282
282
|
await aTimeout(0) // for rAF
|
|
283
283
|
await nextFrame() // for popover to open and highlight
|
|
284
284
|
|
|
285
|
-
|
|
286
|
-
|
|
285
|
+
assert.isTrue(suggestionsBox.matches(':popover-open'))
|
|
286
|
+
assert.isTrue((suggestionsBox.highlightNext as sinon.SinonSpy).calledOnce)
|
|
287
287
|
})
|
|
288
288
|
|
|
289
289
|
it('ArrowUp highlights previous item', async () => {
|
|
@@ -291,7 +291,7 @@ describe('AutocompleteInput', () => {
|
|
|
291
291
|
await nextFrame()
|
|
292
292
|
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp', bubbles: true, composed: true }))
|
|
293
293
|
await nextFrame()
|
|
294
|
-
|
|
294
|
+
assert.isTrue((suggestionsBox.highlightPrevious as sinon.SinonSpy).calledOnce)
|
|
295
295
|
})
|
|
296
296
|
|
|
297
297
|
it('Enter selects highlighted item and dispatches event', async () => {
|
|
@@ -307,13 +307,14 @@ describe('AutocompleteInput', () => {
|
|
|
307
307
|
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true }))
|
|
308
308
|
|
|
309
309
|
const event = await eventPromise
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
310
|
+
|
|
311
|
+
assert.isTrue((suggestionsBox.notifySelect as sinon.SinonSpy).calledWith(items[0]))
|
|
312
|
+
assert.equal(event.detail.item, items[0])
|
|
313
|
+
assert.isFalse(suggestionsBox.matches(':popover-open')) // Popover should close
|
|
313
314
|
})
|
|
314
315
|
|
|
315
316
|
it('Enter does nothing if popover closed or no item highlighted', async () => {
|
|
316
|
-
|
|
317
|
+
assert.isFalse(suggestionsBox.matches(':popover-open'))
|
|
317
318
|
suggestionsBox.highlightListItem = null // Ensure no item is highlighted
|
|
318
319
|
|
|
319
320
|
const spy = sinon.spy()
|
|
@@ -322,8 +323,8 @@ describe('AutocompleteInput', () => {
|
|
|
322
323
|
input.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true, composed: true }))
|
|
323
324
|
await nextFrame()
|
|
324
325
|
|
|
325
|
-
|
|
326
|
-
|
|
326
|
+
assert.isFalse(spy.called)
|
|
327
|
+
assert.isFalse(notifySelectSpy.called)
|
|
327
328
|
})
|
|
328
329
|
})
|
|
329
330
|
|
|
@@ -351,8 +352,8 @@ describe('AutocompleteInput', () => {
|
|
|
351
352
|
)
|
|
352
353
|
|
|
353
354
|
const event = await eventPromise
|
|
354
|
-
|
|
355
|
-
|
|
355
|
+
assert.equal(event.detail.item, items[1])
|
|
356
|
+
assert.isFalse(suggestionsBox.matches(':popover-open')) // Popover should close
|
|
356
357
|
})
|
|
357
358
|
})
|
|
358
359
|
|
|
@@ -369,8 +370,8 @@ describe('AutocompleteInput', () => {
|
|
|
369
370
|
await el.updateComplete // Ensure component processes the new input
|
|
370
371
|
|
|
371
372
|
const slottedInput = getSlottedInput(el)
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
assert.equal(slottedInput, inputEl)
|
|
374
|
+
assert.match(inputEl.id, /^autocomplete-input-/)
|
|
374
375
|
})
|
|
375
376
|
|
|
376
377
|
it('handles dynamically added suggestions', async () => {
|
|
@@ -387,10 +388,10 @@ describe('AutocompleteInput', () => {
|
|
|
387
388
|
await el.updateComplete
|
|
388
389
|
|
|
389
390
|
const slottedSuggestions = getSlottedSuggestions(el)
|
|
390
|
-
|
|
391
|
-
|
|
391
|
+
assert.equal(slottedSuggestions, suggestionsEl)
|
|
392
|
+
assert.equal(suggestionsEl.popover, 'manual')
|
|
392
393
|
const anchorValue = getComputedStyle(suggestionsEl).getPropertyValue('position-anchor')
|
|
393
|
-
|
|
394
|
+
assert.equal(anchorValue, `--${input.id}`)
|
|
394
395
|
})
|
|
395
396
|
|
|
396
397
|
it('re-filters when suggestion items change (via itemschange event)', async () => {
|
|
@@ -404,8 +405,8 @@ describe('AutocompleteInput', () => {
|
|
|
404
405
|
input.value = 'ban' // Should show "Banana"
|
|
405
406
|
input.dispatchEvent(new Event('input', { bubbles: true, composed: true }))
|
|
406
407
|
await nextFrame()
|
|
407
|
-
|
|
408
|
-
|
|
408
|
+
assert.isTrue(items[0].hidden) // Apple
|
|
409
|
+
assert.isFalse(items[1].hidden) // Banana
|
|
409
410
|
|
|
410
411
|
// Add a new item that matches "ban"
|
|
411
412
|
const newItem = document.createElement('ui-list-item') as MdListItem
|
|
@@ -418,9 +419,9 @@ describe('AutocompleteInput', () => {
|
|
|
418
419
|
await nextFrame() // Allow handler to run
|
|
419
420
|
|
|
420
421
|
items = getSuggestionItems(suggestionsBox) // Re-fetch items
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
422
|
+
assert.isFalse(items.find((i) => i.dataset.value === 'bandana')?.hidden)
|
|
423
|
+
assert.isFalse(items.find((i) => i.dataset.value === 'banana')?.hidden)
|
|
424
|
+
assert.isTrue(items.find((i) => i.dataset.value === 'apple')?.hidden)
|
|
424
425
|
})
|
|
425
426
|
})
|
|
426
427
|
|
|
@@ -431,18 +432,18 @@ describe('AutocompleteInput', () => {
|
|
|
431
432
|
const input = getSlottedInput(el)!
|
|
432
433
|
const suggestions = getSlottedSuggestions(el)!
|
|
433
434
|
|
|
434
|
-
|
|
435
|
+
assert.isFalse(el.opened)
|
|
435
436
|
|
|
436
437
|
input.focus()
|
|
437
438
|
await nextFrame()
|
|
438
|
-
|
|
439
|
-
|
|
439
|
+
assert.isTrue(el.opened)
|
|
440
|
+
assert.isTrue(suggestions.matches(':popover-open'))
|
|
440
441
|
|
|
441
442
|
// @ts-expect-error protected method
|
|
442
443
|
el.closeSuggestions()
|
|
443
444
|
await nextFrame()
|
|
444
|
-
|
|
445
|
-
|
|
445
|
+
assert.isFalse(el.opened)
|
|
446
|
+
assert.isFalse(suggestions.matches(':popover-open'))
|
|
446
447
|
})
|
|
447
448
|
})
|
|
448
449
|
|
|
@@ -503,7 +504,7 @@ describe('AutocompleteInput', () => {
|
|
|
503
504
|
await el.updateComplete // For positionArea state change and re-render
|
|
504
505
|
await nextFrame() // For DOM to reflect changes
|
|
505
506
|
|
|
506
|
-
|
|
507
|
+
assert.equal(el.positionArea, 'bottom')
|
|
507
508
|
})
|
|
508
509
|
|
|
509
510
|
it('positions at top when insufficient space below but sufficient space above', async () => {
|
|
@@ -516,7 +517,7 @@ describe('AutocompleteInput', () => {
|
|
|
516
517
|
await el.updateComplete
|
|
517
518
|
await nextFrame()
|
|
518
519
|
|
|
519
|
-
|
|
520
|
+
assert.equal(el.positionArea, 'top')
|
|
520
521
|
})
|
|
521
522
|
|
|
522
523
|
it('positions at top when insufficient space below and more space above', async () => {
|
|
@@ -535,7 +536,7 @@ describe('AutocompleteInput', () => {
|
|
|
535
536
|
await el.updateComplete
|
|
536
537
|
await nextFrame()
|
|
537
538
|
|
|
538
|
-
|
|
539
|
+
assert.equal(el.positionArea, 'top')
|
|
539
540
|
})
|
|
540
541
|
|
|
541
542
|
it('positions at bottom when insufficient space below and also insufficient (or less) space above', async () => {
|
|
@@ -552,7 +553,7 @@ describe('AutocompleteInput', () => {
|
|
|
552
553
|
await el.updateComplete
|
|
553
554
|
await nextFrame()
|
|
554
555
|
|
|
555
|
-
|
|
556
|
+
assert.equal(el.positionArea, 'bottom')
|
|
556
557
|
})
|
|
557
558
|
|
|
558
559
|
it('uses fallback threshold of 150px if popover scrollHeight is 0', async () => {
|
|
@@ -574,7 +575,7 @@ describe('AutocompleteInput', () => {
|
|
|
574
575
|
await el.updateComplete
|
|
575
576
|
await nextFrame()
|
|
576
577
|
|
|
577
|
-
|
|
578
|
+
assert.equal(el.positionArea, 'top')
|
|
578
579
|
scrollHeightStub.restore()
|
|
579
580
|
})
|
|
580
581
|
|
|
@@ -603,8 +604,8 @@ describe('AutocompleteInput', () => {
|
|
|
603
604
|
await el.updateComplete
|
|
604
605
|
await nextFrame()
|
|
605
606
|
|
|
606
|
-
|
|
607
|
-
|
|
607
|
+
assert.equal(el.positionArea, 'top')
|
|
608
|
+
assert.isTrue(getBoundingClientRectStub.called)
|
|
608
609
|
})
|
|
609
610
|
})
|
|
610
611
|
|