@dile/ui 3.5.0 → 3.5.1

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.
@@ -275,6 +275,39 @@ describe('dile-select-ajax-overlay', () => {
275
275
  expect(el.value).toBeUndefined();
276
276
  expect(el.shadowRoot.getElementById('search')).toBeTruthy();
277
277
  });
278
+
279
+ it('clear() does not re-select the same item (regression: infinite add loop under addOnSelect)', async () => {
280
+ // Regression test: unlike onClearSelected() (triggered by the user's own "x" click), the
281
+ // public clear() API left `data`/`keyword` untouched. Flipping isSelected back to false
282
+ // remounts a brand new nested dile-select-overlay, whose firstUpdated() syncs its value to
283
+ // whatever the native <select> currently holds. With no placeholder option and the stale
284
+ // data still in place, that was the just-cleared item's own option — auto-selecting it and
285
+ // re-firing element-changed for the same value, which under dile-many-relation's
286
+ // addOnSelect re-added the same item forever until the API started rate-limiting.
287
+ mockFetch([{ id: 1, name: 'Spain' }]);
288
+ const el = await renderSelectAjaxOverlay(`
289
+ <dile-select-ajax-overlay endpoint="/api/countries" idProperty="id" displayProperty="name" delay="10"></dile-select-ajax-overlay>
290
+ `);
291
+
292
+ await typeKeyword(el, 'sp');
293
+ await selectOption(el, 0);
294
+ expect(el.value).toBe('1');
295
+
296
+ const changedValues = [];
297
+ el.addEventListener('element-changed', (e) => { changedValues.push(e.detail.value); });
298
+
299
+ el.clear();
300
+ await el.updateComplete;
301
+ await wait(20);
302
+ await el.updateComplete;
303
+
304
+ expect(el.isSelected).toBe(false);
305
+ expect(el.value).toBeUndefined();
306
+ expect(el.data).toEqual([]);
307
+ // Exactly one event: the clear itself. A second one carrying the old value ('1') back
308
+ // would mean the freshly remounted select auto-picked the stale option again.
309
+ expect(changedValues).toEqual([undefined]);
310
+ });
278
311
  });
279
312
 
280
313
  describe('Form Association', () => {
@@ -499,6 +499,16 @@ export class DileSelectAjaxOverlay extends DileEmmitChange(LitElement) {
499
499
  this.isSelected = false;
500
500
  this.value = undefined;
501
501
  this.selectedText = '';
502
+ // isSelected flipping back to false remounts a brand new nested dile-select-overlay (the
503
+ // read-only and search branches are mutually exclusive templates). Its firstUpdated() syncs
504
+ // its value to the native <select>'s current value, and this component's <select> has no
505
+ // placeholder option — so leftover data/keyword from the previous search would leave a real
506
+ // option in place, get auto-picked as the new instance's value, and re-fire element-changed
507
+ // for the very same item that was just cleared (an infinite loop under addOnSelect).
508
+ if (!this.static) {
509
+ this.keyword = '';
510
+ this.data = [];
511
+ }
502
512
  }
503
513
 
504
514
  set(value) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/ui",
3
- "version": "3.5.0",
3
+ "version": "3.5.1",
4
4
  "description": "UI Core components from dile-components.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -28,5 +28,5 @@
28
28
  "publishConfig": {
29
29
  "access": "public"
30
30
  },
31
- "gitHead": "817f0dfc3c345957ae7a63c113e22aa0f80a773f"
31
+ "gitHead": "7bcf203fb23acc24867e9f3df4f3ca2367eabd97"
32
32
  }