@aquera/nile-elements 2.0.17 → 2.0.19

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 (89) hide show
  1. package/README.md +8 -0
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.esm.js +1 -1
  4. package/dist/index.js +629 -440
  5. package/dist/nile-breadcrumb/nile-breadcrumb.cjs.js +1 -1
  6. package/dist/nile-breadcrumb/nile-breadcrumb.cjs.js.map +1 -1
  7. package/dist/nile-breadcrumb/nile-breadcrumb.esm.js +2 -2
  8. package/dist/nile-breadcrumb-item/nile-breadcrumb-item.cjs.js +1 -1
  9. package/dist/nile-breadcrumb-item/nile-breadcrumb-item.cjs.js.map +1 -1
  10. package/dist/nile-breadcrumb-item/nile-breadcrumb-item.css.cjs.js +1 -1
  11. package/dist/nile-breadcrumb-item/nile-breadcrumb-item.css.cjs.js.map +1 -1
  12. package/dist/nile-breadcrumb-item/nile-breadcrumb-item.css.esm.js +14 -2
  13. package/dist/nile-breadcrumb-item/nile-breadcrumb-item.esm.js +4 -4
  14. package/dist/nile-minimap/index.cjs.js +2 -0
  15. package/dist/nile-minimap/index.cjs.js.map +1 -0
  16. package/dist/nile-minimap/index.esm.js +1 -0
  17. package/dist/nile-minimap/nile-minimap.cjs.js +2 -0
  18. package/dist/nile-minimap/nile-minimap.cjs.js.map +1 -0
  19. package/dist/nile-minimap/nile-minimap.css.cjs.js +2 -0
  20. package/dist/nile-minimap/nile-minimap.css.cjs.js.map +1 -0
  21. package/dist/nile-minimap/nile-minimap.css.esm.js +150 -0
  22. package/dist/nile-minimap/nile-minimap.esm.js +22 -0
  23. package/dist/nile-select/index.cjs.js +1 -1
  24. package/dist/nile-select/index.esm.js +1 -1
  25. package/dist/nile-select/nile-select.cjs.js +2 -2
  26. package/dist/nile-select/nile-select.cjs.js.map +1 -1
  27. package/dist/nile-select/nile-select.esm.js +1 -1
  28. package/dist/nile-select/virtual-scroll-helper.cjs.js +1 -1
  29. package/dist/nile-select/virtual-scroll-helper.cjs.js.map +1 -1
  30. package/dist/nile-select/virtual-scroll-helper.esm.js +48 -47
  31. package/dist/nile-virtual-select/nile-virtual-select.cjs.js +4 -4
  32. package/dist/nile-virtual-select/nile-virtual-select.cjs.js.map +1 -1
  33. package/dist/nile-virtual-select/nile-virtual-select.esm.js +2 -2
  34. package/dist/src/index.d.ts +1 -0
  35. package/dist/src/index.js +1 -0
  36. package/dist/src/index.js.map +1 -1
  37. package/dist/src/nile-breadcrumb/nile-breadcrumb.d.ts +7 -0
  38. package/dist/src/nile-breadcrumb/nile-breadcrumb.js +24 -1
  39. package/dist/src/nile-breadcrumb/nile-breadcrumb.js.map +1 -1
  40. package/dist/src/nile-breadcrumb/nile-breadcrumb.test.js +51 -0
  41. package/dist/src/nile-breadcrumb/nile-breadcrumb.test.js.map +1 -1
  42. package/dist/src/nile-breadcrumb-item/nile-breadcrumb-item.css.js +12 -0
  43. package/dist/src/nile-breadcrumb-item/nile-breadcrumb-item.css.js.map +1 -1
  44. package/dist/src/nile-breadcrumb-item/nile-breadcrumb-item.d.ts +5 -0
  45. package/dist/src/nile-breadcrumb-item/nile-breadcrumb-item.js +9 -0
  46. package/dist/src/nile-breadcrumb-item/nile-breadcrumb-item.js.map +1 -1
  47. package/dist/src/nile-minimap/index.d.ts +1 -0
  48. package/dist/src/nile-minimap/index.js +2 -0
  49. package/dist/src/nile-minimap/index.js.map +1 -0
  50. package/dist/src/nile-minimap/nile-minimap.css.d.ts +12 -0
  51. package/dist/src/nile-minimap/nile-minimap.css.js +162 -0
  52. package/dist/src/nile-minimap/nile-minimap.css.js.map +1 -0
  53. package/dist/src/nile-minimap/nile-minimap.d.ts +131 -0
  54. package/dist/src/nile-minimap/nile-minimap.js +704 -0
  55. package/dist/src/nile-minimap/nile-minimap.js.map +1 -0
  56. package/dist/src/nile-minimap/nile-minimap.test.d.ts +1 -0
  57. package/dist/src/nile-minimap/nile-minimap.test.js +785 -0
  58. package/dist/src/nile-minimap/nile-minimap.test.js.map +1 -0
  59. package/dist/src/nile-select/nile-select.d.ts +1 -0
  60. package/dist/src/nile-select/nile-select.js +16 -1
  61. package/dist/src/nile-select/nile-select.js.map +1 -1
  62. package/dist/src/nile-select/nile-select.test.js +430 -5
  63. package/dist/src/nile-select/nile-select.test.js.map +1 -1
  64. package/dist/src/nile-select/virtual-scroll-helper.js +7 -4
  65. package/dist/src/nile-select/virtual-scroll-helper.js.map +1 -1
  66. package/dist/src/nile-virtual-select/nile-virtual-select.d.ts +3 -1
  67. package/dist/src/nile-virtual-select/nile-virtual-select.js +14 -6
  68. package/dist/src/nile-virtual-select/nile-virtual-select.js.map +1 -1
  69. package/dist/src/nile-virtual-select/nile-virtual-select.test.js +115 -1
  70. package/dist/src/nile-virtual-select/nile-virtual-select.test.js.map +1 -1
  71. package/dist/src/version.js +1 -1
  72. package/dist/src/version.js.map +1 -1
  73. package/dist/tsconfig.tsbuildinfo +1 -1
  74. package/package.json +2 -1
  75. package/src/index.ts +1 -0
  76. package/src/nile-breadcrumb/nile-breadcrumb.test.ts +57 -0
  77. package/src/nile-breadcrumb/nile-breadcrumb.ts +19 -0
  78. package/src/nile-breadcrumb-item/nile-breadcrumb-item.css.ts +12 -0
  79. package/src/nile-breadcrumb-item/nile-breadcrumb-item.ts +7 -0
  80. package/src/nile-minimap/index.ts +1 -0
  81. package/src/nile-minimap/nile-minimap.css.ts +164 -0
  82. package/src/nile-minimap/nile-minimap.test.ts +924 -0
  83. package/src/nile-minimap/nile-minimap.ts +796 -0
  84. package/src/nile-select/nile-select.test.ts +560 -5
  85. package/src/nile-select/nile-select.ts +21 -1
  86. package/src/nile-select/virtual-scroll-helper.ts +7 -4
  87. package/src/nile-virtual-select/nile-virtual-select.test.ts +139 -1
  88. package/src/nile-virtual-select/nile-virtual-select.ts +17 -6
  89. package/vscode-html-custom-data.json +138 -36
