rich-input 1.2.1 → 1.2.2
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/components/rich-input.js +44 -5
- package/package.json +1 -1
package/components/rich-input.js
CHANGED
|
@@ -283,6 +283,7 @@ TEMPLATE.innerHTML = `
|
|
|
283
283
|
aria-autocomplete="list"
|
|
284
284
|
aria-expanded="false"
|
|
285
285
|
aria-haspopup="listbox"
|
|
286
|
+
aria-controls="ri-listbox"
|
|
286
287
|
/>
|
|
287
288
|
<button part="clear-button" type="button" class="clear-button" aria-label="Clear search query" hidden>
|
|
288
289
|
<svg viewBox="0 0 20 20" fill="currentColor">
|
|
@@ -296,13 +297,17 @@ TEMPLATE.innerHTML = `
|
|
|
296
297
|
part="popover suggestions"
|
|
297
298
|
class="popover"
|
|
298
299
|
popover="manual"
|
|
299
|
-
role="listbox"
|
|
300
|
-
aria-label="Search suggestions"
|
|
301
300
|
>
|
|
302
301
|
<div part="suggestions-header" class="popover-header">
|
|
303
|
-
<span part="suggestions-title" class="popover-title">Suggestions</span>
|
|
302
|
+
<span id="ri-listbox-label" part="suggestions-title" class="popover-title">Suggestions</span>
|
|
304
303
|
</div>
|
|
305
|
-
<ul
|
|
304
|
+
<ul
|
|
305
|
+
id="ri-listbox"
|
|
306
|
+
part="suggestions-list"
|
|
307
|
+
class="suggestions-list"
|
|
308
|
+
role="listbox"
|
|
309
|
+
aria-labelledby="ri-listbox-label"
|
|
310
|
+
></ul>
|
|
306
311
|
</div>
|
|
307
312
|
|
|
308
313
|
<slot style="display: none;"></slot>
|
|
@@ -361,6 +366,8 @@ export class RichInput extends HTMLElement {
|
|
|
361
366
|
'autofocus',
|
|
362
367
|
'required',
|
|
363
368
|
'highlight-quotes',
|
|
369
|
+
'aria-label',
|
|
370
|
+
'aria-labelledby',
|
|
364
371
|
];
|
|
365
372
|
}
|
|
366
373
|
|
|
@@ -383,6 +390,7 @@ export class RichInput extends HTMLElement {
|
|
|
383
390
|
editableDiv.setAttribute('aria-autocomplete', 'list');
|
|
384
391
|
editableDiv.setAttribute('aria-expanded', 'false');
|
|
385
392
|
editableDiv.setAttribute('aria-haspopup', 'listbox');
|
|
393
|
+
editableDiv.setAttribute('aria-controls', 'ri-listbox');
|
|
386
394
|
editableDiv.setAttribute('spellcheck', 'false');
|
|
387
395
|
editableDiv.setAttribute('tabindex', '0');
|
|
388
396
|
existingInput.replaceWith(editableDiv);
|
|
@@ -416,6 +424,7 @@ export class RichInput extends HTMLElement {
|
|
|
416
424
|
this._onClick = this._onClick.bind(this);
|
|
417
425
|
this._onSelectionChange = this._onSelectionChange.bind(this);
|
|
418
426
|
this._onClearClick = this._onClearClick.bind(this);
|
|
427
|
+
this._onClearMouseDown = (e) => e.preventDefault();
|
|
419
428
|
this._onSlotChange = this._onSlotChange.bind(this);
|
|
420
429
|
this._onGlobalClick = this._onGlobalClick.bind(this);
|
|
421
430
|
this._onGlobalResizeOrScroll = this._onGlobalResizeOrScroll.bind(this);
|
|
@@ -453,6 +462,7 @@ export class RichInput extends HTMLElement {
|
|
|
453
462
|
this._input.addEventListener('focus', this._onFocus);
|
|
454
463
|
this._input.addEventListener('blur', this._onBlur);
|
|
455
464
|
this._input.addEventListener('click', this._onClick);
|
|
465
|
+
this._clearBtn.addEventListener('mousedown', this._onClearMouseDown);
|
|
456
466
|
this._clearBtn.addEventListener('click', this._onClearClick);
|
|
457
467
|
|
|
458
468
|
// Global events
|
|
@@ -475,6 +485,7 @@ export class RichInput extends HTMLElement {
|
|
|
475
485
|
this._internals.setFormValue(this._input.value);
|
|
476
486
|
}
|
|
477
487
|
|
|
488
|
+
this._syncAccessibleName();
|
|
478
489
|
this._updateClearButton();
|
|
479
490
|
this.updateHighlights();
|
|
480
491
|
}
|
|
@@ -494,6 +505,7 @@ export class RichInput extends HTMLElement {
|
|
|
494
505
|
this._input.removeEventListener('focus', this._onFocus);
|
|
495
506
|
this._input.removeEventListener('blur', this._onBlur);
|
|
496
507
|
this._input.removeEventListener('click', this._onClick);
|
|
508
|
+
this._clearBtn.removeEventListener('mousedown', this._onClearMouseDown);
|
|
497
509
|
this._clearBtn.removeEventListener('click', this._onClearClick);
|
|
498
510
|
|
|
499
511
|
document.removeEventListener('click', this._onGlobalClick);
|
|
@@ -518,6 +530,9 @@ export class RichInput extends HTMLElement {
|
|
|
518
530
|
}
|
|
519
531
|
} else if (name === 'placeholder') {
|
|
520
532
|
this._input.placeholder = newValue || '';
|
|
533
|
+
this._syncAccessibleName();
|
|
534
|
+
} else if (name === 'aria-label' || name === 'aria-labelledby') {
|
|
535
|
+
this._syncAccessibleName();
|
|
521
536
|
} else if (name === 'disabled') {
|
|
522
537
|
this._input.disabled = newValue !== null;
|
|
523
538
|
} else if (name === 'readonly') {
|
|
@@ -535,6 +550,25 @@ export class RichInput extends HTMLElement {
|
|
|
535
550
|
}
|
|
536
551
|
}
|
|
537
552
|
|
|
553
|
+
_syncAccessibleName() {
|
|
554
|
+
if (!this._input) return;
|
|
555
|
+
if (this.hasAttribute('aria-label')) {
|
|
556
|
+
this._input.setAttribute('aria-label', this.getAttribute('aria-label'));
|
|
557
|
+
} else if (this._internals?.labels?.length > 0) {
|
|
558
|
+
const labelText = Array.from(this._internals.labels)
|
|
559
|
+
.map((l) => l.textContent.trim())
|
|
560
|
+
.filter(Boolean)
|
|
561
|
+
.join(' ');
|
|
562
|
+
if (labelText) {
|
|
563
|
+
this._input.setAttribute('aria-label', labelText);
|
|
564
|
+
}
|
|
565
|
+
} else if (this.hasAttribute('placeholder')) {
|
|
566
|
+
this._input.setAttribute('aria-label', this.getAttribute('placeholder'));
|
|
567
|
+
} else {
|
|
568
|
+
this._input.setAttribute('aria-label', 'Search');
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
538
572
|
// --- Form Associated Lifecycle ---
|
|
539
573
|
formResetCallback() {
|
|
540
574
|
this.value = this.getAttribute('value') || '';
|
|
@@ -949,6 +983,7 @@ export class RichInput extends HTMLElement {
|
|
|
949
983
|
this.updateHighlights();
|
|
950
984
|
// Delay closing so click events on popover items can fire
|
|
951
985
|
setTimeout(() => {
|
|
986
|
+
if (this._isFocused) return;
|
|
952
987
|
this.hideSuggestions();
|
|
953
988
|
this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
|
|
954
989
|
}, 150);
|
|
@@ -1079,9 +1114,9 @@ export class RichInput extends HTMLElement {
|
|
|
1079
1114
|
if (!this._isPopoverOpen()) {
|
|
1080
1115
|
try {
|
|
1081
1116
|
this._popover.showPopover();
|
|
1082
|
-
this._input.setAttribute('aria-expanded', 'true');
|
|
1083
1117
|
} catch (e) {}
|
|
1084
1118
|
}
|
|
1119
|
+
this._input.setAttribute('aria-expanded', 'true');
|
|
1085
1120
|
|
|
1086
1121
|
// Position popover at the start of the current OpaqueRange (or via mirror-div fallback when OpaqueRange is unsupported)
|
|
1087
1122
|
const currentRange = this._getCurrentOpaqueRange();
|
|
@@ -1190,10 +1225,14 @@ export class RichInput extends HTMLElement {
|
|
|
1190
1225
|
const isAct = i === this._selectedIndex;
|
|
1191
1226
|
items[i].classList.toggle('active', isAct);
|
|
1192
1227
|
items[i].setAttribute('aria-selected', isAct ? 'true' : 'false');
|
|
1228
|
+
items[i].setAttribute('part', `suggestion-item${isAct ? ' suggestion-item-active' : ''}`);
|
|
1193
1229
|
if (isAct) {
|
|
1194
1230
|
this._input.setAttribute('aria-activedescendant', items[i].id);
|
|
1195
1231
|
}
|
|
1196
1232
|
}
|
|
1233
|
+
if (this._selectedIndex === -1) {
|
|
1234
|
+
this._input.removeAttribute('aria-activedescendant');
|
|
1235
|
+
}
|
|
1197
1236
|
}
|
|
1198
1237
|
|
|
1199
1238
|
_applySelectedSuggestion() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rich-input",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "A rich input field with keyword-based autocomplete and in-input highlighting powered by <datalist>, OpaqueRange, and the Custom Highlight API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|