@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
@@ -131,6 +131,7 @@ export class NileSelect extends NileElement implements NileFormControl{
131
131
  private observedTagsContainer?: Element;
132
132
 
133
133
  private resizeController = new ResizeController(this, {
134
+ target: null,
134
135
  callback: (entries: ResizeObserverEntry[]) => {
135
136
  for (const entry of entries) {
136
137
  if (entry.target.classList.contains('select__tags')) {
@@ -141,6 +142,7 @@ export class NileSelect extends NileElement implements NileFormControl{
141
142
  });
142
143
  private visibilityManager?: VisibilityManager;
143
144
  private chipFitFrame = 0;
145
+ private measurableWatch?: { observer: ResizeObserver; target: Element };
144
146
  private lastChipLayout = { hidden: -1, visible: -1 };
145
147
  @state() private clippedChips: boolean[] = [];
146
148
  private clipFrame = 0;
@@ -158,6 +160,7 @@ export class NileSelect extends NileElement implements NileFormControl{
158
160
  @state() selectedOptions: NileOption[] = [];
159
161
  @state() oldValue: string | string[] = '';
160
162
  @state() private hiddenChipCount = 0;
163
+ @state() oldMaxOptionsVisible: number = 1;
161
164
 
162
165
  /** Last measured width of the overflow button, in px. */
163
166
  private lastOverflowWidth = 0;
@@ -269,18 +272,29 @@ export class NileSelect extends NileElement implements NileFormControl{
269
272
  }
270
273
 
271
274
  private get chipFittingEnabled(): boolean {
272
- return !!this.multiple && !this.maxOptionsVisibleExplicit;
275
+ return !!this.multiple && this.showTooltip && !this.maxOptionsVisibleExplicit;
276
+ }
277
+
278
+ private get legacyTagFitEnabled(): boolean {
279
+ return !!this.multiple && !this.showTooltip;
280
+ }
281
+
282
+ private setFittedMaxOptionsVisible(value: number): void {
283
+ const previous = this._maxOptionsVisible;
284
+ this._maxOptionsVisible = value;
285
+ this.requestUpdate('maxOptionsVisible', previous);
273
286
  }
274
287
 
275
288
  /** Minimum width, in px, of a squeezed chip. Needs `showtooltip`. */
276
- @property({ type: Number, reflect: true, attribute: true }) chipMinWidth = 110;
289
+ @property({ type: Number, attribute: true }) chipMinWidth = 110;
277
290
 
278
291
  /** Maximum width, in px, of a squeezed chip. Needs `showtooltip`. */
279
- @property({ type: Number, reflect: true, attribute: true }) chipMaxWidth = 180;
292
+ @property({ type: Number, attribute: true }) chipMaxWidth = 180;
280
293
 
281
294
  /**
282
- * Shows a chip's full value in a tooltip when its text is clipped, and is
283
- * what allows a chip to be truncated at all.
295
+ * Opts into the fitted chip row: chips are sized between chipMinWidth and chipMaxWidth, the
296
+ * rest collapse into a +N button, and a clipped chip shows its full value in a tooltip.
297
+ * Off by default, which keeps the pre-2.0.9 chip row.
284
298
  */
285
299
  @property({ type: Boolean, attribute: true, reflect: true }) showTooltip = false;
286
300
 
@@ -399,6 +413,9 @@ export class NileSelect extends NileElement implements NileFormControl{
399
413
 
400
414
  // Because this is a form control, it shouldn't be opened initially
401
415
  this.open = false;
416
+ if (this.hasUpdated && this.chipFittingEnabled) {
417
+ this.calculateTotalWidthOfTags();
418
+ }
402
419
  this.emit('nile-init');
403
420
  }
404
421
 
@@ -418,7 +435,7 @@ export class NileSelect extends NileElement implements NileFormControl{
418
435
 
419
436
  private setupResizeObserver(): void {
420
437
  const wanted =
421
- this.autoResize && this.chipFittingEnabled
438
+ this.autoResize && (this.chipFittingEnabled || this.legacyTagFitEnabled)
422
439
  ? (this.shadowRoot?.querySelector('.select__tags') as HTMLElement | null) ??
423
440
  undefined
424
441
  : undefined;
@@ -456,6 +473,12 @@ export class NileSelect extends NileElement implements NileFormControl{
456
473
  }
457
474
  }
458
475
 
476
+ syncValueFromVirtualSelect(event: CustomEvent<{ value?: string | string[] }>) {
477
+ if (event.composedPath()[0] !== event.currentTarget) return;
478
+ if (!event.detail || !('value' in event.detail)) return;
479
+ this.value = event.detail.value ?? (this.multiple ? [] : '');
480
+ }
481
+
459
482
  protected updated(_changedProperties: PropertyValues): void {
460
483
  if(_changedProperties.has('searchEnabled')) {
461
484
  this.updateGroupStickyOffsets();
@@ -472,10 +495,18 @@ export class NileSelect extends NileElement implements NileFormControl{
472
495
  if (
473
496
  _changedProperties.has('autoResize') ||
474
497
  _changedProperties.has('multiple') ||
475
- _changedProperties.has('maxOptionsVisible')
498
+ _changedProperties.has('maxOptionsVisible') ||
499
+ _changedProperties.has('showTooltip')
476
500
  ) {
477
501
  this.setupResizeObserver();
478
502
  }
503
+ if (
504
+ _changedProperties.has('showTooltip') &&
505
+ _changedProperties.get('showTooltip') !== undefined &&
506
+ this.legacyTagFitEnabled
507
+ ) {
508
+ this.calculateTotalWidthOfTags();
509
+ }
479
510
  this.syncVirtualSelectMaxOptionsVisible();
480
511
  if(_changedProperties.has('enableDescription')) {
481
512
  this.setEnableDescriptionInOptions();
@@ -1045,13 +1076,27 @@ export class NileSelect extends NileElement implements NileFormControl{
1045
1076
  return options;
1046
1077
  }
1047
1078
 
1048
- private getOptionPrefixNodes(option: NileOption): Node[] {
1079
+ private prefixCopies = new WeakMap<NileOption, Map<string, { markup: string; nodes: Node[] }>>();
1080
+
1081
+ private getOptionPrefixNodes(option: NileOption, site: 'trigger' | 'chip'): Node[] {
1049
1082
  const prefixSlot = option.shadowRoot?.querySelector(
1050
1083
  'slot[name="prefix"]'
1051
1084
  ) as HTMLSlotElement | null;
1052
1085
  if (!prefixSlot) return [];
1053
1086
 
1054
- return prefixSlot.assignedElements().map(el => el.cloneNode(true));
1087
+ const sources = prefixSlot.assignedElements();
1088
+ const markup = sources.map(el => el.outerHTML).join('');
1089
+ let sites = this.prefixCopies.get(option);
1090
+ if (!sites) {
1091
+ sites = new Map();
1092
+ this.prefixCopies.set(option, sites);
1093
+ }
1094
+ const cached = sites.get(site);
1095
+ if (cached && cached.markup === markup) return cached.nodes;
1096
+
1097
+ const nodes = sources.map(el => el.cloneNode(true));
1098
+ sites.set(site, { markup, nodes });
1099
+ return nodes;
1055
1100
  }
1056
1101
 
1057
1102
  // Gets the first <nile-option> element
@@ -1458,6 +1503,10 @@ export class NileSelect extends NileElement implements NileFormControl{
1458
1503
  }
1459
1504
 
1460
1505
  calculateTotalWidthOfTags() {
1506
+ if (this.legacyTagFitEnabled) {
1507
+ this.fitTagsLegacy();
1508
+ return;
1509
+ }
1461
1510
  if (!this.chipFittingEnabled) return;
1462
1511
 
1463
1512
  if (this.chipFitFrame) cancelAnimationFrame(this.chipFitFrame);
@@ -1467,6 +1516,56 @@ export class NileSelect extends NileElement implements NileFormControl{
1467
1516
  });
1468
1517
  }
1469
1518
 
1519
+ private calculateWidthOfSelectTagsDiv() {
1520
+ if (this.shadowRoot) {
1521
+ const selectTagsDiv = this.shadowRoot.querySelector('div.select__tags');
1522
+ if (selectTagsDiv instanceof HTMLElement) {
1523
+ const width = selectTagsDiv.offsetWidth;
1524
+ return width - 70;
1525
+ }
1526
+ }
1527
+ }
1528
+
1529
+ private fitTagsLegacy() {
1530
+ if (this.maxOptionsVisible !== Infinity) {
1531
+ this.oldMaxOptionsVisible = this.maxOptionsVisible;
1532
+ }
1533
+
1534
+ this.setFittedMaxOptionsVisible(Infinity);
1535
+ setTimeout(() => {
1536
+ const widths: number[] = [];
1537
+ if (this.shadowRoot) {
1538
+ const tags = this.shadowRoot.querySelectorAll('nile-tag');
1539
+ tags.forEach(tag => {
1540
+ if (tag instanceof HTMLElement) {
1541
+ widths.push(tag.offsetWidth);
1542
+ }
1543
+ });
1544
+ }
1545
+ if (this.value.length !== widths.length) {
1546
+ return;
1547
+ }
1548
+
1549
+ const widthOfSelectTagsDiv = this.calculateWidthOfSelectTagsDiv();
1550
+ if (!widthOfSelectTagsDiv) {
1551
+ return;
1552
+ }
1553
+
1554
+ let summ = 0;
1555
+ let lastindex = 0;
1556
+
1557
+ for (let i = 0; i < widths.length; i++) {
1558
+ summ += widths[i];
1559
+
1560
+ if (summ > widthOfSelectTagsDiv) {
1561
+ lastindex = i;
1562
+ break;
1563
+ }
1564
+ }
1565
+ this.setFittedMaxOptionsVisible(lastindex);
1566
+ }, 1);
1567
+ }
1568
+
1470
1569
  private allocateChipWidths(
1471
1570
  natural: number[],
1472
1571
  available: number
@@ -1567,6 +1666,12 @@ export class NileSelect extends NileElement implements NileFormControl{
1567
1666
  return;
1568
1667
  }
1569
1668
 
1669
+ if (container.clientWidth === 0) {
1670
+ this.refitWhenMeasurable(container);
1671
+ return;
1672
+ }
1673
+ this.stopMeasurableWatch();
1674
+
1570
1675
  const overflowEl = container.querySelector(
1571
1676
  '.select__tags-count'
1572
1677
  ) as HTMLElement | null;
@@ -1632,6 +1737,35 @@ export class NileSelect extends NileElement implements NileFormControl{
1632
1737
  this.refreshClippedChips();
1633
1738
  }
1634
1739
 
1740
+ private labelOverflows(content: HTMLSlotElement): boolean {
1741
+ let left = Infinity;
1742
+ let right = -Infinity;
1743
+ const range = document.createRange();
1744
+ for (const node of content.assignedNodes({ flatten: true })) {
1745
+ let rect: DOMRect;
1746
+ if (node.nodeType === Node.TEXT_NODE) {
1747
+ if (!node.textContent?.trim()) continue;
1748
+ range.selectNodeContents(node);
1749
+ rect = range.getBoundingClientRect();
1750
+ } else if (node instanceof Element) {
1751
+ rect = node.getBoundingClientRect();
1752
+ } else {
1753
+ continue;
1754
+ }
1755
+ if (rect.width === 0) continue;
1756
+ left = Math.min(left, rect.left);
1757
+ right = Math.max(right, rect.right);
1758
+ }
1759
+ if (right < left) return false;
1760
+
1761
+ const box = content.getBoundingClientRect();
1762
+ const styles = getComputedStyle(content);
1763
+ const boxLeft = box.left + parseFloat(styles.borderLeftWidth) + parseFloat(styles.paddingLeft);
1764
+ const boxRight = box.right - parseFloat(styles.borderRightWidth) - parseFloat(styles.paddingRight);
1765
+ const epsilon = 1 / 64;
1766
+ return right > boxRight + epsilon || left < boxLeft - epsilon;
1767
+ }
1768
+
1635
1769
  private isChipClipped(el: HTMLElement | null | undefined): boolean {
1636
1770
  if (!el) return false;
1637
1771
 
@@ -1639,8 +1773,8 @@ export class NileSelect extends NileElement implements NileFormControl{
1639
1773
  if (root) {
1640
1774
  const content = root.querySelector(
1641
1775
  '[part="content"]'
1642
- ) as HTMLElement | null;
1643
- if (content && content.scrollWidth > content.clientWidth + 1) return true;
1776
+ ) as HTMLSlotElement | null;
1777
+ if (content && this.labelOverflows(content)) return true;
1644
1778
 
1645
1779
  const inner = root.querySelector(
1646
1780
  '[part="prefix_content_wrapper"]'
@@ -1691,6 +1825,25 @@ export class NileSelect extends NileElement implements NileFormControl{
1691
1825
  if (this.clipFrame) cancelAnimationFrame(this.clipFrame);
1692
1826
  this.clipFrame = 0;
1693
1827
  this.lastChipLayout = { hidden: -1, visible: -1 };
1828
+ this.stopMeasurableWatch();
1829
+ }
1830
+
1831
+ private refitWhenMeasurable(container: Element): void {
1832
+ if (!this.isConnected) return;
1833
+ if (this.measurableWatch?.target === container) return;
1834
+ this.stopMeasurableWatch();
1835
+ const observer = new ResizeObserver(entries => {
1836
+ if (!entries.some(entry => entry.contentRect.width > 0)) return;
1837
+ this.stopMeasurableWatch();
1838
+ this.calculateTotalWidthOfTags();
1839
+ });
1840
+ observer.observe(container);
1841
+ this.measurableWatch = { observer, target: container };
1842
+ }
1843
+
1844
+ private stopMeasurableWatch(): void {
1845
+ this.measurableWatch?.observer.disconnect();
1846
+ this.measurableWatch = undefined;
1694
1847
  }
1695
1848
 
1696
1849
  private getChipLabel(option: NileOption): string {
@@ -1761,7 +1914,7 @@ export class NileSelect extends NileElement implements NileFormControl{
1761
1914
  <div part="tags" class="select__tags select__tags--fitted">
1762
1915
  ${this.selectedOptions.map((option, index) => {
1763
1916
  const label = this.getChipLabel(option);
1764
- const prefixNodes = this.getOptionPrefixNodes(option);
1917
+ const prefixNodes = this.getOptionPrefixNodes(option, 'chip');
1765
1918
  return html`
1766
1919
  <nile-lite-tooltip
1767
1920
  class="select__tag-tip"
@@ -1816,6 +1969,69 @@ export class NileSelect extends NileElement implements NileFormControl{
1816
1969
  `;
1817
1970
  }
1818
1971
 
1972
+ private renderLegacyTags() {
1973
+ return html`
1974
+ <div part="tags" class="select__tags">
1975
+ ${this.selectedOptions.map((option, index) => {
1976
+ if (index < this.maxOptionsVisible || this.maxOptionsVisible <= 0) {
1977
+ return this.showTooltip
1978
+ ? html`<nile-lite-tooltip
1979
+ class="select__tag-tip"
1980
+ .content=${option.getTextLabel()}
1981
+ ?disabled=${this.chipTooltipDisabled(index)}
1982
+ >${this.renderLegacyTag(option, index)}</nile-lite-tooltip
1983
+ >`
1984
+ : this.renderLegacyTag(option, index);
1985
+ } else if (index === this.maxOptionsVisible) {
1986
+ return html`
1987
+ <span class="select__tags-count"
1988
+ >+${this.selectedOptions.length - index} More
1989
+ </span>
1990
+ `;
1991
+ } else {
1992
+ return null;
1993
+ }
1994
+ })}
1995
+ </div>
1996
+ `;
1997
+ }
1998
+
1999
+ private renderLegacyTag(option: NileOption, index: number) {
2000
+ const prefixNodes = this.getOptionPrefixNodes(option, 'chip');
2001
+ const classes = {
2002
+ select__invisible:
2003
+ index + 1 > this.oldMaxOptionsVisible &&
2004
+ this.maxOptionsVisible === Infinity,
2005
+ };
2006
+ return html`
2007
+ <nile-tag
2008
+ class=${classMap(classes)}
2009
+ part="tag"
2010
+ exportparts="
2011
+ base:tag__base,
2012
+ content:tag__content,
2013
+ remove-button:tag__remove-button,
2014
+ remove-button__base:tag__remove-button__base,
2015
+ prefix:tag__prefix,
2016
+ prefix_content_wrapper:tag__prefix_content_wrapper
2017
+ "
2018
+ style=${ifDefined(
2019
+ this.showTooltip ? `max-width:${this.chipMaxWidth}px` : undefined
2020
+ )}
2021
+ ?pill=${this.pill}
2022
+ size=${this.size}
2023
+ removable
2024
+ @nile-remove=${(event: NileRemoveEvent) =>
2025
+ this.handleTagRemove(event, option)}
2026
+ >
2027
+ ${prefixNodes.length
2028
+ ? html`<span class="tag__prefix" slot="prefix">${prefixNodes}</span>`
2029
+ : ''}
2030
+ ${option.getTextLabel()}
2031
+ </nile-tag>
2032
+ `;
2033
+ }
2034
+
1819
2035
  handleInputAfterInit() {
1820
2036
  this.shadowRoot?.querySelector('nile-input')?.inputFocus();
1821
2037
  }
@@ -1836,7 +2052,7 @@ export class NileSelect extends NileElement implements NileFormControl{
1836
2052
  const hasHelpText = (this.helpText || this.help_text) ? true : false;
1837
2053
  const hasErrorMessage = this.errorMessage ? true : false;
1838
2054
  const prefixNodes = this.selectedOptions[0]
1839
- ? this.getOptionPrefixNodes(this.selectedOptions[0])
2055
+ ? this.getOptionPrefixNodes(this.selectedOptions[0], 'trigger')
1840
2056
  : [];
1841
2057
 
1842
2058
  return html`
@@ -1951,59 +2167,7 @@ export class NileSelect extends NileElement implements NileFormControl{
1951
2167
  ${this.multiple
1952
2168
  ? this.chipFittingEnabled
1953
2169
  ? this.renderFittedTags()
1954
- : html`
1955
- <div part="tags" class="select__tags">
1956
- ${this.selectedOptions.map((option, index) => {
1957
- if (
1958
- index < this.maxOptionsVisible ||
1959
- this.maxOptionsVisible <= 0
1960
- ) {
1961
- const prefixNodes =
1962
- this.getOptionPrefixNodes(option);
1963
- return html`
1964
- <nile-lite-tooltip
1965
- class="select__tag-tip"
1966
- .content=${option.getTextLabel()}
1967
- ?disabled=${this.chipTooltipDisabled(index)}
1968
- >
1969
- <nile-tag
1970
- part="tag"
1971
- exportparts="
1972
- base:tag__base,
1973
- content:tag__content,
1974
- remove-button:tag__remove-button,
1975
- remove-button__base:tag__remove-button__base,
1976
- prefix:tag__prefix,
1977
- prefix_content_wrapper:tag__prefix_content_wrapper
1978
- "
1979
- style="max-width:${this.chipMaxWidth}px"
1980
- ?pill=${this.pill}
1981
- size=${this.size}
1982
- removable
1983
- @nile-remove=${(event: NileRemoveEvent) =>
1984
- this.handleTagRemove(event, option)}
1985
- >
1986
- ${prefixNodes.length
1987
- ? html`<span class="tag__prefix" slot="prefix"
1988
- >${prefixNodes}</span
1989
- >`
1990
- : ''}
1991
- ${option.getTextLabel()}
1992
- </nile-tag>
1993
- </nile-lite-tooltip>
1994
- `;
1995
- } else if (index === this.maxOptionsVisible) {
1996
- return html`
1997
- <span class="select__tags-count"
1998
- >+${this.selectedOptions.length - index} More
1999
- </span>
2000
- `;
2001
- } else {
2002
- return null;
2003
- }
2004
- })}
2005
- </div>
2006
- `
2170
+ : this.renderLegacyTags()
2007
2171
  : ''}
2008
2172
 
2009
2173
  <input
@@ -2115,7 +2279,13 @@ export class NileSelect extends NileElement implements NileFormControl{
2115
2279
  </div>
2116
2280
 
2117
2281
  ${this.hasSlotController.test('pre-footer') || this.multiple
2118
- ? html`<div part="footer-area" class="select__pre-footer-area">
2282
+ ? html`<div
2283
+ part="footer-area"
2284
+ class=${classMap({
2285
+ 'select__pre-footer-area': true,
2286
+ 'select__pre-footer-area--query': !this.noWidthSync || this.portal,
2287
+ })}
2288
+ >
2119
2289
  ${this.hasSlotController.test('pre-footer')
2120
2290
  ? html`
2121
2291
  <div part="pre-footer" @click=${this.handlePreFooterClick}>
@@ -60,6 +60,8 @@ export class VirtualScrollHelper {
60
60
  .enableDescription=${component.enableDescription}
61
61
  .tickOnSelect=${component.tickOnSelect}
62
62
  .legacy=${component.legacy}
63
+ @nile-input=${(e: CustomEvent) => component.syncValueFromVirtualSelect(e)}
64
+ @nile-change=${(e: CustomEvent) => component.syncValueFromVirtualSelect(e)}
63
65
  exportparts="
64
66
  select-options,
65
67
  select-no-results,
@@ -246,35 +246,23 @@ export const styles = css`
246
246
  display: contents;
247
247
  }
248
248
 
249
- .select__tags nile-tag {
249
+ :host([showtooltip]) .select__tags nile-tag {
250
250
  flex: 0 1 auto;
251
251
  cursor: pointer;
252
252
  min-width: 0;
253
- }
254
-
255
- /* A chip is capped - and so truncated - only when a tooltip can reveal the
256
- full value. Without one it keeps its natural width and the fit pass moves
257
- the surplus into the +N button instead. */
258
- :host([showtooltip]) .select__tags nile-tag {
259
253
  max-width: var(--nile-width-180px, var(--ng-height-180px));
260
254
  }
261
255
 
262
- /* Only the fitted layout can move a chip into the +N button, so only there
263
- can a chip refuse to shrink. */
264
- :host(:not([showtooltip])) .select__tags--fitted nile-tag {
265
- flex-shrink: 0;
266
- }
267
-
268
- .select__tags nile-tag::part(base) {
256
+ :host([showtooltip]) .select__tags nile-tag::part(base) {
269
257
  max-width: 100%;
270
258
  }
271
259
 
272
- .select__tags nile-tag::part(prefix_content_wrapper) {
260
+ :host([showtooltip]) .select__tags nile-tag::part(prefix_content_wrapper) {
273
261
  flex: 1 1 auto;
274
262
  min-width: 0;
275
263
  }
276
264
 
277
- .select__tags nile-tag::part(content) {
265
+ :host([showtooltip]) .select__tags nile-tag::part(content) {
278
266
  display: block;
279
267
  flex: 1 1 auto;
280
268
  min-width: 0;
@@ -290,7 +278,7 @@ export const styles = css`
290
278
  text-overflow: ellipsis;
291
279
  }
292
280
 
293
- .select__tags nile-tag::part(remove-button) {
281
+ :host([showtooltip]) .select__tags nile-tag::part(remove-button) {
294
282
  flex: 0 0 auto;
295
283
  }
296
284
 
@@ -552,6 +540,9 @@ export const styles = css`
552
540
  gap: var(--nile-spacing-none, var(--ng-spacing-none));
553
541
  justify-content: space-between;
554
542
  box-sizing: unset;
543
+ }
544
+
545
+ .select__footer--query {
555
546
  container-type: inline-size;
556
547
  container-name: nile-select-footer;
557
548
  }
@@ -620,6 +611,10 @@ export const styles = css`
620
611
  }
621
612
  }
622
613
 
614
+ .select__invisible {
615
+ opacity: 0;
616
+ }
617
+
623
618
  .select__prefix--from-options {
624
619
  margin-inline-end: var(--nile-spacing-lg, var(--ng-spacing-md));
625
620
  }