@aquera/nile-elements 2.0.11 → 2.0.13

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 (74) hide show
  1. package/README.md +7 -0
  2. package/demo/app-shell.html +21 -21
  3. package/dist/index.js +170 -167
  4. package/dist/nile-app-shell/nile-app-shell.cjs.js +1 -1
  5. package/dist/nile-app-shell/nile-app-shell.cjs.js.map +1 -1
  6. package/dist/nile-app-shell/nile-app-shell.css.cjs.js +1 -1
  7. package/dist/nile-app-shell/nile-app-shell.css.cjs.js.map +1 -1
  8. package/dist/nile-app-shell/nile-app-shell.css.esm.js +35 -32
  9. package/dist/nile-app-shell/nile-app-shell.esm.js +39 -34
  10. package/dist/nile-app-shell-panel/nile-app-shell-panel.css.cjs.js +1 -1
  11. package/dist/nile-app-shell-panel/nile-app-shell-panel.css.cjs.js.map +1 -1
  12. package/dist/nile-app-shell-panel/nile-app-shell-panel.css.esm.js +3 -1
  13. package/dist/nile-select/nile-select.cjs.js +2 -2
  14. package/dist/nile-select/nile-select.cjs.js.map +1 -1
  15. package/dist/nile-select/nile-select.css.cjs.js +1 -1
  16. package/dist/nile-select/nile-select.css.cjs.js.map +1 -1
  17. package/dist/nile-select/nile-select.css.esm.js +12 -17
  18. package/dist/nile-select/nile-select.esm.js +43 -42
  19. package/dist/nile-select/virtual-scroll-helper.cjs.js +1 -1
  20. package/dist/nile-select/virtual-scroll-helper.cjs.js.map +1 -1
  21. package/dist/nile-select/virtual-scroll-helper.esm.js +2 -0
  22. package/dist/nile-virtual-select/nile-virtual-select.cjs.js +4 -4
  23. package/dist/nile-virtual-select/nile-virtual-select.cjs.js.map +1 -1
  24. package/dist/nile-virtual-select/nile-virtual-select.css.cjs.js +1 -1
  25. package/dist/nile-virtual-select/nile-virtual-select.css.cjs.js.map +1 -1
  26. package/dist/nile-virtual-select/nile-virtual-select.css.esm.js +12 -17
  27. package/dist/nile-virtual-select/nile-virtual-select.esm.js +26 -26
  28. package/dist/src/nile-app-shell/nile-app-shell-regions.test.js +9 -5
  29. package/dist/src/nile-app-shell/nile-app-shell-regions.test.js.map +1 -1
  30. package/dist/src/nile-app-shell/nile-app-shell.css.js +33 -30
  31. package/dist/src/nile-app-shell/nile-app-shell.css.js.map +1 -1
  32. package/dist/src/nile-app-shell/nile-app-shell.d.ts +22 -22
  33. package/dist/src/nile-app-shell/nile-app-shell.js +86 -76
  34. package/dist/src/nile-app-shell/nile-app-shell.js.map +1 -1
  35. package/dist/src/nile-app-shell/nile-app-shell.test.d.ts +1 -0
  36. package/dist/src/nile-app-shell/nile-app-shell.test.js +307 -89
  37. package/dist/src/nile-app-shell/nile-app-shell.test.js.map +1 -1
  38. package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.js +3 -1
  39. package/dist/src/nile-app-shell-panel/nile-app-shell-panel.css.js.map +1 -1
  40. package/dist/src/nile-select/nile-select.css.js +12 -17
  41. package/dist/src/nile-select/nile-select.css.js.map +1 -1
  42. package/dist/src/nile-select/nile-select.d.ts +18 -2
  43. package/dist/src/nile-select/nile-select.js +226 -64
  44. package/dist/src/nile-select/nile-select.js.map +1 -1
  45. package/dist/src/nile-select/nile-select.test.d.ts +1 -0
  46. package/dist/src/nile-select/nile-select.test.js +896 -17
  47. package/dist/src/nile-select/nile-select.test.js.map +1 -1
  48. package/dist/src/nile-select/virtual-scroll-helper.js +2 -0
  49. package/dist/src/nile-select/virtual-scroll-helper.js.map +1 -1
  50. package/dist/src/nile-virtual-select/nile-virtual-select.css.js +12 -17
  51. package/dist/src/nile-virtual-select/nile-virtual-select.css.js.map +1 -1
  52. package/dist/src/nile-virtual-select/nile-virtual-select.d.ts +10 -2
  53. package/dist/src/nile-virtual-select/nile-virtual-select.js +142 -30
  54. package/dist/src/nile-virtual-select/nile-virtual-select.js.map +1 -1
  55. package/dist/src/nile-virtual-select/nile-virtual-select.test.d.ts +1 -0
  56. package/dist/src/nile-virtual-select/nile-virtual-select.test.js +331 -16
  57. package/dist/src/nile-virtual-select/nile-virtual-select.test.js.map +1 -1
  58. package/dist/src/version.js +1 -1
  59. package/dist/src/version.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +1 -1
  62. package/src/nile-app-shell/nile-app-shell-regions.test.ts +9 -5
  63. package/src/nile-app-shell/nile-app-shell.css.ts +33 -30
  64. package/src/nile-app-shell/nile-app-shell.test.ts +348 -105
  65. package/src/nile-app-shell/nile-app-shell.ts +89 -82
  66. package/src/nile-app-shell-panel/nile-app-shell-panel.css.ts +3 -1
  67. package/src/nile-select/nile-select.css.ts +12 -17
  68. package/src/nile-select/nile-select.test.ts +1112 -17
  69. package/src/nile-select/nile-select.ts +237 -67
  70. package/src/nile-select/virtual-scroll-helper.ts +2 -0
  71. package/src/nile-virtual-select/nile-virtual-select.css.ts +12 -17
  72. package/src/nile-virtual-select/nile-virtual-select.test.ts +404 -16
  73. package/src/nile-virtual-select/nile-virtual-select.ts +200 -79
  74. package/vscode-html-custom-data.json +36 -41
