@breadstone/mosaik-elements-foundation 0.0.151 → 0.0.152

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.
Files changed (27) hide show
  1. package/Controls/Behaviors/AutoCompleteable.d.ts +45 -7
  2. package/Controls/Behaviors/AutoCompleteable.d.ts.map +1 -1
  3. package/Controls/Behaviors/AutoCompleteable.js +230 -21
  4. package/Controls/Behaviors/AutoCompleteable.js.map +1 -1
  5. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElement.d.ts +236 -3
  6. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElement.d.ts.map +1 -1
  7. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElement.js +647 -9
  8. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElement.js.map +1 -1
  9. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementIntl.d.ts +31 -0
  10. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementIntl.d.ts.map +1 -0
  11. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementIntl.js +50 -0
  12. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementIntl.js.map +1 -0
  13. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementTemplate.d.ts.map +1 -1
  14. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementTemplate.js +64 -10
  15. package/Controls/Components/Inputs/AutoCompleteBox/AutoCompleteBoxElementTemplate.js.map +1 -1
  16. package/Controls/Components/Inputs/AutoCompleteBox/IAutoCompleteBoxElementProps.d.ts +15 -1
  17. package/Controls/Components/Inputs/AutoCompleteBox/IAutoCompleteBoxElementProps.d.ts.map +1 -1
  18. package/Controls/Controllers/AutoCompleteController.d.ts +1 -0
  19. package/Controls/Controllers/AutoCompleteController.d.ts.map +1 -1
  20. package/Controls/Controllers/AutoCompleteController.js +22 -5
  21. package/Controls/Controllers/AutoCompleteController.js.map +1 -1
  22. package/Index.d.ts +1 -1
  23. package/Index.d.ts.map +1 -1
  24. package/Index.js.map +1 -1
  25. package/Routing/PathToRegexp.d.ts +1 -1
  26. package/custom-elements.json +707 -28
  27. package/package.json +3 -3
@@ -8,6 +8,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var AutoCompleteBoxElement_1;
12
+ import { CssLength } from '@breadstone/mosaik-themes';
13
+ import { html } from '../../../../Dom/Html';
11
14
  import { AutoCompleteable } from '../../../Behaviors/AutoCompleteable';
12
15
  import { Attribute } from '../../../Decorators/AttributeDecorator';
13
16
  import { Component } from '../../../Decorators/ComponentDecorator';
@@ -17,6 +20,17 @@ import { autoCompleteBoxElementJoyStyle } from './Themes/AutoCompleteBoxElement.
17
20
  import { autoCompleteBoxElementRetroStyle } from './Themes/AutoCompleteBoxElement.Retro';
18
21
  import { autoCompleteBoxElementCosmopolitanStyle } from './Themes/AutoCompleteBoxElement.Cosmopolitan';
19
22
  import { Themeable } from '../../../Behaviors/Themeable';
23
+ import { Placement } from '../../../Types/Placement';
24
+ import { Strategy } from '../../../Types/Strategy';
25
+ import { FloatingSync } from '../../../Types/FloatingSync';
26
+ import { PortalElement } from '../../Primitives/Portal/PortalElement';
27
+ import { FloatingElement } from '../../Primitives/Floating/FloatingElement';
28
+ import { DropDownable } from '../../../Behaviors/DropDownable';
29
+ import { Disableable } from '../../../Behaviors/Disableable';
30
+ import { Focusable } from '../../../Behaviors/Focusable';
31
+ import { Watch } from '../../../Decorators/WatchDecorator';
32
+ import { IntlController } from '../../../../Intl/IntlController';
33
+ import { AutoCompleteBoxElementIntl } from './AutoCompleteBoxElementIntl';
20
34
  // #endregion
