1
0
Эх сурвалжийг харах

Finishing touches on combobox

Caleb Porzio 2 жил өмнө
parent
commit
6e1cb07342

+ 4 - 2
packages/ui/src/combobox.js

@@ -171,12 +171,14 @@ function handleRoot(el, Alpine) {
                 __activateSelectedOrFirst(activateSelected = true) {
                     if (! this.__isOpen) return
 
+                    if (this.__context.hasActive()) return
+
                     let firstSelectedValue
 
                     if (this.__isMultiple) {
-                        let activeElement = this.__context.getItemsByValues(this.__value)
+                        let selectedItem = this.__context.getItemsByValues(this.__value)
 
-                        firstSelectedValue = activeElement.length ? activeElement[0].value : null
+                        firstSelectedValue = selectedItem.length ? selectedItem[0].value : null
                     } else {
                         firstSelectedValue = this.__value
                     }

+ 0 - 131
packages/ui/src/list-context.js

@@ -5,13 +5,8 @@ export function generateContext(multiple, orientation, activateSelectedOrFirst)
          * Main state...
          */
         items: [],
-
-        disabledKeys: [],
         activeKey: null,
-        selectedKeys: [],
         orderedKeys: [],
-        elsByKey: {},
-        values: {},
 
         /**
          *  Initialization...
@@ -148,57 +143,6 @@ export function generateContext(multiple, orientation, activateSelectedOrFirst)
             }, 25)
         },
 
-        /**
-         * Handle values...
-         */
-        // selectedValueOrValues() {
-        //     if (multiple) {
-        //         return this.selectedValues()
-        //     } else {
-        //         return this.selectedValue()
-        //     }
-        // },
-
-        // selectedValues() {
-        //     return this.selectedKeys.map(i => this.values[i])
-        // },
-
-        // selectedValue() {
-        //     return this.selectedKeys[0] ? this.values[this.selectedKeys[0]] : null
-        // },
-
-        // selectValue(value, by) {
-        //     if (!value) value = (multiple ? [] : null)
-        //     if (! by) by = (a, b) => a === b
-
-        //     if (typeof by === 'string') {
-        //         let property = by
-        //         by = (a, b) => a[property] === b[property]
-        //     }
-
-        //     if (multiple) {
-        //         let keys = []
-
-        //         value.forEach(i => {
-        //             for (let key in this.values) {
-        //                 if (by(this.values[key], i)) {
-        //                     if (! keys.includes(key)) {
-        //                         keys.push(key)
-        //                     }
-        //                 }
-        //             }
-        //         })
-
-        //         this.selectExclusive(keys)
-        //     } else {
-        //         for (let key in this.values) {
-        //             if (value && by(this.values[key], value)) {
-        //                 this.selectKey(key)
-        //             }
-        //         }
-        //     }
-        // },
-
         /**
          * Handle disabled keys...
          */
@@ -214,66 +158,6 @@ export function generateContext(multiple, orientation, activateSelectedOrFirst)
             return this.orderedKeys.filter(i => ! this.isDisabled(i))
         },
 
-        /**
-         * Handle selected keys...
-         */
-        // selectKey(key) {
-        //     if (this.isDisabled(key)) return
-
-        //     if (multiple) {
-        //         this.toggleSelected(key)
-        //     } else {
-        //         this.selectOnly(key)
-        //     }
-        // },
-
-        // toggleSelected(key) {
-        //     console.log(key)
-        //     if (this.selectedKeys.includes(key)) {
-        //         this.selectedKeys.splice(this.selectedKeys.indexOf(key), 1)
-        //     } else {
-        //         this.selectedKeys.push(key)
-        //     }
-        // },
-
-        // selectOnly(key) {
-        //     this.selectedKeys = []
-        //     this.selectedKeys.push(key)
-        // },
-
-        // selectExclusive(keys) {
-        //     // We can't just do this.selectedKeys = keys,
-        //     // because we need to preserve reactivity...
-
-        //     let toAdd = [...keys]
-
-        //     for (let i = 0; i < this.selectedKeys.length; i++) {
-        //         if (keys.includes(this.selectedKeys[i])) {
-        //             delete toAdd[toAdd.indexOf(this.selectedKeys[i])]
-        //             continue;
-        //         }
-
-        //         if (! keys.includes(this.selectedKeys[i])) {
-        //             this.selectedKeys.splice(i, 1)
-        //         }
-        //     }
-
-        //     toAdd.forEach(i => {
-        //         this.selectedKeys.push(i)
-        //     })
-        // },
-
-        // selectActive(key) {
-        //     if (! this.activeKey) return
-
-        //     this.selectKey(this.activeKey)
-        // },
-
-        // isSelected(key) { return this.selectedKeys.includes(key) },
-
-
-        // firstSelectedKey() { return this.selectedKeys[0] },
-
         /**
          * Handle activated keys...
          */
@@ -281,21 +165,6 @@ export function generateContext(multiple, orientation, activateSelectedOrFirst)
 
         isActiveKey(key) { return this.activeKey === key },
 
-
-        // activateSelectedOrFirst() {
-        //     let firstSelected = this.firstSelectedKey()
-
-        //     if (firstSelected) {
-        //         return this.activateKey(firstSelected)
-        //     }
-
-        //     let firstKey = this.firstKey()
-
-        //     if (firstKey) {
-        //         this.activateKey(firstKey)
-        //     }
-        // },
-
         activateKey(key) {
             if (this.isDisabled(key)) return
 

+ 91 - 0
tests/cypress/integration/plugins/ui/combobox.spec.js

@@ -271,6 +271,97 @@ test('"name" prop',
     },
 );
 
+test('Preserves currenty active selection while options change from searching even if there\'s a selected option in the filtered results',
+    [html`
+        <div
+            x-data="{
+                query: '',
+                selected: null,
+                people: [
+                    { id: 1, name: 'Wade Cooper' },
+                    { id: 2, name: 'Arlene Mccoy' },
+                    { id: 3, name: 'Devon Webb' },
+                    { id: 4, name: 'Tom Cook' },
+                    { id: 5, name: 'Tanya Fox', disabled: true },
+                    { id: 6, name: 'Hellen Schmidt' },
+                    { id: 7, name: 'Caroline Schultz' },
+                    { id: 8, name: 'Mason Heaney' },
+                    { id: 9, name: 'Claudie Smitham' },
+                    { id: 10, name: 'Emil Schaefer' },
+                ],
+                get filteredPeople() {
+                    return this.query === ''
+                        ? this.people
+                        : this.people.filter((person) => {
+                            return person.name.toLowerCase().includes(this.query.toLowerCase())
+                        })
+                },
+            }"
+        >
+            <div x-combobox x-model="selected">
+                <label x-combobox:label>Select person</label>
+
+                <div>
+                    <div>
+                        <input
+                            x-combobox:input
+                            :display-value="person => person.name"
+                            @change="query = $event.target.value"
+                            placeholder="Search..."
+                        />
+
+                        <button x-combobox:button>Toggle</button>
+                    </div>
+
+                    <div x-combobox:options>
+                        <ul>
+                            <template
+                                x-for="person in filteredPeople"
+                                :key="person.id"
+                                hidden
+                            >
+                                <li
+                                    x-combobox:option
+                                    :option="person.id"
+                                    :value="person"
+                                    :disabled="person.disabled"
+                                >
+                                    <span x-text="person.name"></span>
+                                    <span x-show="$comboboxOption.isActive">*</span>
+                                    <span x-show="$comboboxOption.isSelected">x</span>
+                                </li>
+                            </template>
+                        </ul>
+
+                        <p x-show="filteredPeople.length == 0">No people match your query.</p>
+                    </div>
+                </div>
+            </div>
+
+            <article>lorem ipsum</article>
+        </div>
+    `],
+    ({ get }) => {
+        get('input').should(haveText(''))
+        get('button').click()
+        get('[option="3"]').click()
+        cy.wait(100)
+        get('input').type('{selectAll}{backspace}')
+        cy.wait(100)
+        get('input').type('{downArrow}')
+        cy.wait(100)
+        get('[option="3"]').should(contain('*'))
+        get('input').type('{upArrow}{upArrow}')
+        cy.wait(100)
+        get('[option="1"]').should(contain('*'))
+        cy.wait(100)
+        get('input').type('d')
+        get('input').trigger('change')
+        cy.wait(100)
+        get('[option="1"]').should(contain('*'))
+    },
+);
+
 test('"name" prop with object value',
     [html`
         <div