@@ -127,7 +127,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
127
127
  @state() displayLabel = '';
128
128
  @state() selectedOptions: VirtualOption[] = [];
129
129
  @state() oldValue: string | string[] = '';
130
-
130
+
131
131
  private scrollTimeout: number | undefined;
132
132
  private scrolling = false;
133
133
  private visibilityManager?: VisibilityManager;
@@ -260,7 +260,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
260
260
  /** Disable width synchronization */
261
261
  @property({ type: Boolean, reflect: true }) noWidthSync = false;
262
262
 
263
- /**
263
+ /**
264
264
  * When true, the listbox will be appended to the document body instead of the parent container.
265
265
  * This is useful when the parent has overflow: hidden, clip-path, or transform applied.
266
266
  */
@@ -288,23 +288,35 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
288
288
  }
289
289
 
290
290
  private get chipFittingEnabled(): boolean {
291
- return !!this.multiple && !this.maxOptionsVisibleExplicit;
291
+ return !!this.multiple && this.showTooltip && !this.maxOptionsVisibleExplicit;
292
+ }
293
+
294
+ private get legacyTagFitEnabled(): boolean {
295
+ return !!this.multiple && !this.showTooltip;
296
+ }
297
+
298
+ private setFittedMaxOptionsVisible(value: number): void {
299
+ const previous = this._maxOptionsVisible;
300
+ this._maxOptionsVisible = value;
301
+ this.requestUpdate('maxOptionsVisible', previous);
292
302
  }
293
303
 
294
304
  /** Minimum width, in px, of a squeezed chip. Needs `showtooltip`. */
295
- @property({ type: Number, reflect: true, attribute: true }) chipMinWidth = 110;
305
+ @property({ type: Number, attribute: true }) chipMinWidth = 110;
296
306
 
297
307
  /** Maximum width, in px, of a squeezed chip. Needs `showtooltip`. */
298
- @property({ type: Number, reflect: true, attribute: true }) chipMaxWidth = 180;
308
+ @property({ type: Number, attribute: true }) chipMaxWidth = 180;
299
309
 
300
310
  /**
301
- * Shows a chip's full value in a tooltip when its text is clipped, and is
302
- * what allows a chip to be truncated at all.
311
+ * Opts into the fitted chip row: chips are sized between chipMinWidth and chipMaxWidth, the
312
+ * rest collapse into a +N button, and a clipped chip shows its full value in a tooltip.
313
+ * Off by default, which keeps the pre-2.0.9 chip row.
303
314
  */