21
35
  /**
22
36
  * Auto Complete Box - An input field with auto-completion functionality for enhanced user experience.
@@ -34,6 +48,8 @@ import { Themeable } from '../../../Behaviors/Themeable';
34
48
  * @csspart input - the input field.
35
49
  * @csspart list - the suggestions list.
36
50
  * @csspart item - individual suggestion items.
51
+ * @csspart portal - the floating portal container for the suggestions.
52
+ * @csspart popup - the floating popup container for the suggestions.
37
53
  *
38
54
  * @cssprop {String} --auto-complete-box-background-color - The background color.
39
55
  * @cssprop {String} --auto-complete-box-border-color - The border color.
@@ -50,6 +66,9 @@ import { Themeable } from '../../../Behaviors/Themeable';
50
66
  * @cssprop {String} --auto-complete-box-shadow - The shadow.
51
67
  * @cssprop {String} --auto-complete-box-width - The width.
52
68
  *
69
+ * @dependency mosaik-portal - Provides a portal host for rendering the suggestion popup.
70
+ * @dependency mosaik-floating - Positions the suggestion popup relative to the host element.
71
+ *
53
72
  * @example
54
73
  * ```html
55
74
  * <mosaik-autocompletebox
@@ -60,9 +79,23 @@ import { Themeable } from '../../../Behaviors/Themeable';
60
79
  *
61
80
  * @public
62
81
  */
