bard-tag_field 0.6.0 → 0.7.0
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/input-tag.js +44 -7
- data/input-tag/src/input-tag.js +44 -7
- data/input-tag/test/autocomplete.test.js +184 -0
- data/lib/bard/tag_field/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c3d22221c1cc7dc87d084173f83e04a7a5307348c180d5ec4b7ecad432c6ba6e
|
|
4
|
+
data.tar.gz: 1dd1de41961bf59afa2b7a788871e39c785660a7cdc6ebf1b1eab8e54c9965ef
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 00b31b2872c1a9bd7df2c4ad1439625d44df574efa3ecbb4450a181eda11594815a469e51f505c6e5809c3992670eecb37d5d8309280f54d8c9656b5c7c236aa
|
|
7
|
+
data.tar.gz: 21bc20e35322cc29d63fe74ddecaacbb1d15a4eb66497c5a4d73722d52de6adf71984e199581c3f9bcc8335d8cd96d9d8a89634648bf1bbc75927d0f066f138a
|
|
@@ -1337,6 +1337,7 @@ class InputTag extends HTMLElement {
|
|
|
1337
1337
|
reset() {
|
|
1338
1338
|
this._taggle.removeAll();
|
|
1339
1339
|
this._taggleInputTarget.value = '';
|
|
1340
|
+
this._updateButtonContent();
|
|
1340
1341
|
}
|
|
1341
1342
|
|
|
1342
1343
|
get options() {
|
|
@@ -1437,11 +1438,15 @@ class InputTag extends HTMLElement {
|
|
|
1437
1438
|
this.checkRequired();
|
|
1438
1439
|
|
|
1439
1440
|
this.buttonTarget = document.createElement("button");
|
|
1441
|
+
this.buttonTarget.type = "button";
|
|
1440
1442
|
this.buttonTarget.className = "add";
|
|
1441
1443
|
this.buttonTarget.textContent = "+";
|
|
1444
|
+
this.buttonTarget.addEventListener("mousedown", e => e.preventDefault());
|
|
1442
1445
|
this.buttonTarget.addEventListener("click", e => this._add(e));
|
|
1443
1446
|
this._taggleInputTarget.insertAdjacentElement("afterend", this.buttonTarget);
|
|
1444
1447
|
|
|
1448
|
+
this._taggleInputTarget.addEventListener("input", () => this._updateButtonContent());
|
|
1449
|
+
|
|
1445
1450
|
this.autocompleteContainerTarget = document.createElement("ul");
|
|
1446
1451
|
this._wrapperTarget.appendChild(this.autocompleteContainerTarget);
|
|
1447
1452
|
|
|
@@ -1452,22 +1457,20 @@ class InputTag extends HTMLElement {
|
|
|
1452
1457
|
|
|
1453
1458
|
// Update visibility based on current state
|
|
1454
1459
|
this.updateInputVisibility();
|
|
1460
|
+
this._updateButtonContent();
|
|
1455
1461
|
}
|
|
1456
1462
|
|
|
1457
1463
|
setupAutocomplete() {
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
autocomplete({
|
|
1464
|
+
this._autocompleteResult = autocomplete({
|
|
1461
1465
|
input: this._taggleInputTarget,
|
|
1462
1466
|
container: this.autocompleteContainerTarget,
|
|
1463
1467
|
className: "ui-menu ui-autocomplete",
|
|
1464
1468
|
fetch: (text, update) => {
|
|
1465
1469
|
const currentTags = this._taggle.getTagValues();
|
|
1466
|
-
const suggestions =
|
|
1470
|
+
const suggestions = this._getOptionsWithLabels().filter(option =>
|
|
1467
1471
|
option.label.toLowerCase().includes(text.toLowerCase()) &&
|
|
1468
1472
|
!currentTags.includes(option.value)
|
|
1469
1473
|
);
|
|
1470
|
-
// Store the suggestions for testing (can't assign to getter, tests read from DOM)
|
|
1471
1474
|
update(suggestions);
|
|
1472
1475
|
},
|
|
1473
1476
|
render: item => {
|
|
@@ -1481,6 +1484,7 @@ class InputTag extends HTMLElement {
|
|
|
1481
1484
|
// Prevent adding multiple tags in single mode
|
|
1482
1485
|
if (!this.multiple && this._taggle.getTagValues().length > 0) {
|
|
1483
1486
|
this._taggleInputTarget.value = '';
|
|
1487
|
+
this._updateButtonContent();
|
|
1484
1488
|
return
|
|
1485
1489
|
}
|
|
1486
1490
|
|
|
@@ -1492,8 +1496,9 @@ class InputTag extends HTMLElement {
|
|
|
1492
1496
|
|
|
1493
1497
|
// Clear input
|
|
1494
1498
|
this._taggleInputTarget.value = '';
|
|
1499
|
+
this._updateButtonContent();
|
|
1495
1500
|
},
|
|
1496
|
-
minLength:
|
|
1501
|
+
minLength: 0,
|
|
1497
1502
|
customize: (input, inputRect, container, maxHeight) => {
|
|
1498
1503
|
// Position autocomplete below the input-tag container, accounting for dynamic height
|
|
1499
1504
|
this._updateAutocompletePosition(container);
|
|
@@ -1568,8 +1573,35 @@ class InputTag extends HTMLElement {
|
|
|
1568
1573
|
|
|
1569
1574
|
_add(event) {
|
|
1570
1575
|
event.preventDefault();
|
|
1571
|
-
this.
|
|
1576
|
+
const value = this._taggleInputTarget.value;
|
|
1577
|
+
if (value === '') {
|
|
1578
|
+
if (this._isAutocompleteOpen()) {
|
|
1579
|
+
this._closeAutocomplete();
|
|
1580
|
+
} else {
|
|
1581
|
+
this._taggleInputTarget.focus();
|
|
1582
|
+
this._autocompleteResult.fetch();
|
|
1583
|
+
}
|
|
1584
|
+
return
|
|
1585
|
+
}
|
|
1586
|
+
this._taggle.add(value);
|
|
1572
1587
|
this._taggleInputTarget.value = '';
|
|
1588
|
+
this._updateButtonContent();
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
_isAutocompleteOpen() {
|
|
1592
|
+
return this._taggleInputTarget.getAttribute("aria-expanded") === "true"
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
_closeAutocomplete() {
|
|
1596
|
+
this._taggleInputTarget.setAttribute("aria-expanded", "false");
|
|
1597
|
+
this.autocompleteContainerTarget.remove();
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
_updateButtonContent() {
|
|
1601
|
+
const isEmpty = !this._taggleInputTarget.value;
|
|
1602
|
+
const currentTags = this._taggle.getTagValues();
|
|
1603
|
+
const hasAvailableOption = this.options.some(value => !currentTags.includes(value));
|
|
1604
|
+
this.buttonTarget.textContent = isEmpty && hasAvailableOption ? "▾" : "+";
|
|
1573
1605
|
}
|
|
1574
1606
|
|
|
1575
1607
|
onTagAdd(event, tag) {
|
|
@@ -1584,6 +1616,8 @@ class InputTag extends HTMLElement {
|
|
|
1584
1616
|
this.syncValue();
|
|
1585
1617
|
this.checkRequired();
|
|
1586
1618
|
this.updateInputVisibility();
|
|
1619
|
+
// Defer button update: taggle clears input.value after calling this callback
|
|
1620
|
+
setTimeout(() => this._updateButtonContent(), 0);
|
|
1587
1621
|
|
|
1588
1622
|
// Update autocomplete position if it's currently open
|
|
1589
1623
|
if (this._autocompleteContainer) {
|
|
@@ -1603,6 +1637,7 @@ class InputTag extends HTMLElement {
|
|
|
1603
1637
|
this.syncValue();
|
|
1604
1638
|
this.checkRequired();
|
|
1605
1639
|
this.updateInputVisibility();
|
|
1640
|
+
this._updateButtonContent();
|
|
1606
1641
|
|
|
1607
1642
|
// Update autocomplete position if it's currently open
|
|
1608
1643
|
if (this._autocompleteContainer) {
|
|
@@ -1824,9 +1859,11 @@ class InputTag extends HTMLElement {
|
|
|
1824
1859
|
this._taggleInputTarget.autocomplete = "off";
|
|
1825
1860
|
this._taggleInputTarget.setAttribute("data-turbo-permanent", true);
|
|
1826
1861
|
this._taggleInputTarget.addEventListener("keyup", e => this.keyup(e));
|
|
1862
|
+
this._taggleInputTarget.addEventListener("input", () => this._updateButtonContent());
|
|
1827
1863
|
|
|
1828
1864
|
// Re-setup autocomplete
|
|
1829
1865
|
this.setupAutocomplete();
|
|
1866
|
+
this._updateButtonContent();
|
|
1830
1867
|
|
|
1831
1868
|
// Re-process existing tag options
|
|
1832
1869
|
this.processTagOptions();
|
data/input-tag/src/input-tag.js
CHANGED
|
@@ -341,6 +341,7 @@ class InputTag extends HTMLElement {
|
|
|
341
341
|
reset() {
|
|
342
342
|
this._taggle.removeAll()
|
|
343
343
|
this._taggleInputTarget.value = ''
|
|
344
|
+
this._updateButtonContent()
|
|
344
345
|
}
|
|
345
346
|
|
|
346
347
|
get options() {
|
|
@@ -441,11 +442,15 @@ class InputTag extends HTMLElement {
|
|
|
441
442
|
this.checkRequired()
|
|
442
443
|
|
|
443
444
|
this.buttonTarget = document.createElement("button")
|
|
445
|
+
this.buttonTarget.type = "button"
|
|
444
446
|
this.buttonTarget.className = "add"
|
|
445
447
|
this.buttonTarget.textContent = "+"
|
|
448
|
+
this.buttonTarget.addEventListener("mousedown", e => e.preventDefault())
|
|
446
449
|
this.buttonTarget.addEventListener("click", e => this._add(e))
|
|
447
450
|
this._taggleInputTarget.insertAdjacentElement("afterend", this.buttonTarget)
|
|
448
451
|
|
|
452
|
+
this._taggleInputTarget.addEventListener("input", () => this._updateButtonContent())
|
|
453
|
+
|
|
449
454
|
this.autocompleteContainerTarget = document.createElement("ul");
|
|
450
455
|
this._wrapperTarget.appendChild(this.autocompleteContainerTarget)
|
|
451
456
|
|
|
@@ -456,22 +461,20 @@ class InputTag extends HTMLElement {
|
|
|
456
461
|
|
|
457
462
|
// Update visibility based on current state
|
|
458
463
|
this.updateInputVisibility()
|
|
464
|
+
this._updateButtonContent()
|
|
459
465
|
}
|
|
460
466
|
|
|
461
467
|
setupAutocomplete() {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
autocomplete({
|
|
468
|
+
this._autocompleteResult = autocomplete({
|
|
465
469
|
input: this._taggleInputTarget,
|
|
466
470
|
container: this.autocompleteContainerTarget,
|
|
467
471
|
className: "ui-menu ui-autocomplete",
|
|
468
472
|
fetch: (text, update) => {
|
|
469
473
|
const currentTags = this._taggle.getTagValues()
|
|
470
|
-
const suggestions =
|
|
474
|
+
const suggestions = this._getOptionsWithLabels().filter(option =>
|
|
471
475
|
option.label.toLowerCase().includes(text.toLowerCase()) &&
|
|
472
476
|
!currentTags.includes(option.value)
|
|
473
477
|
)
|
|
474
|
-
// Store the suggestions for testing (can't assign to getter, tests read from DOM)
|
|
475
478
|
update(suggestions)
|
|
476
479
|
},
|
|
477
480
|
render: item => {
|
|
@@ -485,6 +488,7 @@ class InputTag extends HTMLElement {
|
|
|
485
488
|
// Prevent adding multiple tags in single mode
|
|
486
489
|
if (!this.multiple && this._taggle.getTagValues().length > 0) {
|
|
487
490
|
this._taggleInputTarget.value = ''
|
|
491
|
+
this._updateButtonContent()
|
|
488
492
|
return
|
|
489
493
|
}
|
|
490
494
|
|
|
@@ -496,8 +500,9 @@ class InputTag extends HTMLElement {
|
|
|
496
500
|
|
|
497
501
|
// Clear input
|
|
498
502
|
this._taggleInputTarget.value = ''
|
|
503
|
+
this._updateButtonContent()
|
|
499
504
|
},
|
|
500
|
-
minLength:
|
|
505
|
+
minLength: 0,
|
|
501
506
|
customize: (input, inputRect, container, maxHeight) => {
|
|
502
507
|
// Position autocomplete below the input-tag container, accounting for dynamic height
|
|
503
508
|
this._updateAutocompletePosition(container);
|
|
@@ -572,8 +577,35 @@ class InputTag extends HTMLElement {
|
|
|
572
577
|
|
|
573
578
|
_add(event) {
|
|
574
579
|
event.preventDefault()
|
|
575
|
-
this.
|
|
580
|
+
const value = this._taggleInputTarget.value
|
|
581
|
+
if (value === '') {
|
|
582
|
+
if (this._isAutocompleteOpen()) {
|
|
583
|
+
this._closeAutocomplete()
|
|
584
|
+
} else {
|
|
585
|
+
this._taggleInputTarget.focus()
|
|
586
|
+
this._autocompleteResult.fetch()
|
|
587
|
+
}
|
|
588
|
+
return
|
|
589
|
+
}
|
|
590
|
+
this._taggle.add(value)
|
|
576
591
|
this._taggleInputTarget.value = ''
|
|
592
|
+
this._updateButtonContent()
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
_isAutocompleteOpen() {
|
|
596
|
+
return this._taggleInputTarget.getAttribute("aria-expanded") === "true"
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
_closeAutocomplete() {
|
|
600
|
+
this._taggleInputTarget.setAttribute("aria-expanded", "false")
|
|
601
|
+
this.autocompleteContainerTarget.remove()
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
_updateButtonContent() {
|
|
605
|
+
const isEmpty = !this._taggleInputTarget.value
|
|
606
|
+
const currentTags = this._taggle.getTagValues()
|
|
607
|
+
const hasAvailableOption = this.options.some(value => !currentTags.includes(value))
|
|
608
|
+
this.buttonTarget.textContent = isEmpty && hasAvailableOption ? "▾" : "+"
|
|
577
609
|
}
|
|
578
610
|
|
|
579
611
|
onTagAdd(event, tag) {
|
|
@@ -588,6 +620,8 @@ class InputTag extends HTMLElement {
|
|
|
588
620
|
this.syncValue()
|
|
589
621
|
this.checkRequired()
|
|
590
622
|
this.updateInputVisibility()
|
|
623
|
+
// Defer button update: taggle clears input.value after calling this callback
|
|
624
|
+
setTimeout(() => this._updateButtonContent(), 0)
|
|
591
625
|
|
|
592
626
|
// Update autocomplete position if it's currently open
|
|
593
627
|
if (this._autocompleteContainer) {
|
|
@@ -607,6 +641,7 @@ class InputTag extends HTMLElement {
|
|
|
607
641
|
this.syncValue()
|
|
608
642
|
this.checkRequired()
|
|
609
643
|
this.updateInputVisibility()
|
|
644
|
+
this._updateButtonContent()
|
|
610
645
|
|
|
611
646
|
// Update autocomplete position if it's currently open
|
|
612
647
|
if (this._autocompleteContainer) {
|
|
@@ -828,9 +863,11 @@ class InputTag extends HTMLElement {
|
|
|
828
863
|
this._taggleInputTarget.autocomplete = "off";
|
|
829
864
|
this._taggleInputTarget.setAttribute("data-turbo-permanent", true);
|
|
830
865
|
this._taggleInputTarget.addEventListener("keyup", e => this.keyup(e));
|
|
866
|
+
this._taggleInputTarget.addEventListener("input", () => this._updateButtonContent());
|
|
831
867
|
|
|
832
868
|
// Re-setup autocomplete
|
|
833
869
|
this.setupAutocomplete();
|
|
870
|
+
this._updateButtonContent();
|
|
834
871
|
|
|
835
872
|
// Re-process existing tag options
|
|
836
873
|
this.processTagOptions();
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
waitForBasicInitialization,
|
|
8
8
|
waitForUpdate,
|
|
9
9
|
simulateInput,
|
|
10
|
+
simulateKeyup,
|
|
11
|
+
simulateClick,
|
|
10
12
|
getTagElements,
|
|
11
13
|
getTagValues
|
|
12
14
|
} from './lib/test-utils.js'
|
|
@@ -179,6 +181,27 @@ describe('Autocomplete', () => {
|
|
|
179
181
|
expect(inputTag._autocompleteSuggestions).to.not.include('React')
|
|
180
182
|
expect(inputTag._autocompleteSuggestions).to.not.include('Vue')
|
|
181
183
|
})
|
|
184
|
+
|
|
185
|
+
it('should include options added to the datalist after initialization', async () => {
|
|
186
|
+
document.body.innerHTML = `
|
|
187
|
+
<input-tag name="frameworks" list="late-datalist" multiple></input-tag>
|
|
188
|
+
<datalist id="late-datalist">
|
|
189
|
+
<option value="react">React</option>
|
|
190
|
+
</datalist>
|
|
191
|
+
`
|
|
192
|
+
const inputTag = document.querySelector('input-tag')
|
|
193
|
+
const datalist = document.querySelector('#late-datalist')
|
|
194
|
+
await waitForBasicInitialization(inputTag)
|
|
195
|
+
|
|
196
|
+
const newOption = document.createElement('option')
|
|
197
|
+
newOption.value = 'added'
|
|
198
|
+
newOption.textContent = 'Added'
|
|
199
|
+
datalist.appendChild(newOption)
|
|
200
|
+
|
|
201
|
+
await simulateInput(inputTag._taggleInputTarget, 'add')
|
|
202
|
+
|
|
203
|
+
expect(inputTag._autocompleteSuggestions).to.include('Added')
|
|
204
|
+
})
|
|
182
205
|
})
|
|
183
206
|
|
|
184
207
|
describe('Autocomplete Selection Behavior', () => {
|
|
@@ -612,4 +635,165 @@ describe('Autocomplete', () => {
|
|
|
612
635
|
expect(getTagValues(inputTag)).to.deep.equal(['option1'])
|
|
613
636
|
})
|
|
614
637
|
})
|
|
638
|
+
|
|
639
|
+
describe('Dropdown on Empty Input', () => {
|
|
640
|
+
async function setupDropdownTest() {
|
|
641
|
+
document.body.innerHTML = `
|
|
642
|
+
<input-tag name="frameworks" list="suggestions" multiple></input-tag>
|
|
643
|
+
<datalist id="suggestions">
|
|
644
|
+
<option value="react">React</option>
|
|
645
|
+
<option value="vue">Vue</option>
|
|
646
|
+
<option value="angular">Angular</option>
|
|
647
|
+
</datalist>
|
|
648
|
+
`
|
|
649
|
+
const inputTag = document.querySelector('input-tag')
|
|
650
|
+
await waitForBasicInitialization(inputTag)
|
|
651
|
+
return inputTag
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
it('should show all options on ArrowDown when input is empty', async () => {
|
|
655
|
+
const inputTag = await setupDropdownTest()
|
|
656
|
+
const input = inputTag._taggleInputTarget
|
|
657
|
+
|
|
658
|
+
simulateKeyup(input, 40, { key: 'ArrowDown' })
|
|
659
|
+
await waitForUpdate()
|
|
660
|
+
|
|
661
|
+
expect(inputTag._autocompleteSuggestions).to.include.members(['React', 'Vue', 'Angular'])
|
|
662
|
+
})
|
|
663
|
+
|
|
664
|
+
it('should exclude already-selected tags from ArrowDown dropdown', async () => {
|
|
665
|
+
const inputTag = await setupDropdownTest()
|
|
666
|
+
inputTag.add('react')
|
|
667
|
+
await waitForUpdate()
|
|
668
|
+
const input = inputTag._taggleInputTarget
|
|
669
|
+
|
|
670
|
+
simulateKeyup(input, 40, { key: 'ArrowDown' })
|
|
671
|
+
await waitForUpdate()
|
|
672
|
+
|
|
673
|
+
expect(inputTag._autocompleteSuggestions).to.include.members(['Vue', 'Angular'])
|
|
674
|
+
expect(inputTag._autocompleteSuggestions).to.not.include('React')
|
|
675
|
+
})
|
|
676
|
+
|
|
677
|
+
it('should show down chevron on the button when input is empty', async () => {
|
|
678
|
+
const inputTag = await setupDropdownTest()
|
|
679
|
+
|
|
680
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
it('should keep + button when there are no autocomplete options', async () => {
|
|
684
|
+
const inputTag = await setupInputTag('<input-tag name="tags" multiple></input-tag>')
|
|
685
|
+
|
|
686
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
687
|
+
})
|
|
688
|
+
|
|
689
|
+
it('should keep + button when datalist is empty', async () => {
|
|
690
|
+
document.body.innerHTML = `
|
|
691
|
+
<input-tag name="tags" list="empty" multiple></input-tag>
|
|
692
|
+
<datalist id="empty"></datalist>
|
|
693
|
+
`
|
|
694
|
+
const inputTag = document.querySelector('input-tag')
|
|
695
|
+
await waitForBasicInitialization(inputTag)
|
|
696
|
+
|
|
697
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
698
|
+
})
|
|
699
|
+
|
|
700
|
+
it('should swap to + when all datalist options are already selected', async () => {
|
|
701
|
+
const inputTag = await setupDropdownTest()
|
|
702
|
+
|
|
703
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
704
|
+
|
|
705
|
+
inputTag.add('react')
|
|
706
|
+
inputTag.add('vue')
|
|
707
|
+
inputTag.add('angular')
|
|
708
|
+
await waitForUpdate()
|
|
709
|
+
|
|
710
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
711
|
+
})
|
|
712
|
+
|
|
713
|
+
it('should close the dropdown when chevron is clicked while open', async () => {
|
|
714
|
+
const inputTag = await setupDropdownTest()
|
|
715
|
+
const input = inputTag._taggleInputTarget
|
|
716
|
+
|
|
717
|
+
simulateClick(inputTag.buttonTarget)
|
|
718
|
+
await waitForUpdate()
|
|
719
|
+
expect(input.getAttribute('aria-expanded')).to.equal('true')
|
|
720
|
+
|
|
721
|
+
simulateClick(inputTag.buttonTarget)
|
|
722
|
+
await waitForUpdate()
|
|
723
|
+
|
|
724
|
+
expect(input.getAttribute('aria-expanded')).to.equal('false')
|
|
725
|
+
})
|
|
726
|
+
|
|
727
|
+
it('should swap back to chevron after removing a tag frees an option', async () => {
|
|
728
|
+
const inputTag = await setupDropdownTest()
|
|
729
|
+
|
|
730
|
+
inputTag.add('react')
|
|
731
|
+
inputTag.add('vue')
|
|
732
|
+
inputTag.add('angular')
|
|
733
|
+
await waitForUpdate()
|
|
734
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
735
|
+
|
|
736
|
+
inputTag.remove('react')
|
|
737
|
+
await waitForUpdate()
|
|
738
|
+
|
|
739
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
740
|
+
})
|
|
741
|
+
|
|
742
|
+
it('should show + on the button when input has text', async () => {
|
|
743
|
+
const inputTag = await setupDropdownTest()
|
|
744
|
+
const input = inputTag._taggleInputTarget
|
|
745
|
+
|
|
746
|
+
await simulateInput(input, 'r')
|
|
747
|
+
|
|
748
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
749
|
+
})
|
|
750
|
+
|
|
751
|
+
it('should swap button content as input changes', async () => {
|
|
752
|
+
const inputTag = await setupDropdownTest()
|
|
753
|
+
const input = inputTag._taggleInputTarget
|
|
754
|
+
|
|
755
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
756
|
+
|
|
757
|
+
await simulateInput(input, 'react')
|
|
758
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
759
|
+
|
|
760
|
+
await simulateInput(input, '')
|
|
761
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
762
|
+
})
|
|
763
|
+
|
|
764
|
+
it('should open autocomplete dropdown when chevron is clicked', async () => {
|
|
765
|
+
const inputTag = await setupDropdownTest()
|
|
766
|
+
|
|
767
|
+
simulateClick(inputTag.buttonTarget)
|
|
768
|
+
await waitForUpdate()
|
|
769
|
+
|
|
770
|
+
expect(inputTag._autocompleteSuggestions).to.include.members(['React', 'Vue', 'Angular'])
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
it('should still add typed text as tag when + button is clicked', async () => {
|
|
774
|
+
const inputTag = await setupDropdownTest()
|
|
775
|
+
const input = inputTag._taggleInputTarget
|
|
776
|
+
|
|
777
|
+
await simulateInput(input, 'custom-tag')
|
|
778
|
+
simulateClick(inputTag.buttonTarget)
|
|
779
|
+
await waitForUpdate()
|
|
780
|
+
|
|
781
|
+
expect(getTagValues(inputTag)).to.include('custom-tag')
|
|
782
|
+
expect(input.value).to.equal('')
|
|
783
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
it('should show chevron again after a tag is added', async () => {
|
|
787
|
+
const inputTag = await setupDropdownTest()
|
|
788
|
+
const input = inputTag._taggleInputTarget
|
|
789
|
+
|
|
790
|
+
await simulateInput(input, 'react')
|
|
791
|
+
expect(inputTag.buttonTarget.textContent).to.equal('+')
|
|
792
|
+
|
|
793
|
+
inputTag.add('react')
|
|
794
|
+
await waitForUpdate()
|
|
795
|
+
|
|
796
|
+
expect(inputTag.buttonTarget.textContent).to.equal('▾')
|
|
797
|
+
})
|
|
798
|
+
})
|
|
615
799
|
})
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bard-tag_field
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Micah Geisel
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|