304
315
  @property({ type: Boolean, attribute: true, reflect: true }) showTooltip = false;
305
316
 
306
317
 
307
318
  @state() private hiddenChipCount = 0;
319
+ @state() oldMaxOptionsVisible: number = 1;
308
320
 
309
321
  /** Last measured width of the overflow button, in px. */
310
322
  private lastOverflowWidth = 0;
@@ -353,7 +365,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
353
365
  super.connectedCallback();
354
366
  this.initializeComponent();
355
367
  this.setupEventListeners();
356
-
368
+
357
369
  this.updateComplete.then(() => {
358
370
  if (this.value && this.data.length > 0) {
359
371
  this.selectionChanged();
@@ -381,10 +393,18 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
381
393
  if (
382
394
  changedProperties.has('autoResize') ||
383
395
  changedProperties.has('multiple') ||
384
- changedProperties.has('maxOptionsVisible')
396
+ changedProperties.has('maxOptionsVisible') ||
397
+ changedProperties.has('showTooltip')
385
398
  ) {
386
399
  this.setupResizeObserver();
387
400
  }
401
+ if (
402
+ changedProperties.has('showTooltip') &&
403
+ changedProperties.get('showTooltip') !== undefined &&
404
+ this.legacyTagFitEnabled
405
+ ) {
406
+ this.calculateTotalWidthOfTags();
407
+ }
388
408
  if (
389
409
  changedProperties.has('chipMinWidth') ||
390
410
  changedProperties.has('chipMaxWidth')
@@ -479,7 +499,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
479
499
  document.addEventListener('keydown', this.handleDocumentKeyDown);
480
500
  document.addEventListener('mousedown', this.handleDocumentMouseDown);
481
501
  window.addEventListener('error', this.handleWindowError);
482
-
502
+
483
503
  if (this.portal) {
484
504
  window.addEventListener('resize', this.handleWindowResize);
485
505
  window.addEventListener('scroll', this.handleWindowScroll, true);
@@ -505,11 +525,11 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
505
525
  this.emit('nile-blur');
506
526
  }
507
527
 
508
-
528
+
509
529
  protected firstUpdated(_changed: PropertyValues) {
510
530
  this.visibilityManager = new VisibilityManager({
511
531
  host: this,
512
- target: this.combobox,
532
+ target: this.combobox,
513
533
  enableVisibilityEffect: this.enableVisibilityEffect,
514
534
  enableTabClose: this.enableTabClose,
515
535
  isOpen: () => this.open,
@@ -532,13 +552,13 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
532
552
  emit: (event, detail) => this.emit(`nile-${event}`, detail),
533
553
  });
534
554
  }
535
-
536
-
555
+
556
+
537
557
 
538
558
 
539
559
  private handleDocumentFocusIn(event: FocusEvent): void {
540
- if (!this.open) return;
541
- const path = event.composedPath();
560
+ if (!this.open) return;
561
+ const path = event.composedPath();
542
562
  const hitSelf = path.includes(this);
543
563
  const hitPopup = this.popup && path.includes(this.popup);
544
564
  const hitPortalAppend = this.portal && this.portalManager.portalContainerElement && path.includes(this.portalManager.portalContainerElement);
@@ -600,13 +620,13 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
600
620
  }
601
621
 
602
622
  private handleDocumentMouseDown = (event: MouseEvent): void => {
603
- if (!this.open) return;
604
-
623
+ if (!this.open) return;
624
+
605
625
  const path = event.composedPath();
606
626
  const hitSelf = path.includes(this);
607
627
  const hitPopup = this.popup && path.includes(this.popup);
608
628
  const hitPortalAppend = this.portal && this.portalManager.portalContainerElement && path.includes(this.portalManager.portalContainerElement);
609
-
629
+
610
630
  if (!hitSelf && !hitPopup && !hitPortalAppend) {
611
631
  this.hide();
612
632
  }
@@ -770,7 +790,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
770
790
 
771
791
  private handleOptionSelection(option: Element): void {
772
792
  const optionValue = (option as any).value;
773
-
793
+
774
794
  if (this.multiple) {
775
795
  this.toggleOptionSelection(optionValue);
776
796
  } else {
@@ -801,13 +821,13 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
801
821
 
802
822
  private toggleOptionSelection(optionValue: string): void {
803
823
  const currentValues = Array.isArray(this.value) ? this.value : [];
804
-
824
+
805
825
  if (currentValues.includes(optionValue)) {
806
826
  this.value = currentValues.filter(v => v !== optionValue);
807
827
  } else {
808
828
  this.value = [...currentValues, optionValue];
809
829
  }
810
-
830
+
811
831
  this.selectionChanged();
812
832
  }
813
833
 
@@ -841,8 +861,8 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
841
861
  private selectionChanged(): void {
842
862
  const itemsToSearch = this.originalOptionItems.length > 0 ? this.originalOptionItems : this.data;
843
863
  this.selectedOptions = VirtualSelectSelectionManager.createVirtualOptionsFromValues(
844
- this.value,
845
- itemsToSearch,
864
+ this.value,
865
+ itemsToSearch,
846
866
  this.getDisplayText.bind(this),
847
867
  this.renderItemConfig?.getValue,
848
868
  this.allowHtmlLabel
@@ -872,7 +892,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
872
892
 
873
893
  this.calculateTotalWidthOfTags();
874
894
  }
875
-
895
+
876
896
 
877
897
  handleSearchFocus(): void {
878
898
  document.removeEventListener('keydown', this.handleDocumentKeyDown);
@@ -887,21 +907,21 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
887
907
  if (this.portal) {
888
908
  this.portalManager.updatePortalAppendPosition();
889
909
  }
890
-
891
- this.emit('nile-search', {
910
+
911
+ this.emit('nile-search', {
892
912
  query: this.searchValue,
893
- name: this.name
913
+ name: this.name
894
914
  });
895
-
915
+
896
916
  if (!this.disableLocalSearch) {
897
917
  this.filterVirtualOptions(this.searchValue);
898
918
  this.repaintOptionsContainer();
899
-
919
+
900
920
  // Reset measured height when search changes (content height may change)
901
921
  this.portalManager.resetMeasuredHeight();
902
922
  }
903
923
  }
904
-
924
+
905
925
  repaintOptionsContainer() {
906
926
  this.resetScrollPosition();
907
927
  this.updateComplete.then(() => {
@@ -922,7 +942,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
922
942
  }
923
943
 
924
944
  const target = e.target as HTMLElement;
925
-
945
+
926
946
  this.emit('nile-scroll', {
927
947
  scrollTop: target.scrollTop,
928
948
  scrollLeft: target.scrollLeft,
@@ -995,12 +1015,12 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
995
1015
  }
996
1016
  }
997
1017
 
998
-
1018
+
999
1019
  @watch('value', { waitUntilFirstUpdate: true })
1000
1020
  handleValueChange(): void {
1001
1021
  this.selectionChanged();
1002
1022
  this.requestUpdate();
1003
-
1023
+
1004
1024
  // Update body append content if it's active
1005
1025
  if (this.portal && this.portalManager.portalContainerElement) {
1006
1026
  this.portalManager.updatePortalAppendPosition();
@@ -1020,10 +1040,10 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1020
1040
  this.showNoResults = false;
1021
1041
  }
1022
1042
  this.requestUpdate();
1023
-
1043
+
1024
1044
  // Reset measured height when data changes (content height may change)
1025
1045
  this.portalManager.resetMeasuredHeight();
1026
-
1046
+
1027
1047
  // Update body append content if it's active
1028
1048
  if (this.portal && this.portalManager.portalContainerElement) {
1029
1049
  this.portalManager.updatePortalAppendPosition();
@@ -1045,7 +1065,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1045
1065
  this.showNoResults = true;
1046
1066
  }
1047
1067
  this.requestUpdate();
1048
-
1068
+
1049
1069
  // Update body append content if it's active
1050
1070
  if (this.portal && this.portalManager.portalContainerElement) {
1051
1071
  this.portalManager.updatePortalAppendPosition();
@@ -1070,7 +1090,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1070
1090
  this.showListbox = true;
1071
1091
  await this.updateComplete;
1072
1092
  await this.handleOpen();
1073
-
1093
+
1074
1094
  if (this.portal) {
1075
1095
  this.portalManager.setupPortalAppend();
1076
1096
  }
@@ -1078,7 +1098,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1078
1098
  this.visibilityManager?.cleanup();
1079
1099
  await this.handleClose();
1080
1100
  this.showListbox = false;
1081
-
1101
+
1082
1102
  if (this.portal) {
1083
1103
  this.portalManager.cleanupPortalAppend();
1084
1104
  }
@@ -1091,20 +1111,20 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1091
1111
  this.showNoResults = !this.data?.length;
1092
1112
 
1093
1113
  await stopAnimations(this);
1094
-
1114
+
1095
1115
  // Hide popup initially to prevent flickering during positioning calculation
1096
1116
  // This allows content to be measured while invisible
1097
1117
  if (this.popup?.popup) {
1098
1118
  this.popup.popup.style.visibility = 'hidden';
1099
1119
  }
1100
-
1120
+
1101
1121
  this.popup.active = true;
1102
-
1122
+
1103
1123
  // Wait for positioning to complete before showing the popup
1104
1124
  await new Promise(resolve => requestAnimationFrame(resolve));
1105
1125
  // Wait for next frame to allow Floating UI to calculate position
1106
1126
  await new Promise(resolve => requestAnimationFrame(resolve));
1107
-
1127
+
1108
1128
  // Show popup after positioning is calculated
1109
1129
  if (this.popup?.popup) {
1110
1130
  this.popup.popup.style.visibility = '';
@@ -1120,7 +1140,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1120
1140
  this.data = [...this.originalOptionItems];
1121
1141
  this.wasShowSelectedCheckedOnClose = false;
1122
1142
  }
1123
-
1143
+
1124
1144
  this.filterVirtualOptions("");
1125
1145
  this.resetScrollPosition();
1126
1146
  this.emit('nile-after-show', { value: this.value, name: this.name });
@@ -1138,17 +1158,17 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1138
1158
  });
1139
1159
  await animateTo(this.popup.popup, keyframes, options);
1140
1160
  this.popup.active = false;
1141
-
1161
+
1142
1162
  // Reset visibility style when closing
1143
1163
  if (this.popup?.popup) {
1144
1164
  this.popup.popup.style.visibility = '';
1145
1165
  }
1146
1166
 
1147
1167
  this.searchValue = '';
1148
-
1168
+
1149
1169
  // Reset measured height when popup closes (content may change on next open)
1150
1170
  this.portalManager.resetMeasuredHeight();
1151
-
1171
+
1152
1172
  this.emit('nile-after-hide', { value: this.value, name: this.name });
1153
1173
  }
1154
1174
 
@@ -1248,10 +1268,10 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1248
1268
  }
1249
1269
 
1250
1270
  private renderFormControlInput(
1251
- hasCustomSelect: boolean,
1252
- hasClearIcon: boolean,
1253
- isPlaceholderVisible: boolean,
1254
- hasHelpText: boolean,
1271
+ hasCustomSelect: boolean,
1272
+ hasClearIcon: boolean,
1273
+ isPlaceholderVisible: boolean,
1274
+ hasHelpText: boolean,
1255
1275
  hasErrorMessage: boolean
1256
1276
  ): TemplateResult {
1257
1277
  return html`
@@ -1441,31 +1461,14 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1441
1461
  index < this.maxOptionsVisible ||
1442
1462
  this.maxOptionsVisible <= 0
1443
1463
  ) {
1444
- return html`
1445
- <nile-lite-tooltip
1464
+ return this.showTooltip
1465
+ ? html`<nile-lite-tooltip
1446
1466
  class="select__tag-tip"
1447
1467
  .content=${option.getTextLabel()}
1448
1468
  ?disabled=${this.chipTooltipDisabled(index)}
1449
- >
1450
- <nile-tag
1451
- part="tag"
1452
- exportparts="
1453
- base:tag__base,
1454
- content:tag__content,
1455
- remove-button:tag__remove-button,
1456
- remove-button__base:tag__remove-button__base
1457
- "
1458
- style="max-width:${this.chipMaxWidth}px"
1459
- ?pill=${this.pill}
1460
- size=${this.size}
1461
- removable
1462
- @nile-remove=${(event: NileRemoveEvent) =>
1463
- this.handleTagRemove(event, option)}
1464
- >
1465
- ${option.getTextLabel()}
1466
- </nile-tag>
1467
- </nile-lite-tooltip>
1468
- `;
1469
+ >${this.renderLegacyTag(option, index)}</nile-lite-tooltip
1470
+ >`
1471
+ : this.renderLegacyTag(option, index);
1469
1472
  } else if (index === this.maxOptionsVisible) {
1470
1473
  return html`
1471
1474
  <span class="select__tags-count"
@@ -1481,6 +1484,36 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1481
1484
  : html``;
1482
1485
  }
1483
1486
 
1487
+ private renderLegacyTag(option: VirtualOption, index: number): TemplateResult {
1488
+ const classes = {
1489
+ select__invisible:
1490
+ index + 1 > this.oldMaxOptionsVisible &&
1491
+ this.maxOptionsVisible === Infinity,
1492
+ };
1493
+ return html`
1494
+ <nile-tag
1495
+ class=${classMap(classes)}
1496
+ part="tag"
1497
+ exportparts="
1498
+ base:tag__base,
1499
+ content:tag__content,
1500
+ remove-button:tag__remove-button,
1501
+ remove-button__base:tag__remove-button__base
1502
+ "
1503
+ style=${ifDefined(
1504
+ this.showTooltip ? `max-width:${this.chipMaxWidth}px` : undefined
1505
+ )}
1506
+ ?pill=${this.pill}
1507
+ size=${this.size}
1508
+ removable
1509
+ @nile-remove=${(event: NileRemoveEvent) =>
1510
+ this.handleTagRemove(event, option)}
1511
+ >
1512
+ ${option.getTextLabel()}
1513
+ </nile-tag>
1514
+ `;
1515
+ }
1516
+
1484
1517
  private renderValueInput(): TemplateResult {
1485
1518
  return html`
1486
1519
  <input
@@ -1595,7 +1628,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1595
1628
  </span>
1596
1629
  `;
1597
1630
  }
1598
-
1631
+
1599
1632
  if (this.optionsLoading) {
1600
1633
  return html`
1601
1634
  <span part="loader" class="select__loader">
@@ -1606,7 +1639,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1606
1639
  </span>
1607
1640
  `;
1608
1641
  }
1609
-
1642
+
1610
1643
  return html``;
1611
1644
  }
1612
1645
 
@@ -1615,7 +1648,11 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1615
1648
  ? html`
1616
1649
  <div
1617
1650
  part="footer"
1618
- class="select__footer ${this.loading ? 'loading' : ''}"
1651
+ class=${classMap({
1652
+ 'select__footer': true,
1653
+ loading: !!this.loading,
1654
+ 'select__footer--query': !this.noWidthSync || this.portal,
1655
+ })}
1619
1656
  @click="${this.handleFooterClick}"
1620
1657
  >
1621
1658
  <span
@@ -1708,7 +1745,7 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1708
1745
 
1709
1746
  private setupResizeObserver(): void {
1710
1747
  const wanted =
1711
- this.autoResize && this.chipFittingEnabled
1748
+ this.autoResize && (this.chipFittingEnabled || this.legacyTagFitEnabled)
1712
1749
  ? (this.shadowRoot?.querySelector('.select__tags') as HTMLElement | null) ??
1713
1750
  undefined
1714
1751
  : undefined;
@@ -1735,6 +1772,10 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1735
1772
  }
1736
1773
 
1737
1774
  private calculateTotalWidthOfTags(): void {
1775
+ if (this.legacyTagFitEnabled) {
1776
+ this.fitTagsLegacy();
1777
+ return;
1778
+ }
1738
1779
  if (!this.chipFittingEnabled) return;
1739
1780
 
1740
1781
  if (this.chipFitFrame) cancelAnimationFrame(this.chipFitFrame);
@@ -1744,6 +1785,57 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1744
1785
  });
1745
1786
  }
1746
1787
 
1788
+ private calculateWidthOfSelectTagsDiv(): number | null {
1789
+ if (this.shadowRoot) {
1790
+ const selectTagsDiv = this.shadowRoot.querySelector('.select__tags') as HTMLElement;
1791
+ if (selectTagsDiv) {
1792
+ const width = selectTagsDiv.offsetWidth;
1793
+ return width - 70;
1794
+ }
1795
+ }
1796
+ return null;
1797
+ }
1798
+
1799
+ private fitTagsLegacy(): void {
1800
+ if (this.maxOptionsVisible !== Infinity) {
1801
+ this.oldMaxOptionsVisible = this.maxOptionsVisible;
1802
+ }
1803
+
1804
+ this.setFittedMaxOptionsVisible(Infinity);
1805
+ setTimeout(() => {
1806
+ const widths: number[] = [];
1807
+ if (this.shadowRoot) {
1808
+ const tags = this.shadowRoot.querySelectorAll('nile-tag');
1809
+ tags.forEach(tag => {
1810
+ if (tag instanceof HTMLElement) {
1811
+ widths.push(tag.offsetWidth);
1812
+ }
1813
+ });
1814
+ }
1815
+ if (this.value.length !== widths.length) {
1816
+ return;
1817
+ }
1818
+
1819
+ const widthOfSelectTagsDiv = this.calculateWidthOfSelectTagsDiv();
1820
+ if (!widthOfSelectTagsDiv) {
1821
+ return;
1822
+ }
1823
+
1824
+ let summ = 0;
1825
+ let lastindex = 0;
1826
+
1827
+ for (let i = 0; i < widths.length; i++) {
1828
+ summ += widths[i];
1829
+
1830
+ if (summ > widthOfSelectTagsDiv) {
1831
+ lastindex = i;
1832
+ break;
1833
+ }
1834
+ }
1835
+ this.setFittedMaxOptionsVisible(lastindex);
1836
+ }, 1);
1837
+ }
1838
+
1747
1839
  private allocateChipWidths(
1748
1840
  natural: number[],
1749
1841
  available: number
@@ -1913,6 +2005,35 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1913
2005
  this.refreshClippedChips();
1914
2006
  }
1915
2007
 
2008
+ private labelOverflows(content: HTMLSlotElement): boolean {
2009
+ let left = Infinity;
2010
+ let right = -Infinity;
2011
+ const range = document.createRange();
2012
+ for (const node of content.assignedNodes({ flatten: true })) {
2013
+ let rect: DOMRect;
2014
+ if (node.nodeType === Node.TEXT_NODE) {
2015
+ if (!node.textContent?.trim()) continue;
2016
+ range.selectNodeContents(node);
2017
+ rect = range.getBoundingClientRect();
2018
+ } else if (node instanceof Element) {
2019
+ rect = node.getBoundingClientRect();
2020
+ } else {
2021
+ continue;
2022
+ }
2023
+ if (rect.width === 0) continue;
2024
+ left = Math.min(left, rect.left);
2025
+ right = Math.max(right, rect.right);
2026
+ }
2027
+ if (right < left) return false;
2028
+
2029
+ const box = content.getBoundingClientRect();
2030
+ const styles = getComputedStyle(content);
2031
+ const boxLeft = box.left + parseFloat(styles.borderLeftWidth) + parseFloat(styles.paddingLeft);
2032
+ const boxRight = box.right - parseFloat(styles.borderRightWidth) - parseFloat(styles.paddingRight);
2033
+ const epsilon = 1 / 64;
2034
+ return right > boxRight + epsilon || left < boxLeft - epsilon;
2035
+ }
2036
+
1916
2037
  private isChipClipped(el: HTMLElement | null | undefined): boolean {
1917
2038
  if (!el) return false;
1918
2039
 
@@ -1920,8 +2041,8 @@ export class NileVirtualSelect extends NileElement implements NileFormControl {
1920
2041
  if (root) {
1921
2042
  const content = root.querySelector(
1922
2043
  '[part="content"]'
1923
- ) as HTMLElement | null;
1924
- if (content && content.scrollWidth > content.clientWidth + 1) return true;
2044
+ ) as HTMLSlotElement | null;
2045
+ if (content && this.labelOverflows(content)) return true;
1925
2046
 
1926
2047
  const inner = root.querySelector(
1927
2048
  '[part="prefix_content_wrapper"]'