Skip to content

Commit a438b03

Browse files
authored
fix: uui-combobox should correctly handle the active item (#682)
* use expand symbol * use option value as anchor instead of index
1 parent 985bfaf commit a438b03

File tree

4 files changed

+53
-50
lines changed

4 files changed

+53
-50
lines changed

packages/uui-combobox-list/lib/uui-combobox-list.element.ts

+39-34
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,8 @@ export class UUIComboboxListElement extends LitElement {
7979
@state()
8080
private _value: FormDataEntryValue | FormData = '';
8181

82-
private __activeElement: UUIComboboxListOptionElement | undefined;
83-
private get _activeElement(): UUIComboboxListOptionElement | undefined {
84-
return this.__activeElement;
85-
}
86-
private set _activeElement(el: UUIComboboxListOptionElement | undefined) {
87-
if (this.__activeElement) {
88-
this.__activeElement.active = false;
89-
}
90-
if (el) {
91-
el.active = true;
92-
this.__activeElement = el;
93-
}
94-
}
82+
@state()
83+
private _activeElementValue: string | null = null;
9584

9685
private _selectedElement: UUIComboboxListOptionElement | undefined;
9786

@@ -129,30 +118,35 @@ export class UUIComboboxListElement extends LitElement {
129118
}
130119

131120
private _onSlotChange = () => {
132-
this._activeElement = undefined;
133121
// Get index from first active, remove active from the rest.
134-
for (let i = 0; i < this._activeOptions.length; i++) {
135-
if (i === 0) {
136-
this._activeElement = this._activeOptions[i];
137-
} else {
138-
this._activeOptions[i].active = false;
139-
}
140-
}
122+
this.#updateActiveElement();
141123

142124
this._updateSelection();
143125
this.dispatchEvent(
144126
new UUIComboboxListEvent(UUIComboboxListEvent.INNER_SLOT_CHANGE)
145127
);
146128
};
147129

130+
#updateActiveElement() {
131+
for (let i = 0; i < this._activeOptions.length; i++) {
132+
this._activeOptions[i].active = false;
133+
}
134+
135+
const activeElement = this._getActiveElement;
136+
if (activeElement) {
137+
activeElement.active = true;
138+
} else {
139+
this._goToIndex(0);
140+
}
141+
}
142+
148143
private _onSelected = (e: Event) => {
149144
if (this._selectedElement) {
150145
this._selectedElement.selected = false;
151146
this._selectedElement.active = false;
152147
this._selectedElement = undefined;
153148
}
154149
this._selectedElement = e.composedPath()[0] as UUIComboboxListOptionElement;
155-
this._activeElement = this._selectedElement;
156150

157151
this.value = this._selectedElement.value || '';
158152
this.displayValue = this._selectedElement.displayValue || '';
@@ -161,37 +155,48 @@ export class UUIComboboxListElement extends LitElement {
161155
};
162156
private _onDeselected = (e: Event) => {
163157
const el = e.composedPath()[0] as UUIComboboxListOptionElement;
164-
if (this._activeElement === el) {
165-
this._activeElement = undefined;
166-
}
167158
if (this._selectedElement === el) {
168159
this.value = '';
169160
this.displayValue = '';
170161
this.dispatchEvent(new UUIComboboxListEvent(UUIComboboxListEvent.CHANGE));
171162
}
172163
};
173164

174-
private _getActiveIndex(): number {
175-
return this._activeElement
176-
? this._options.indexOf(this._activeElement)
177-
: -1;
165+
private get _getActiveIndex(): number {
166+
if (this._activeElementValue === null) return -1;
167+
168+
return this._options.findIndex(
169+
element => element.value === this._activeElementValue
170+
);
171+
}
172+
173+
private get _getActiveElement() {
174+
if (this._activeElementValue === null) return null;
175+
176+
return this._options.find(
177+
element => element.value === this._activeElementValue
178+
);
178179
}
179180

180181
private _moveIndex = (distance: number) => {
181182
const newIndex = Math.min(
182-
Math.max(this._getActiveIndex() + distance, 0),
183+
Math.max(this._getActiveIndex + distance, 0),
183184
this._options.length - 1
184185
);
185186

186187
this._goToIndex(newIndex);
187188
};
188189

189190
private _goToIndex(index: number) {
191+
if (this._options.length === 0) return;
192+
190193
index = Math.min(Math.max(index, 0), this._options.length - 1); // Makes sure the index stays within array length
191-
this._activeElement = this._options[index];
194+
const activeElement = this._options[index];
195+
this._activeElementValue = activeElement.value;
196+
this.#updateActiveElement();
192197

193-
if (this._activeElement) {
194-
this._activeElement.scrollIntoView({
198+
if (activeElement) {
199+
activeElement.scrollIntoView({
195200
behavior: 'auto',
196201
block: 'nearest',
197202
inline: 'nearest',
@@ -222,7 +227,7 @@ export class UUIComboboxListElement extends LitElement {
222227

223228
case 'Enter': {
224229
e.preventDefault();
225-
this._activeElement?.click();
230+
this._getActiveElement?.click();
226231
break;
227232
}
228233

packages/uui-combobox/lib/uui-combobox.element.ts

+11-15
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export class UUIComboboxElement extends FormControlMixin(LitElement) {
147147
demandCustomElement(this, 'uui-combobox-list');
148148
demandCustomElement(this, 'uui-scroll-container');
149149
demandCustomElement(this, 'uui-popover-container');
150+
demandCustomElement(this, 'uui-symbol-expand');
150151
}
151152

152153
disconnectedCallback(): void {
@@ -286,17 +287,14 @@ export class UUIComboboxElement extends FormControlMixin(LitElement) {
286287
@input=${this.#onInput}
287288
@keydown=${this.#onKeyDown}>
288289
<slot name="input-prepend" slot="prepend"></slot>
289-
${this.disabled ? '' : this.#renderClearButton()} ${this.#renderCaret()}
290+
${this.disabled ? '' : this.#renderClearButton()}
291+
<div id="expand-symbol-wrapper" slot="append">
292+
<uui-symbol-expand .open=${this._isOpen}></uui-symbol-expand>
293+
</div>
290294
<slot name="input-append" slot="append"></slot>
291295
</uui-input>`;
292296
};
293297

294-
#renderCaret = () => {
295-
return html`<svg id="caret" slot="append" viewBox="0 0 512 512">
296-
<path d="M 255.125 400.35 L 88.193 188.765 H 422.055 Z"></path>
297-
</svg>`;
298-
};
299-
300298
#renderClearButton = () => {
301299
return this.value || this.search
302300
? html`<uui-button
@@ -361,6 +359,12 @@ export class UUIComboboxElement extends FormControlMixin(LitElement) {
361359
width: 100%;
362360
max-height: var(--uui-combobox-popover-max-height, 500px);
363361
}
362+
#expand-symbol-wrapper {
363+
height: 100%;
364+
padding-right: var(--uui-size-space-3);
365+
display: flex;
366+
justify-content: center;
367+
}
364368
365369
#dropdown {
366370
overflow: hidden;
@@ -377,14 +381,6 @@ export class UUIComboboxElement extends FormControlMixin(LitElement) {
377381
box-shadow: var(--uui-shadow-depth-3);
378382
}
379383
380-
#caret {
381-
margin-right: var(--uui-size-3, 9px);
382-
display: flex;
383-
width: 1.15em;
384-
flex-shrink: 0;
385-
margin-top: -1px;
386-
}
387-
388384
:host([disabled]) #caret {
389385
fill: var(--uui-color-disabled-contrast);
390386
}

packages/uui-combobox/lib/uui-combobox.story.ts

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import '@umbraco-ui/uui-icon/lib';
33
import '@umbraco-ui/uui-input/lib';
44
import '@umbraco-ui/uui-button/lib';
55
import '@umbraco-ui/uui-popover-container/lib';
6+
import '@umbraco-ui/uui-symbol-expand';
67

78
import '.';
89
import './uui-combobox-async-example';

packages/uui-combobox/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"@umbraco-ui/uui-combobox-list": "1.6.0-rc.1",
3636
"@umbraco-ui/uui-icon": "1.6.0-rc.1",
3737
"@umbraco-ui/uui-scroll-container": "1.6.0-rc.1",
38-
"@umbraco-ui/uui-popover-container": "1.6.0-rc.1"
38+
"@umbraco-ui/uui-popover-container": "1.6.0-rc.1",
39+
"@umbraco-ui/uui-symbol-expand": "1.6.0-rc.1"
3940
},
4041
"scripts": {
4142
"build": "npm run analyze && tsc --build --force && rollup -c rollup.config.js",

0 commit comments

Comments
 (0)