63
- let AutoCompleteBoxElement = class AutoCompleteBoxElement extends Themeable(AutoCompleteable(CustomElement)) {
82
+ let AutoCompleteBoxElement = class AutoCompleteBoxElement extends Themeable(DropDownable(Focusable(Disableable(AutoCompleteable(CustomElement))))) {
83
+ static { AutoCompleteBoxElement_1 = this; }
64
84
  // #region Fields
65
- _text = '';
85
+ static _idCounter = 0;
86
+ static _floatingFlipFallbackPlacements = Object.freeze([
87
+ Placement.Top,
88
+ Placement.Bottom
89
+ ]);
90
+ _text;
91
+ _shouldSyncSearchFromText;
92
+ _highlightedIndex;
93
+ _lastFilterText;
94
+ _inputId;
95
+ _listboxId;
96
+ _intlController;
97
+ _closeTimeoutHandle;
98
+ _suggestionSync;
66
99
  // #endregion
67
100
  // #region Ctor
68
101
  /**
@@ -70,6 +103,22 @@ let AutoCompleteBoxElement = class AutoCompleteBoxElement extends Themeable(Auto
70
103
  */
71
104
  constructor() {
72
105
  super();
106
+ this._text = '';
107
+ this._shouldSyncSearchFromText = true;
108
+ this._highlightedIndex = -1;
109
+ this._lastFilterText = '';
110
+ this._closeTimeoutHandle = null;
111
+ this._inputId = AutoCompleteBoxElement_1.generateId('mosaik-autocomplete-input');
112
+ this._listboxId = AutoCompleteBoxElement_1.generateId('mosaik-autocomplete-list');
113
+ this._suggestionSync = FloatingSync.Width;
114
+ this.dropDownPlacement = Placement.BottomStart;
115
+ this.dropDownStrategy = Strategy.Fixed;
116
+ this.dropDownDistance = 8;
117
+ this.dropDownSkidding = 0;
118
+ this.maxDropDownHeight = '280px';
119
+ this._intlController = new IntlController(this, {
120
+ factory: () => new AutoCompleteBoxElementIntl()
121
+ });
73
122
  }
74
123
  // #endregion
75
124
  // #region Properties
@@ -97,17 +146,561 @@ let AutoCompleteBoxElement = class AutoCompleteBoxElement extends Themeable(Auto
97
146
  if (this._text !== value) {
98
147
  this._text = value;
99
148
  this.requestUpdate('text');
149
+ if (this._shouldSyncSearchFromText) {
150
+ this._lastFilterText = value;
151
+ this.updateSearchText(value);
152
+ }
100
153
  }
101
154
  }
155
+ /**
156
+ * Gets the identifier of the input element.
157
+ *
158
+ * @public
159
+ * @readonly
160
+ */
161
+ get inputId() {
162
+ return this._inputId;
163
+ }
164
+ /**
165
+ * Gets the identifier of the suggestion list element.
166
+ *
167
+ * @public
168
+ * @readonly
169
+ */
170
+ get listboxId() {
171
+ return this._listboxId;
172
+ }
173
+ /**
174
+ * Gets the index of the highlighted suggestion.
175
+ *
176
+ * @public
177
+ * @readonly
178
+ */
179
+ get highlightedIndex() {
180
+ return this._highlightedIndex;
181
+ }
182
+ /**
183
+ * Gets a value indicating whether the suggestion list should be rendered.
184
+ *
185
+ * @public
186
+ * @readonly
187
+ */
188
+ get shouldRenderSuggestions() {
189
+ if (!this.isFocused) {
190
+ return false;
191
+ }
192
+ if (!this.isDropDownOpen) {
193
+ return false;
194
+ }
195
+ return this.hasSuggestions || this.shouldShowNoResultsMessage || this.shouldShowLoadingState;
196
+ }
197
+ /**
198
+ * Gets a value indicating whether suggestions are available.
199
+ *
200
+ * @public
201
+ * @readonly
202
+ */
203
+ get hasSuggestions() {
204
+ return this.filteredItems.length > 0;
205
+ }
206
+ /**
207
+ * Gets the active descendant identifier for accessibility.
208
+ *
209
+ * @public
210
+ * @readonly
211
+ */
212
+ get activeDescendantId() {
213
+ return this._highlightedIndex >= 0
214
+ ? this.getOptionId(this._highlightedIndex)
215
+ : null;
216
+ }
217
+ /**
218
+ * Gets a value indicating whether the no-results message should be displayed.
219
+ *
220
+ * @public
221
+ * @readonly
222
+ */
223
+ get shouldShowNoResultsMessage() {
224
+ return this.isFocused && !this.isPopulating && this._lastFilterText.length >= this.minimumPrefixLength && this.filteredItems.length === 0;
225
+ }
226
+ /**
227
+ * Gets a value indicating whether the loading state should be displayed.
228
+ *
229
+ * @public
230
+ * @readonly
231
+ */
232
+ get shouldShowLoadingState() {
233
+ return this.isPopulating && !this.hasSuggestions;
234
+ }
235
+ /**
236
+ * Gets or sets the preferred placement for the suggestion popup.
237
+ *
238
+ * @public
239
+ * @attr
240
+ */
241
+ get suggestionPlacement() {
242
+ return this.dropDownPlacement;
243
+ }
244
+ set suggestionPlacement(value) {
245
+ if (this.dropDownPlacement !== value) {
246
+ this.dropDownPlacement = value;
247
+ this.requestUpdate('suggestionPlacement');
248
+ }
249
+ }
250
+ /**
251
+ * Gets or sets the positioning strategy for the suggestion popup.
252
+ *
253
+ * @public
254
+ * @attr
255
+ */
256
+ get suggestionStrategy() {
257
+ return this.dropDownStrategy;
258
+ }
259
+ set suggestionStrategy(value) {
260
+ if (this.dropDownStrategy !== value) {
261
+ this.dropDownStrategy = value;
262
+ this.requestUpdate('suggestionStrategy');
263
+ }
264
+ }
265
+ /**
266
+ * Gets or sets the distance in pixels between the host and the suggestion popup.
267
+ *
268
+ * @public
269
+ * @attr
270
+ */
271
+ get suggestionDistance() {
272
+ return this.dropDownDistance;
273
+ }
274
+ set suggestionDistance(value) {
275
+ if (this.dropDownDistance !== value) {
276
+ this.dropDownDistance = value;
277
+ this.requestUpdate('suggestionDistance');
278
+ }
279
+ }
280
+ /**
281
+ * Gets or sets the horizontal skidding offset for the suggestion popup.
282
+ *
283
+ * @public
284
+ * @attr
285
+ */
286
+ get suggestionSkidding() {
287
+ return this.dropDownSkidding;
288
+ }
289
+ set suggestionSkidding(value) {
290
+ if (this.dropDownSkidding !== value) {
291
+ this.dropDownSkidding = value;
292
+ this.requestUpdate('suggestionSkidding');
293
+ }
294
+ }
295
+ /**
296
+ * Gets or sets the size synchronization mode for the suggestion popup.
297
+ *
298
+ * @public
299
+ * @attr
300
+ */
301
+ get suggestionSync() {
302
+ return this._suggestionSync;
303
+ }
304
+ set suggestionSync(value) {
305
+ if (this._suggestionSync !== value) {
306
+ this._suggestionSync = value;
307
+ this.requestUpdate('suggestionSync');
308
+ }
309
+ }
310
+ /**
311
+ * Gets or sets the maximum height for the suggestion popup.
312
+ *
313
+ * @public
314
+ * @attr
315
+ */
316
+ get maxSuggestionHeight() {
317
+ return this.maxDropDownHeight;
318
+ }
319
+ set maxSuggestionHeight(value) {
320
+ if (this.maxDropDownHeight !== value) {
321
+ this.maxDropDownHeight = value;
322
+ this.requestUpdate('maxSuggestionHeight');
323
+ }
324
+ }
325
+ /**
326
+ * Gets the fallback placements used when positioning the suggestion popup.
327
+ *
328
+ * @public
329
+ * @readonly
330
+ */
331
+ get suggestionFlipFallbackPlacements() {
332
+ return Array.from(AutoCompleteBoxElement_1._floatingFlipFallbackPlacements);
333
+ }
334
+ /**
335
+ * Returns the `intl` property.
336
+ *
337
+ * @public
338
+ * @readonly
339
+ */
340
+ get intl() {
341
+ return this._intlController.intl;
342
+ }
102
343
  // #endregion
103
344
  // #region Methods
104
- onInput(e) {
105
- const input = e.target.value;
106
- this.text = input;
107
- this.updateSearchText(input);
345
+ /**
346
+ * @internal
347
+ */
348
+ onFilterCallback(items) {
349
+ super.onFilterCallback?.(items);
350
+ if (items.length > 0) {
351
+ this.openSuggestions();
352
+ this.setHighlightedIndex(0);
353
+ }
354
+ else if (this.shouldShowNoResultsMessage && this.isFocused) {
355
+ this.openSuggestions();
356
+ this._highlightedIndex = -1;
357
+ }
358
+ else if (!this.isFocused) {
359
+ this.closeSuggestions();
360
+ }
361
+ this.applyTextCompletion();
362
+ }
363
+ /**
364
+ * Synchronizes the suggestion visibility with the floating popup state.
365
+ *
366
+ * @public
367
+ * @param isActive - Indicates whether the floating popup is active.
368
+ */
369
+ onFloatingActiveChanged(isActive) {
370
+ if (!isActive) {
371
+ this.closeSuggestions();
372
+ }
108
373
  }
374
+ /**
375
+ * @public
376
+ * @override
377
+ */
109
378
  onSelectCallback(item) {
110
- this.text = this.getDisplayValue(item);
379
+ const displayValue = this.getDisplayValue(item);
380
+ this.executeWithoutSearchSync(() => {
381
+ this.text = displayValue;
382
+ });
383
+ this._lastFilterText = displayValue;
384
+ this.closeSuggestions();
385
+ }
386
+ /**
387
+ * @public
388
+ * @override
389
+ */
390
+ disconnectedCallback() {
391
+ this.clearCloseTimeout();
392
+ super.disconnectedCallback();
393
+ }
394
+ /**
395
+ * Handles input events raised by the native text box.
396
+ *
397
+ * @public
398
+ * @param event - The event that triggered the handler.
399
+ */
400
+ onInput(event) {
401
+ if (this.disabled) {
402
+ return;
403
+ }
404
+ const value = event.target.value;
405
+ this.cancelCloseSuggestions();
406
+ this._shouldSyncSearchFromText = true;
407
+ this._lastFilterText = value;
408
+ this.text = value;
409
+ if (value.length === 0) {
410
+ this._highlightedIndex = -1;
411
+ }
412
+ this.openSuggestions();
413
+ }
414
+ /**
415
+ * Handles focus events raised by the native input element.
416
+ *
417
+ * @public
418
+ */
419
+ onFocus(_event) {
420
+ this.isFocused = true;
421
+ this.cancelCloseSuggestions();
422
+ if (this.hasSuggestions || this.shouldShowNoResultsMessage) {
423
+ this.openSuggestions();
424
+ }
425
+ }
426
+ /**
427
+ * Handles blur events raised by the native input element.
428
+ *
429
+ * @public
430
+ */
431
+ onBlur(_event) {
432
+ this.isFocused = false;
433
+ this.scheduleCloseSuggestions();
434
+ }
435
+ /**
436
+ * Handles keyboard interactions for navigating the suggestion list.
437
+ *
438
+ * @public
439
+ * @param event - The keyboard event that triggered the handler.
440
+ */
441
+ onKeyDown(event) {
442
+ if (this.disabled) {
443
+ return;
444
+ }
445
+ switch (event.key) {
446
+ case 'ArrowDown': {
447
+ event.preventDefault();
448
+ this.cancelCloseSuggestions();
449
+ this.openSuggestions();
450
+ this.moveHighlight(1);
451
+ break;
452
+ }
453
+ case 'ArrowUp': {
454
+ event.preventDefault();
455
+ this.cancelCloseSuggestions();
456
+ this.openSuggestions();
457
+ this.moveHighlight(-1);
458
+ break;
459
+ }
460
+ case 'Home': {
461
+ if (this.filteredItems.length > 0) {
462
+ event.preventDefault();
463
+ this.setHighlightedIndex(0);
464
+ }
465
+ break;
466
+ }
467
+ case 'End': {
468
+ if (this.filteredItems.length > 0) {
469
+ event.preventDefault();
470
+ this.setHighlightedIndex(this.filteredItems.length - 1);
471
+ }
472
+ break;
473
+ }
474
+ case 'Enter': {
475
+ if (this._highlightedIndex >= 0 && this._highlightedIndex < this.filteredItems.length) {
476
+ event.preventDefault();
477
+ const item = this.filteredItems[this._highlightedIndex];
478
+ this.commitSelection(item);
479
+ }
480
+ break;
481
+ }
482
+ case 'Tab': {
483
+ if (this._highlightedIndex >= 0 && this._highlightedIndex < this.filteredItems.length) {
484
+ const item = this.filteredItems[this._highlightedIndex];
485
+ this.commitSelection(item);
486
+ }
487
+ break;
488
+ }
489
+ case 'Escape': {
490
+ if (this.isDropDownOpen) {
491
+ event.preventDefault();
492
+ this.closeSuggestions();
493
+ }
494
+ break;
495
+ }
496
+ default:
497
+ break;
498
+ }
499
+ }
500
+ /**
501
+ * Handles pointer events to keep the suggestion list open while interacting with it.
502
+ *
503
+ * @public
504
+ * @param event - The mouse event that triggered the handler.
505
+ */
506
+ onSuggestionMouseDown(event) {
507
+ event.preventDefault();
508
+ this.cancelCloseSuggestions();
509
+ }
510
+ /**
511
+ * Handles click events on suggestion items.
512
+ *
513
+ * @public
514
+ * @param index - The index of the clicked suggestion.
515
+ */
516
+ onSuggestionClick(index) {
517
+ if (this.disabled) {
518
+ return;
519
+ }
520
+ const item = this.filteredItems[index];
521
+ if (item !== undefined) {
522
+ this.commitSelection(item);
523
+ }
524
+ }
525
+ /**
526
+ * Renders a suggestion with highlighted text.
527
+ *
528
+ * @public
529
+ * @param item - The item to render.
530
+ */
531
+ renderHighlightedItem(item) {
532
+ const value = this.getDisplayValue(item);
533
+ const searchText = this._lastFilterText;
534
+ if (!searchText) {
535
+ return html `${value}`;
536
+ }
537
+ const lowerValue = value.toLowerCase();
538
+ const lowerSearch = searchText.toLowerCase();
539
+ const segments = [];
540
+ let cursor = 0;
541
+ let matchIndex = lowerValue.indexOf(lowerSearch, cursor);
542
+ while (matchIndex !== -1) {
543
+ const unmatched = value.slice(cursor, matchIndex);
544
+ if (unmatched) {
545
+ segments.push(unmatched);
546
+ }
547
+ const matched = value.slice(matchIndex, matchIndex + searchText.length);
548
+ segments.push(html `<span class="match">${matched}</span>`);
549
+ cursor = matchIndex + searchText.length;
550
+ matchIndex = lowerValue.indexOf(lowerSearch, cursor);
551
+ }
552
+ const tail = value.slice(cursor);
553
+ if (tail) {
554
+ segments.push(tail);
555
+ }
556
+ if (segments.length === 0) {
557
+ segments.push(value);
558
+ }
559
+ return html `${segments}`;
560
+ }
561
+ /**
562
+ * Gets the identifier for the suggestion option at the specified index.
563
+ *
564
+ * @public
565
+ * @param index - The index of the option.
566
+ */
567
+ getOptionId(index) {
568
+ return `${this._listboxId}-option-${index}`;
569
+ }
570
+ /**
571
+ * Synchronizes internal state when the dropdown open state changes.
572
+ *
573
+ * @protected
574
+ */
575
+ onDropDownOpenChanged(_previous, next) {
576
+ if (!next) {
577
+ this._highlightedIndex = -1;
578
+ this.clearCloseTimeout();
579
+ }
580
+ }
581
+ /**
582
+ * @protected
583
+ */
584
+ onDisabledChanged(_previous, next) {
585
+ if (next) {
586
+ this.closeSuggestions();
587
+ }
588
+ }
589
+ static generateId(prefix) {
590
+ AutoCompleteBoxElement_1._idCounter += 1;
591
+ return `${prefix}-${AutoCompleteBoxElement_1._idCounter}`;
592
+ }
593
+ getInputElement() {
594
+ return this.renderRoot.querySelector(`#${this._inputId}`) ?? null;
595
+ }
596
+ executeWithoutSearchSync(action) {
597
+ const previous = this._shouldSyncSearchFromText;
598
+ this._shouldSyncSearchFromText = false;
599
+ try {
600
+ action();
601
+ }
602
+ finally {
603
+ this._shouldSyncSearchFromText = previous;
604
+ }
605
+ }
606
+ openSuggestions() {
607
+ if (!this.isDropDownOpen) {
608
+ this.open();
609
+ }
610
+ }
611
+ closeSuggestions() {
612
+ if (this.isDropDownOpen) {
613
+ this.close();
614
+ }
615
+ this._highlightedIndex = -1;
616
+ this.clearCloseTimeout();
617
+ }
618
+ scheduleCloseSuggestions() {
619
+ this.clearCloseTimeout();
620
+ this._closeTimeoutHandle = window.setTimeout(() => {
621
+ this._closeTimeoutHandle = null;
622
+ this.closeSuggestions();
623
+ }, 150);
624
+ }
625
+ cancelCloseSuggestions() {
626
+ this.clearCloseTimeout();
627
+ }
628
+ clearCloseTimeout() {
629
+ if (this._closeTimeoutHandle !== null) {
630
+ window.clearTimeout(this._closeTimeoutHandle);
631
+ this._closeTimeoutHandle = null;
632
+ }
633
+ }
634
+ commitSelection(item) {
635
+ this.updateSelectedItem(item);
636
+ const input = this.getInputElement();
637
+ if (input) {
638
+ const value = this.text;
639
+ input.value = value;
640
+ input.setSelectionRange(value.length, value.length);
641
+ }
642
+ }
643
+ applyTextCompletion() {
644
+ if (!this.isTextCompletionEnabled) {
645
+ return;
646
+ }
647
+ if (!this.isFocused) {
648
+ return;
649
+ }
650
+ if (!this._lastFilterText) {
651
+ return;
652
+ }
653
+ if (this.filteredItems.length === 0) {
654
+ return;
655
+ }
656
+ const firstItem = this.filteredItems[0];
657
+ const completion = this.getDisplayValue(firstItem);
658
+ if (!completion.toLowerCase().startsWith(this._lastFilterText.toLowerCase())) {
659
+ return;
660
+ }
661
+ const typedLength = this._lastFilterText.length;
662
+ this.executeWithoutSearchSync(() => {
663
+ this.text = completion;
664
+ });
665
+ const input = this.getInputElement();
666
+ if (input) {
667
+ input.value = completion;
668
+ input.setSelectionRange(typedLength, completion.length);
669
+ }
670
+ }
671
+ moveHighlight(step) {
672
+ if (this.filteredItems.length === 0) {
673
+ this._highlightedIndex = -1;
674
+ return;
675
+ }
676
+ const length = this.filteredItems.length;
677
+ const currentIndex = this._highlightedIndex;
678
+ const nextIndex = currentIndex === -1
679
+ ? step > 0 ? 0 : length - 1
680
+ : (currentIndex + step + length) % length;
681
+ this.setHighlightedIndex(nextIndex);
682
+ }
683
+ setHighlightedIndex(index) {
684
+ if (this.filteredItems.length === 0) {
685
+ this._highlightedIndex = -1;
686
+ return;
687
+ }
688
+ const normalizedIndex = Math.max(0, Math.min(index, this.filteredItems.length - 1));
689
+ if (this._highlightedIndex !== normalizedIndex) {
690
+ this._highlightedIndex = normalizedIndex;
691
+ this.requestUpdate();
692
+ this.scrollHighlightedOptionIntoView();
693
+ }
694
+ }
695
+ scrollHighlightedOptionIntoView() {
696
+ if (this._highlightedIndex < 0) {
697
+ return;
698
+ }
699
+ this.scrollOptionIntoView(this._highlightedIndex);
700
+ }
701
+ scrollOptionIntoView(index) {
702
+ const option = this.renderRoot.querySelector(`#${this.getOptionId(index)}`);
703
+ option?.scrollIntoView({ block: 'nearest' });
111
704
  }
112
705
  };
113
706
  __decorate([
@@ -115,7 +708,49 @@ __decorate([
115
708
  __metadata("design:type", String),
116
709
  __metadata("design:paramtypes", [String])
117
710
  ], AutoCompleteBoxElement.prototype, "text", null);
118
- AutoCompleteBoxElement = __decorate([
711
+ __decorate([
712
+ Attribute({ type: Placement }),
713
+ __metadata("design:type", String),
714
+ __metadata("design:paramtypes", [String])
715
+ ], AutoCompleteBoxElement.prototype, "suggestionPlacement", null);
716
+ __decorate([
717
+ Attribute({ type: Strategy }),
718
+ __metadata("design:type", String),
719
+ __metadata("design:paramtypes", [String])
720
+ ], AutoCompleteBoxElement.prototype, "suggestionStrategy", null);
721
+ __decorate([
722
+ Attribute({ type: Number }),
723
+ __metadata("design:type", Number),
724
+ __metadata("design:paramtypes", [Number])
725
+ ], AutoCompleteBoxElement.prototype, "suggestionDistance", null);
726
+ __decorate([
727
+ Attribute({ type: Number }),
728
+ __metadata("design:type", Number),
729
+ __metadata("design:paramtypes", [Number])
730
+ ], AutoCompleteBoxElement.prototype, "suggestionSkidding", null);
731
+ __decorate([
732
+ Attribute({ type: FloatingSync }),
733
+ __metadata("design:type", String),
734
+ __metadata("design:paramtypes", [String])
735
+ ], AutoCompleteBoxElement.prototype, "suggestionSync", null);
736
+ __decorate([
737
+ Attribute({ type: CssLength }),
738
+ __metadata("design:type", Object),
739
+ __metadata("design:paramtypes", [Object])
740
+ ], AutoCompleteBoxElement.prototype, "maxSuggestionHeight", null);
741
+ __decorate([
742
+ Watch('isDropDownOpen'),
743
+ __metadata("design:type", Function),
744
+ __metadata("design:paramtypes", [Boolean, Boolean]),
745
+ __metadata("design:returntype", void 0)
746
+ ], AutoCompleteBoxElement.prototype, "onDropDownOpenChanged", null);
747
+ __decorate([
748
+ Watch('disabled'),
749
+ __metadata("design:type", Function),
750
+ __metadata("design:paramtypes", [Boolean, Boolean]),
751
+ __metadata("design:returntype", void 0)
752
+ ], AutoCompleteBoxElement.prototype, "onDisabledChanged", null);
753
+ AutoCompleteBoxElement = AutoCompleteBoxElement_1 = __decorate([
119
754
  Component({
120
755
  selector: 'mosaik-autocompletebox',
121
756
  template: autoCompleteBoxElementTemplate,
@@ -128,7 +763,10 @@ AutoCompleteBoxElement = __decorate([
128
763
  mode: 'open',
129
764
  delegatesFocus: true
130
765
  },
131
- imports: []
766
+ imports: [
767
+ PortalElement,
768
+ FloatingElement
769
+ ]
132
770
  }),
133
771
  __metadata("design:paramtypes", [])
134
772
  ], AutoCompleteBoxElement);