@gjsify/adwaita-web 0.16.2 → 0.16.4
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.
- package/package.json +5 -5
- package/src/adw-drop-down.spec.ts +14 -9
- package/src/elements/adw-drop-down.ts +19 -12
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/adwaita-web",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "Adwaita/Libadwaita web components for browser targets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"@codemirror/language": "^6.12.4",
|
|
42
42
|
"@codemirror/state": "^6.7.0",
|
|
43
43
|
"@codemirror/view": "^6.43.4",
|
|
44
|
-
"@gjsify/adwaita-fonts": "^0.16.
|
|
45
|
-
"@gjsify/adwaita-icons": "^0.16.
|
|
44
|
+
"@gjsify/adwaita-fonts": "^0.16.4",
|
|
45
|
+
"@gjsify/adwaita-icons": "^0.16.4",
|
|
46
46
|
"@lezer/highlight": "^1.2.3"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@gjsify/cli": "^0.16.
|
|
50
|
-
"@gjsify/unit": "^0.16.
|
|
49
|
+
"@gjsify/cli": "^0.16.4",
|
|
50
|
+
"@gjsify/unit": "^0.16.4",
|
|
51
51
|
"sass": "^1.101.0",
|
|
52
52
|
"typescript": "^6.0.3"
|
|
53
53
|
},
|
|
@@ -102,21 +102,26 @@ export const AdwDropDownTest = async () => {
|
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
await describe('adw-drop-down notify-on-change', async () => {
|
|
105
|
-
await it('fires notify::selected
|
|
105
|
+
await it('a programmatic set fires notify::selected but NOT change (DOM <select> semantics)', async () => {
|
|
106
106
|
const dd = makeDropDown();
|
|
107
107
|
dd.options = ['a', 'b', 'c'];
|
|
108
108
|
let notifyCount = 0;
|
|
109
|
-
let
|
|
109
|
+
let changeCount = 0;
|
|
110
110
|
dd.addEventListener('notify::selected', () => notifyCount++);
|
|
111
|
-
dd.addEventListener('change', (
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
dd.selected = 2;
|
|
115
|
-
expect(notifyCount).toBe(1);
|
|
116
|
-
expect(lastChange).toStrictEqual({ index: 2, value: 'c', label: 'c' });
|
|
117
|
-
// Re-selecting the same index must NOT fire again.
|
|
111
|
+
dd.addEventListener('change', () => changeCount++);
|
|
112
|
+
// Programmatic `.selected`: notify::selected fires (GObject property-notify), but the
|
|
113
|
+
// user-facing DOM `change` must NOT — native `select.value = x` fires no `change` either.
|
|
118
114
|
dd.selected = 2;
|
|
119
115
|
expect(notifyCount).toBe(1);
|
|
116
|
+
expect(changeCount).toBe(0);
|
|
117
|
+
// Programmatic `.selectedValue` is likewise silent on `change`.
|
|
118
|
+
dd.selectedValue = 'a';
|
|
119
|
+
expect(notifyCount).toBe(2);
|
|
120
|
+
expect(changeCount).toBe(0);
|
|
121
|
+
// Re-selecting the same value fires neither event again.
|
|
122
|
+
dd.selectedValue = 'a';
|
|
123
|
+
expect(notifyCount).toBe(2);
|
|
124
|
+
expect(changeCount).toBe(0);
|
|
120
125
|
dd.remove();
|
|
121
126
|
});
|
|
122
127
|
|
|
@@ -190,7 +190,7 @@ export class AdwDropDown extends HTMLElement {
|
|
|
190
190
|
this._renderAll();
|
|
191
191
|
} else if (name === 'selected') {
|
|
192
192
|
const index = Number.parseInt(value ?? '', 10);
|
|
193
|
-
if (!Number.isNaN(index)) this._selectIndex(index);
|
|
193
|
+
if (!Number.isNaN(index)) this._selectIndex(index, { fromAttr: true });
|
|
194
194
|
} else if (name === 'enable-search') {
|
|
195
195
|
this._renderPopover();
|
|
196
196
|
} else if (name === 'disabled') {
|
|
@@ -212,26 +212,33 @@ export class AdwDropDown extends HTMLElement {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
private _selectIndex(index: number, fromAttr =
|
|
215
|
+
private _selectIndex(index: number, opts: { fromAttr?: boolean; fromUser?: boolean } = {}): void {
|
|
216
216
|
if (!Number.isFinite(index) || index < 0 || index >= this._options.length) return;
|
|
217
217
|
const changed = index !== this._selected;
|
|
218
218
|
this._selected = index;
|
|
219
219
|
this._updateLabel();
|
|
220
220
|
this._updateSelectedStates();
|
|
221
221
|
// Keep the attribute in sync without re-entering the guarded callback.
|
|
222
|
-
if (!fromAttr && this.getAttribute('selected') !== String(index)) {
|
|
222
|
+
if (!opts.fromAttr && this.getAttribute('selected') !== String(index)) {
|
|
223
223
|
this.setAttribute('selected', String(index));
|
|
224
224
|
}
|
|
225
|
-
// Notify only on an actual change (GObject notify semantics).
|
|
226
225
|
if (changed) {
|
|
227
226
|
const option = this._options[index];
|
|
227
|
+
// `notify::selected` mirrors GObject property-notify: it fires on EVERY change,
|
|
228
|
+
// programmatic included.
|
|
228
229
|
this.dispatchEvent(new CustomEvent('notify::selected', { bubbles: true, detail: { selected: index } }));
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
230
|
+
// `change` mirrors the DOM <select> contract: it fires ONLY on a user-initiated change.
|
|
231
|
+
// A programmatic `.selected`/`.selectedValue`/`selected`-attribute assignment stays silent
|
|
232
|
+
// (just as native `select.value = x` fires no `change`), so consumers can set the value
|
|
233
|
+
// without guarding against a spurious user-style event.
|
|
234
|
+
if (opts.fromUser) {
|
|
235
|
+
this.dispatchEvent(
|
|
236
|
+
new CustomEvent('change', {
|
|
237
|
+
bubbles: true,
|
|
238
|
+
detail: { index, value: option?.value ?? '', label: option?.label ?? '' },
|
|
239
|
+
}),
|
|
240
|
+
);
|
|
241
|
+
}
|
|
235
242
|
}
|
|
236
243
|
}
|
|
237
244
|
|
|
@@ -302,7 +309,7 @@ export class AdwDropDown extends HTMLElement {
|
|
|
302
309
|
const match = this._options.findIndex((o) => o.label.toLowerCase().startsWith(this._typeAheadBuffer));
|
|
303
310
|
if (match < 0) return;
|
|
304
311
|
if (this._active) this._itemButtons[match]?.focus();
|
|
305
|
-
else this._selectIndex(match);
|
|
312
|
+
else this._selectIndex(match, { fromUser: true });
|
|
306
313
|
}
|
|
307
314
|
|
|
308
315
|
/** Filter the visible items by a search query (case-insensitive substring). */
|
|
@@ -378,7 +385,7 @@ export class AdwDropDown extends HTMLElement {
|
|
|
378
385
|
|
|
379
386
|
item.append(label, check);
|
|
380
387
|
item.addEventListener('click', () => {
|
|
381
|
-
this._selectIndex(index);
|
|
388
|
+
this._selectIndex(index, { fromUser: true });
|
|
382
389
|
this._setActive(false);
|
|
383
390
|
this._buttonEl.focus();
|
|
384
391
|
});
|