@@ -1,4 +1,4 @@
1
- import { aTimeout, expect, fixture, html, nextFrame, waitUntil } from '@open-wc/testing';
1
+ import { aTimeout, expect, fixture, html, nextFrame, oneEvent, waitUntil } from '@open-wc/testing';
2
2
  import './nile-select';
3
3
  import '../nile-option/nile-option';
4
4
  import '../nile-input/nile-input';
@@ -507,12 +507,13 @@ describe('NileSelect chip fitting behaviour matrix', () => {
507
507
  expect(el.shadowRoot.querySelector('button.select__tags-count')).to.not.exist;
508
508
  });
509
509
  });
510
- describe('NileSelect enableVirtualScroll value sync', () => {
510
+ describe('NileSelect enableVirtualScroll value sync (showTooltip)', () => {
511
511
  const ROLES = ['Administrators', 'Users', 'Guests', 'Print Operators'];
512
512
  const DATA = ROLES.map(role => ({ label: role, value: role }));
513
513
  async function virtualSelect(tpl = html `<nile-select
514
514
  multiple
515
515
  .enableVirtualScroll=${true}
516
+ .showTooltip=${true}
516
517
  .data=${DATA}
517
518
  .value=${[]}
518
519
  ></nile-select>`) {
@@ -546,6 +547,7 @@ describe('NileSelect enableVirtualScroll value sync', () => {
546
547
  const { el, inner } = await virtualSelect(html `<nile-select
547
548
  multiple
548
549
  .enableVirtualScroll=${true}
550
+ .showTooltip=${true}
549
551
  .data=${DATA}
550
552
  .value=${['Administrators', 'Users', 'Guests']}
551
553
  ></nile-select>`);
@@ -569,6 +571,7 @@ describe('NileSelect enableVirtualScroll value sync', () => {
569
571
  it('V5. single-select virtual mode keeps the wrapper value in sync', async () => {
570
572
  const { el, inner } = await virtualSelect(html `<nile-select
571
573
  .enableVirtualScroll=${true}
574
+ .showTooltip=${true}
572
575
  .data=${DATA}
573
576
  ></nile-select>`);
574
577
  inner.handleOptionSelection({ value: 'Users' });
@@ -580,7 +583,8 @@ describe('NileSelect enableVirtualScroll value sync', () => {
580
583
  });
581
584
  it('V6. resizing the host does not re-render the wrapper without autoResize', async () => {
582
585
  const host = await fixture(html `<div style="width: 400px">
583
- <nile-select multiple .enableVirtualScroll=${true} .data=${DATA}></nile-select>
586
+ <nile-select multiple .enableVirtualScroll=${true}
587
+ .showTooltip=${true} .data=${DATA}></nile-select>
584
588
  </div>`);
585
589
  const el = host.querySelector('nile-select');
586
590
  await el.updateComplete;
@@ -599,7 +603,7 @@ describe('NileSelect enableVirtualScroll value sync', () => {
599
603
  expect(updates).to.equal(0);
600
604
  });
601
605
  });
602
- describe('NileSelect enableVirtualScroll + searchEnabled value sync', () => {
606
+ describe('NileSelect enableVirtualScroll + searchEnabled value sync (showTooltip)', () => {
603
607
  const ROLES = ['Administrators', 'Users', 'Guests', 'Print Operators'];
604
608
  const DATA = ROLES.map(role => ({ label: role, value: role }));
605
609
  async function settle(el, inner) {
@@ -615,6 +619,7 @@ describe('NileSelect enableVirtualScroll + searchEnabled value sync', () => {
615
619
  ?multiple=${multiple}
616
620
  .searchEnabled=${true}
617
621
  .enableVirtualScroll=${true}
622
+ .showTooltip=${true}
618
623
  .portal=${portal}
619
624
  .data=${DATA}
620
625
  .value=${value}
@@ -1251,7 +1256,7 @@ describe('NileSelect 2.0.8 compatibility matrix', () => {
1251
1256
  expect(inner.value).to.deep.equal(['b']);
1252
1257
  expect(inner.shadowRoot.querySelectorAll('.select__tags nile-tag').length).to.equal(1);
1253
1258
  });
1254
- it('C9. enableVirtualScroll: programmatic value and clear-all reach both selects', async () => {
1259
+ it('C9. enableVirtualScroll: programmatic value reaches the inner select; clear-all leaves the outer value alone (pre-2.0.9)', async () => {
1255
1260
  const el = await fixture(html `<nile-select multiple .enableVirtualScroll=${true} .data=${DATA}></nile-select>`);
1256
1261
  await settle(el);
1257
1262
  const inner = el.shadowRoot.querySelector('nile-virtual-select');
@@ -1263,6 +1268,21 @@ describe('NileSelect 2.0.8 compatibility matrix', () => {
1263
1268
  await inner.updateComplete;
1264
1269
  await settle(el);
1265
1270
  expect(inner.value).to.deep.equal([]);
1271
+ // Without showTooltip the inner select owns the selection; the outer value is not written back.
1272
+ expect(el.value).to.deep.equal(['a', 'c']);
1273
+ });
1274
+ it('C9b. enableVirtualScroll + showTooltip: programmatic value and clear-all reach both selects', async () => {
1275
+ const el = await fixture(html `<nile-select multiple showTooltip .enableVirtualScroll=${true} .data=${DATA}></nile-select>`);
1276
+ await settle(el);
1277
+ const inner = el.shadowRoot.querySelector('nile-virtual-select');
1278
+ el.value = ['a', 'c'];
1279
+ await settle(el);
1280
+ await inner.updateComplete;
1281
+ expect(inner.value).to.deep.equal(['a', 'c']);
1282
+ inner.unSelectAll();
1283
+ await inner.updateComplete;
1284
+ await settle(el);
1285
+ expect(inner.value).to.deep.equal([]);
1266
1286
  expect(el.value).to.deep.equal([]);
1267
1287
  });
1268
1288
  });
@@ -1325,4 +1345,409 @@ describe('NileSelect showtooltip tooltip on sub-pixel truncation', () => {
1325
1345
  }
1326
1346
  });
1327
1347
  });
1348
+ const vsMounted = [];
1349
+ const VS_OPTIONS = Array.from({ length: 300 }, (_, i) => ({ value: `option-${i + 1}`, label: `Option ${i + 1}` }));
1350
+ function vsRoots(inner) {
1351
+ const portal = document.body.querySelector('.nile-virtual-select-portal-append');
1352
+ return [inner.shadowRoot, ...(portal ? [portal] : [])];
1353
+ }
1354
+ function vsAll(inner, selector) {
1355
+ return vsRoots(inner).flatMap(root => Array.from(root.querySelectorAll(selector)));
1356
+ }
1357
+ async function vsMount({ showTooltip = false, multiple = true, search = false, portal = false, value = undefined, data = VS_OPTIONS, } = {}) {
1358
+ const initial = value ?? (multiple ? [] : '');
1359
+ const el = await fixture(html `<nile-select
1360
+ ?multiple=${multiple}
1361
+ ?searchEnabled=${search}
1362
+ ?showTooltip=${showTooltip}
1363
+ .enableVirtualScroll=${true}
1364
+ .portal=${portal}
1365
+ .data=${data}
1366
+ .value=${initial}
1367
+ ></nile-select>`);
1368
+ await el.updateComplete;
1369
+ const inner = el.shadowRoot.querySelector('nile-virtual-select');
1370
+ await inner.updateComplete;
1371
+ vsMounted.push(inner);
1372
+ let updates = 0;
1373
+ const update = el.update;
1374
+ el.update = function (changed) {
1375
+ updates++;
1376
+ return update.call(this, changed);
1377
+ };
1378
+ return { el, inner, updates: () => updates, resetUpdates: () => (updates = 0) };
1379
+ }
1380
+ async function vsSettle(el, inner) {
1381
+ await inner.updateComplete;
1382
+ await el.updateComplete;
1383
+ await inner.updateComplete;
1384
+ await aTimeout(30);
1385
+ }
1386
+ async function vsOpen(inner) {
1387
+ const shown = oneEvent(inner, 'nile-after-show');
1388
+ inner.shadowRoot.querySelector('[part="combobox"]').dispatchEvent(new MouseEvent('mousedown', { bubbles: true, composed: true, button: 0 }));
1389
+ await shown;
1390
+ await aTimeout(50);
1391
+ }
1392
+ async function vsPick(el, inner, value) {
1393
+ await waitUntil(() => vsAll(inner, 'nile-option').find(o => o.value === value), `option ${value} was not rendered`);
1394
+ const option = vsAll(inner, 'nile-option').find(o => o.value === value);
1395
+ option.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, composed: true, button: 0 }));
1396
+ await vsSettle(el, inner);
1397
+ }
1398
+ async function vsToggleSelected(el, inner) {
1399
+ vsAll(inner, '.select__footer nile-checkbox')[0].click();
1400
+ await vsSettle(el, inner);
1401
+ }
1402
+ async function vsType(el, inner, text) {
1403
+ const input = vsAll(inner, '.select__search nile-input')[0].shadowRoot.querySelector('input');
1404
+ input.value = text;
1405
+ input.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
1406
+ await vsSettle(el, inner);
1407
+ }
1408
+ async function vsRemoveChip(el, inner, index = 0) {
1409
+ const tag = inner.shadowRoot.querySelectorAll('nile-tag')[index];
1410
+ const remove = tag.shadowRoot.querySelector('[part="remove-button"], nile-icon-button, button');
1411
+ (remove.shadowRoot?.querySelector('button') ?? remove).click();
1412
+ await vsSettle(el, inner);
1413
+ }
1414
+ const VS_SEARCH = 'Option 99';
1415
+ const VS_SEARCH_HITS = VS_OPTIONS.filter(o => o.label.includes(VS_SEARCH)).length;
1416
+ const vsDataValues = (inner) => inner.data.map(item => item.value);
1417
+ // Known, pre-existing noise from @lit-labs/virtualizer, unrelated to these tests: a "ResizeObserver loop" notice
1418
+ // while a list is laid out, and a detached-list error when the visible list swaps between a short and a long data
1419
+ // set (for example leaving the Selected view). The browser raises them as window errors, which would fail
1420
+ // whichever test happens to be running. Only the new virtual-scroll describes below install this filter; their
1421
+ // assertions still decide pass or fail.
1422
+ // The virtualizer-only errors are matched on message AND on a `virtualizer` frame in the stack, so the same message
1423
+ // thrown from anywhere else still fails the test. "ResizeObserver loop" is a browser notice with no stack.
1424
+ const VS_VIRTUALIZER_ERRORS = ['ChildPart` has no `parentNode`', "reading 'insertBefore'"];
1425
+ function vsIsKnownVirtualizerNoise(message, error) {
1426
+ if (typeof message !== 'string')
1427
+ return false;
1428
+ if (message.includes('ResizeObserver loop'))
1429
+ return true;
1430
+ return (VS_VIRTUALIZER_ERRORS.some(known => message.includes(known)) &&
1431
+ !!error?.stack &&
1432
+ error.stack.toLowerCase().includes('virtualizer'));
1433
+ }
1434
+ function vsIgnoreKnownVirtualizerErrors() {
1435
+ const previous = window.onerror;
1436
+ window.onerror = (message, source, lineno, colno, error) => {
1437
+ if (vsIsKnownVirtualizerNoise(message, error))
1438
+ return true;
1439
+ return previous ? previous.call(window, message, source, lineno, colno, error) : false;
1440
+ };
1441
+ return () => {
1442
+ window.onerror = previous;
1443
+ };
1444
+ }
1445
+ // Close every dropdown and let it finish hiding before its fixture goes away, so the virtualizer is not
1446
+ // still laying out a list that has already been detached. Registered per describe below, not file-wide.
1447
+ async function vsCloseDropdowns() {
1448
+ const mounted = vsMounted.splice(0);
1449
+ for (const inner of mounted) {
1450
+ if (!inner.open)
1451
+ continue;
1452
+ const hidden = oneEvent(inner, 'nile-after-hide');
1453
+ inner.open = false;
1454
+ await Promise.race([hidden, aTimeout(1500)]);
1455
+ }
1456
+ if (mounted.length) {
1457
+ await nextFrame();
1458
+ await nextFrame();
1459
+ await aTimeout(250);
1460
+ }
1461
+ document.body.querySelectorAll('.nile-virtual-select-portal-append').forEach(n => n.remove());
1462
+ }
1463
+ describe('NileSelect enableVirtualScroll without showTooltip keeps the pre-2.0.9 behaviour', () => {
1464
+ let restoreOnError;
1465
+ before(() => {
1466
+ restoreOnError = vsIgnoreKnownVirtualizerErrors();
1467
+ });
1468
+ after(() => {
1469
+ restoreOnError();
1470
+ });
1471
+ afterEach(vsCloseDropdowns);
1472
+ it('L1. a pick does not write the outer value', async () => {
1473
+ const { el, inner } = await vsMount();
1474
+ await vsOpen(inner);
1475
+ await vsPick(el, inner, 'option-1');
1476
+ expect(inner.value).to.deep.equal(['option-1']);
1477
+ expect(el.value).to.deep.equal([]);
1478
+ });
1479
+ it('L2. a normal pick, uncheck and chip removal cause no outer update', async () => {
1480
+ const { el, inner, updates, resetUpdates } = await vsMount({ value: ['option-9'] });
1481
+ await vsOpen(inner);
1482
+ resetUpdates();
1483
+ await vsPick(el, inner, 'option-1');
1484
+ await vsPick(el, inner, 'option-1');
1485
+ await vsRemoveChip(el, inner, 0);
1486
+ expect(updates()).to.equal(0);
1487
+ });
1488
+ it('L3. a parent re-render pushes the stale outer value back over the selection', async () => {
1489
+ const { el, inner } = await vsMount();
1490
+ await vsOpen(inner);
1491
+ await vsPick(el, inner, 'option-1');
1492
+ expect(inner.value).to.deep.equal(['option-1']);
1493
+ el.requestUpdate();
1494
+ await vsSettle(el, inner);
1495
+ expect(inner.value).to.deep.equal([]);
1496
+ });
1497
+ it('L4. nile-input / nile-change from the inner select are not synced (no sync listeners)', async () => {
1498
+ const { el, inner } = await vsMount({ value: ['option-1'] });
1499
+ const fire = (name, value) => inner.dispatchEvent(new CustomEvent(name, { detail: { value }, bubbles: true, composed: true }));
1500
+ fire('nile-input', ['option-2']);
1501
+ fire('nile-change', ['option-3']);
1502
+ await vsSettle(el, inner);
1503
+ expect(el.value).to.deep.equal(['option-1']);
1504
+ });
1505
+ it('L5. a direct syncValueFromVirtualSelect call does not change the outer value', async () => {
1506
+ const { el, inner } = await vsMount({ value: ['option-1'] });
1507
+ const event = new CustomEvent('nile-change', { detail: { value: ['option-2'] } });
1508
+ Object.defineProperty(event, 'currentTarget', { value: inner });
1509
+ Object.defineProperty(event, 'composedPath', { value: () => [inner] });
1510
+ el.syncValueFromVirtualSelect(event);
1511
+ await vsSettle(el, inner);
1512
+ expect(el.value).to.deep.equal(['option-1']);
1513
+ });
1514
+ it('L6. Selected stays filtered through a normal uncheck', async () => {
1515
+ const { el, inner } = await vsMount();
1516
+ await vsOpen(inner);
1517
+ await vsPick(el, inner, 'option-1');
1518
+ await vsPick(el, inner, 'option-2');
1519
+ await vsPick(el, inner, 'option-3');
1520
+ await vsToggleSelected(el, inner);
1521
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2', 'option-3']);
1522
+ await vsPick(el, inner, 'option-2');
1523
+ expect(inner.showSelected).to.be.true;
1524
+ expect(inner.value).to.deep.equal(['option-1', 'option-3']);
1525
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2', 'option-3']);
1526
+ });
1527
+ it('L7. search stays filtered through a pick and an unpick', async () => {
1528
+ const { el, inner } = await vsMount({ search: true });
1529
+ await vsOpen(inner);
1530
+ await vsType(el, inner, VS_SEARCH);
1531
+ expect(inner.data.length).to.equal(VS_SEARCH_HITS);
1532
+ await vsPick(el, inner, 'option-99');
1533
+ expect(inner.data.length).to.equal(VS_SEARCH_HITS);
1534
+ expect(inner.searchValue).to.equal(VS_SEARCH);
1535
+ await vsPick(el, inner, 'option-99');
1536
+ expect(inner.data.length).to.equal(VS_SEARCH_HITS);
1537
+ expect(inner.value).to.deep.equal([]);
1538
+ });
1539
+ it('L9. the wrapper pushes maxOptionsVisible to the inner select (pre-2.0.9 binding)', async () => {
1540
+ const { el, inner } = await vsMount({ value: ['option-1'] });
1541
+ const writes = [];
1542
+ const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(inner), 'maxOptionsVisible');
1543
+ Object.defineProperty(inner, 'maxOptionsVisible', {
1544
+ configurable: true,
1545
+ get() {
1546
+ return descriptor.get.call(this);
1547
+ },
1548
+ set(value) {
1549
+ writes.push(value);
1550
+ descriptor.set.call(this, value);
1551
+ },
1552
+ });
1553
+ el.maxOptionsVisible = 5;
1554
+ await vsSettle(el, inner);
1555
+ expect(writes).to.include(5);
1556
+ });
1557
+ it('L10. the untouched default maxOptionsVisible is not pushed, so the inner select is not pinned as explicit', async () => {
1558
+ const { inner } = await vsMount();
1559
+ expect(inner.maxOptionsVisibleExplicit).to.be.false;
1560
+ });
1561
+ it('L8. data is re-applied on every wrapper render (plain binding, pre-2.0.9)', async () => {
1562
+ const { el, inner } = await vsMount({ value: ['option-1'] });
1563
+ await vsOpen(inner);
1564
+ // After opening, the inner select holds its own copy of the list.
1565
+ expect(inner.data).to.not.equal(el.data);
1566
+ el.requestUpdate();
1567
+ await vsSettle(el, inner);
1568
+ expect(inner.data).to.equal(el.data);
1569
+ });
1570
+ });
1571
+ describe('NileSelect enableVirtualScroll with showTooltip: guarded data and external value updates', () => {
1572
+ let restoreOnError;
1573
+ before(() => {
1574
+ restoreOnError = vsIgnoreKnownVirtualizerErrors();
1575
+ });
1576
+ after(() => {
1577
+ restoreOnError();
1578
+ });
1579
+ afterEach(vsCloseDropdowns);
1580
+ it('T1. Selected + uncheck stays filtered', async () => {
1581
+ const { el, inner } = await vsMount({ showTooltip: true });
1582
+ await vsOpen(inner);
1583
+ await vsPick(el, inner, 'option-1');
1584
+ await vsPick(el, inner, 'option-2');
1585
+ await vsPick(el, inner, 'option-3');
1586
+ await vsToggleSelected(el, inner);
1587
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2', 'option-3']);
1588
+ await vsPick(el, inner, 'option-2');
1589
+ expect(inner.showSelected).to.be.true;
1590
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2', 'option-3']);
1591
+ expect(el.value).to.deep.equal(['option-1', 'option-3']);
1592
+ });
1593
+ it('T2. search + pick/unpick stays filtered', async () => {
1594
+ const { el, inner } = await vsMount({ showTooltip: true, search: true });
1595
+ await vsOpen(inner);
1596
+ await vsType(el, inner, VS_SEARCH);
1597
+ expect(inner.data.length).to.equal(VS_SEARCH_HITS);
1598
+ await vsPick(el, inner, 'option-99');
1599
+ expect(inner.data.length).to.equal(VS_SEARCH_HITS);
1600
+ expect(inner.searchValue).to.equal(VS_SEARCH);
1601
+ expect(el.value).to.deep.equal(['option-99']);
1602
+ await vsPick(el, inner, 'option-99');
1603
+ expect(inner.data.length).to.equal(VS_SEARCH_HITS);
1604
+ expect(el.value).to.deep.equal([]);
1605
+ });
1606
+ it('T3. chip removal while Selected stays filtered', async () => {
1607
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2', 'option-3'] });
1608
+ await vsOpen(inner);
1609
+ await vsToggleSelected(el, inner);
1610
+ expect(inner.data.length).to.equal(3);
1611
+ await vsRemoveChip(el, inner, 0);
1612
+ expect(inner.showSelected).to.be.true;
1613
+ expect(inner.data.length).to.equal(3);
1614
+ expect(el.value).to.deep.equal(['option-2', 'option-3']);
1615
+ });
1616
+ it('T4. portal: Selected + uncheck stays filtered', async () => {
1617
+ const { el, inner } = await vsMount({ showTooltip: true, portal: true });
1618
+ await vsOpen(inner);
1619
+ await waitUntil(() => document.body.querySelector('.nile-virtual-select-portal-append #listbox'), 'listbox never portalled');
1620
+ await vsPick(el, inner, 'option-1');
1621
+ await vsPick(el, inner, 'option-2');
1622
+ await vsToggleSelected(el, inner);
1623
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2']);
1624
+ await vsPick(el, inner, 'option-2');
1625
+ expect(inner.showSelected).to.be.true;
1626
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2']);
1627
+ expect(el.value).to.deep.equal(['option-1']);
1628
+ });
1629
+ it('T5. picking, removing a chip and clearing sync the outer value; nile-change listeners see it', async () => {
1630
+ const { el, inner } = await vsMount({ showTooltip: true });
1631
+ const seen = [];
1632
+ el.addEventListener('nile-change', () => seen.push(el.value));
1633
+ await vsOpen(inner);
1634
+ await vsPick(el, inner, 'option-1');
1635
+ await vsPick(el, inner, 'option-2');
1636
+ expect(el.value).to.deep.equal(['option-1', 'option-2']);
1637
+ expect(seen[0]).to.deep.equal(['option-1']);
1638
+ await vsRemoveChip(el, inner, 0);
1639
+ expect(el.value).to.deep.equal(['option-2']);
1640
+ vsAll(inner, '.select__clear')[0].click();
1641
+ await vsSettle(el, inner);
1642
+ expect(el.value).to.deep.equal([]);
1643
+ });
1644
+ it('T6. an external value replace while Selected recomputes the list', async () => {
1645
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2'] });
1646
+ await vsOpen(inner);
1647
+ await vsToggleSelected(el, inner);
1648
+ el.value = ['option-5'];
1649
+ await vsSettle(el, inner);
1650
+ expect(inner.showSelected).to.be.true;
1651
+ expect(vsDataValues(inner)).to.deep.equal(['option-5']);
1652
+ });
1653
+ it('T7. an external value that adds an item while Selected shows the new item', async () => {
1654
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2'] });
1655
+ await vsOpen(inner);
1656
+ await vsToggleSelected(el, inner);
1657
+ el.value = ['option-1', 'option-2', 'option-7'];
1658
+ await vsSettle(el, inner);
1659
+ expect(vsDataValues(inner)).to.deep.equal(['option-1', 'option-2', 'option-7']);
1660
+ });
1661
+ it('T8. an external value that removes an item while Selected drops it from the list', async () => {
1662
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2'] });
1663
+ await vsOpen(inner);
1664
+ await vsToggleSelected(el, inner);
1665
+ el.value = ['option-1'];
1666
+ await vsSettle(el, inner);
1667
+ expect(vsDataValues(inner)).to.deep.equal(['option-1']);
1668
+ });
1669
+ it('T9. an external empty value leaves the Selected view', async () => {
1670
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2'] });
1671
+ await vsOpen(inner);
1672
+ await vsToggleSelected(el, inner);
1673
+ el.value = [];
1674
+ await vsSettle(el, inner);
1675
+ expect(inner.showSelected).to.be.false;
1676
+ expect(inner.data.length).to.equal(VS_OPTIONS.length);
1677
+ });
1678
+ it('T10. a normal pick after an external value update still keeps the item listed', async () => {
1679
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2'] });
1680
+ await vsOpen(inner);
1681
+ await vsToggleSelected(el, inner);
1682
+ el.value = ['option-5', 'option-6'];
1683
+ await vsSettle(el, inner);
1684
+ await vsPick(el, inner, 'option-5');
1685
+ expect(inner.value).to.deep.equal(['option-6']);
1686
+ expect(el.value).to.deep.equal(['option-6']);
1687
+ expect(inner.showSelected).to.be.true;
1688
+ expect(vsDataValues(inner)).to.deep.equal(['option-5', 'option-6']);
1689
+ });
1690
+ it('T11. a normal pick does not re-send the data array', async () => {
1691
+ const { el, inner } = await vsMount({ showTooltip: true, value: ['option-1', 'option-2'] });
1692
+ await vsOpen(inner);
1693
+ await vsToggleSelected(el, inner);
1694
+ const before = inner.data;
1695
+ await vsPick(el, inner, 'option-2');
1696
+ expect(inner.data).to.equal(before);
1697
+ });
1698
+ it('T12. turning showTooltip on at runtime keeps the selection', async () => {
1699
+ const { el, inner } = await vsMount({ showTooltip: false });
1700
+ await vsOpen(inner);
1701
+ await vsPick(el, inner, 'option-1');
1702
+ await vsPick(el, inner, 'option-2');
1703
+ expect(el.value).to.deep.equal([]);
1704
+ expect(inner.value).to.deep.equal(['option-1', 'option-2']);
1705
+ el.showTooltip = true;
1706
+ await vsSettle(el, inner);
1707
+ expect(el.value).to.deep.equal(['option-1', 'option-2']);
1708
+ expect(inner.value).to.deep.equal(['option-1', 'option-2']);
1709
+ });
1710
+ it('T15. turning showTooltip on at runtime engages the fitted chip row', async () => {
1711
+ const { el, inner } = await vsMount({
1712
+ showTooltip: false,
1713
+ value: ['option-1', 'option-2', 'option-3', 'option-4', 'option-5'],
1714
+ });
1715
+ const fitted = () => !!inner.shadowRoot.querySelector('.select__tags--fitted');
1716
+ expect(fitted()).to.be.false;
1717
+ el.showTooltip = true;
1718
+ await vsSettle(el, inner);
1719
+ await waitUntil(fitted, 'the fitted chip row never engaged');
1720
+ expect(el.value).to.deep.equal(['option-1', 'option-2', 'option-3', 'option-4', 'option-5']);
1721
+ });
1722
+ it('T16. changing showTooltip and value in the same update keeps the consumer value', async () => {
1723
+ const { el, inner } = await vsMount({ showTooltip: false });
1724
+ await vsOpen(inner);
1725
+ await vsPick(el, inner, 'option-1');
1726
+ expect(inner.value).to.deep.equal(['option-1']);
1727
+ expect(el.value).to.deep.equal([]);
1728
+ el.value = ['option-7'];
1729
+ el.showTooltip = true;
1730
+ await vsSettle(el, inner);
1731
+ expect(el.value).to.deep.equal(['option-7']);
1732
+ expect(inner.value).to.deep.equal(['option-7']);
1733
+ });
1734
+ it('T13. assigning a new data array propagates', async () => {
1735
+ const { el, inner } = await vsMount({ showTooltip: true });
1736
+ await vsOpen(inner);
1737
+ el.data = [...VS_OPTIONS.slice(0, 10), { value: 'extra', label: 'Extra' }];
1738
+ await vsSettle(el, inner);
1739
+ expect(inner.data.length).to.equal(11);
1740
+ expect(vsDataValues(inner)).to.include('extra');
1741
+ });
1742
+ it('T14. mutating data in place (data.push) is not propagated; assign a new array instead', async () => {
1743
+ const data = VS_OPTIONS.slice(0, 20);
1744
+ const { el, inner } = await vsMount({ showTooltip: true, data });
1745
+ await vsOpen(inner);
1746
+ data.push({ value: 'extra', label: 'Extra' });
1747
+ el.requestUpdate();
1748
+ await vsSettle(el, inner);
1749
+ expect(inner.data.length).to.equal(20);
1750
+ expect(vsDataValues(inner)).to.not.include('extra');
1751
+ });
1752
+ });
1328
1753
  //# sourceMappingURL=nile-select.test.js.map