rich-input 1.2.1 → 1.3.0

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/README.md CHANGED
@@ -45,7 +45,8 @@ The visual below illustrates the internal Shadow DOM elements, exposed CSS Shado
45
45
  - `::part(suggestions-header)`: The header bar at the top of the suggestions popover.
46
46
  - `::part(suggestions-list)`: The `<ul>` container holding autocomplete suggestion items.
47
47
  - `::part(suggestion-item)`: Each suggestion `<li>` row.
48
- - `::part(suggestion-item-active)`: The currently selected / keyboard-focused suggestion row.
48
+ - `::part(suggestion-item-active)`: The currently focused / hovered suggestion row.
49
+ - `::part(suggestion-item-selected)`: The suggestion row matching the value currently echoed in the input.
49
50
  - `::part(suggestion-image)`: The circular logo, icon, or avatar image prepended to rich suggestions.
50
51
  - `::part(suggestion-keyword)`: The keyword label text inside a keyword suggestion.
51
52
  - `::part(suggestion-value)`: The value label text inside a value suggestion.
@@ -82,6 +83,7 @@ Nest `<datalist>` elements inside `<rich-input>` to configure keywords and autoc
82
83
  <rich-input placeholder="Search music catalog...">
83
84
  <datalist id="label" label="Record Label">
84
85
  <option value="Defected"></option>
86
+ <option value="House"></option>
85
87
  <option value="Keinemusik"></option>
86
88
  <option value="Kranky"></option>
87
89
  <option value="Madhouse Records"></option>
@@ -134,6 +136,10 @@ Datalists can be added, updated, or removed dynamically at runtime; `<rich-input
134
136
  <img src="assets/defected.jpg" height="50" width="50" alt="Defected Logo">
135
137
  Defected
136
138
  </option>
139
+ <option value="House">
140
+ <img src="assets/house.jpg" height="50" width="50" alt="House Logo">
141
+ House
142
+ </option>
137
143
  <option value="Keinemusik">
138
144
  <img src="assets/keinemusik.jpg" height="50" width="50" alt="Keinemusik Logo">
139
145
  Keinemusik
@@ -345,7 +351,8 @@ rich-input::part(suggestion-item-active) {
345
351
  | `::part(suggestions-header)` | The header bar at the top of the popover |
346
352
  | `::part(suggestions-list)` | The `<ul>` list element |
347
353
  | `::part(suggestion-item)` | Each suggestion `<li>` item |
348
- | `::part(suggestion-item-active)` | The currently selected / hovered suggestion item |
354
+ | `::part(suggestion-item-active)` | The currently focused / hovered suggestion item |
355
+ | `::part(suggestion-item-selected)` | The suggestion item matching the value currently echoed in the input |
349
356
  | `::part(suggestion-keyword)` | Keyword name element in suggestion items |
350
357
  | `::part(suggestion-value)` | Value element in suggestion items |
351
358
  | `::part(suggestion-content)` | The content container inside each suggestion item |
@@ -10,6 +10,7 @@
10
10
  --text-muted: #64748b;
11
11
  --text-hint: #94a3b8;
12
12
  --popover-bg: #ffffff;
13
+ --selected-item-bg: rgba(219, 39, 119, 0.07);
13
14
  --active-item-bg: #eff6ff;
14
15
 
15
16
  /* Annotation Colors */
@@ -22,6 +23,7 @@
22
23
  --c-popover: #9333ea; /* Purple */
23
24
  --c-header: #475569; /* Slate */
24
25
  --c-list: #7c3aed; /* Violet */
26
+ --c-selected: #db2777; /* Pink / Rose */
25
27
  --c-item: #16a34a; /* Green */
26
28
  --c-active: #0284c7; /* Sky */
27
29
  --c-image: #ea580c; /* Orange */
@@ -40,6 +42,7 @@
40
42
  --text-muted: #94a3b8;
41
43
  --text-hint: #64748b;
42
44
  --popover-bg: #1e293b;
45
+ --selected-item-bg: rgba(244, 114, 182, 0.12);
43
46
  --active-item-bg: #1e3a5f;
44
47
 
45
48
  /* Annotation Colors (Brighter for Dark Mode) */
@@ -52,6 +55,7 @@
52
55
  --c-popover: #c084fc;
53
56
  --c-header: #94a3b8;
54
57
  --c-list: #a78bfa;
58
+ --c-selected: #f472b6;
55
59
  --c-item: #4ade80;
56
60
  --c-active: #38bdf8;
57
61
  --c-image: #fb923c;
@@ -180,6 +184,7 @@
180
184
  :scope:has(.lbl-popover:hover) .target-popover,
181
185
  :scope:has(.lbl-header:hover) .target-header,
182
186
  :scope:has(.lbl-list:hover) .target-list,
187
+ :scope:has(.lbl-selected:hover) .target-selected,
183
188
  :scope:has(.lbl-item:hover) .target-item,
184
189
  :scope:has(.lbl-active:hover) .target-active,
185
190
  :scope:has(.lbl-image:hover) .target-image,
@@ -193,7 +198,7 @@
193
198
  }
194
199
 
195
200
  /* Contained parts: when hovering a container, contained parts in the preview also remain at opacity 1 */
196
- /* Control contains icon, input (including highlight hou), and clear button */
201
+ /* Control contains icon, input (including highlight house), and clear button */
197
202
  :scope:has(.lbl-control:hover) #component-preview .target-icon,
198
203
  :scope:has(.lbl-control:hover) #component-preview .target-input,
199
204
  :scope:has(.lbl-control:hover) #component-preview .target-hl-val,
@@ -201,19 +206,21 @@
201
206
  opacity: 1 !important;
202
207
  }
203
208
 
204
- /* Input contains highlight label (hou text and background pill) */
209
+ /* Input contains highlight label (house text and background pill) */
205
210
  :scope:has(.lbl-input:hover) #component-preview .target-hl-val {
206
211
  opacity: 1 !important;
207
212
  }
208
213
 
209
214
  /* Popover contains header, list, and all suggestion items */
210
215
  :scope:has(.lbl-popover:hover) #component-preview .target-header,
216
+ :scope:has(.lbl-popover:hover) #component-preview .target-selected,
211
217
  :scope:has(.lbl-popover:hover) #component-preview .target-item,
212
218
  :scope:has(.lbl-popover:hover) #component-preview .target-active {
213
219
  opacity: 1 !important;
214
220
  }
215
221
 
216
222
  /* Suggestions list contains all suggestion items */
223
+ :scope:has(.lbl-list:hover) #component-preview .target-selected,
217
224
  :scope:has(.lbl-list:hover) #component-preview .target-item,
218
225
  :scope:has(.lbl-list:hover) #component-preview .target-active {
219
226
  opacity: 1 !important;
@@ -229,6 +236,7 @@
229
236
  :scope:has(.lbl-popover:hover) .target-popover.guide-line,
230
237
  :scope:has(.lbl-header:hover) .target-header.guide-line,
231
238
  :scope:has(.lbl-list:hover) .target-list.guide-line,
239
+ :scope:has(.lbl-selected:hover) .target-selected.guide-line,
232
240
  :scope:has(.lbl-item:hover) .target-item.guide-line,
233
241
  :scope:has(.lbl-active:hover) .target-active.guide-line,
234
242
  :scope:has(.lbl-image:hover) .target-image.guide-line,
@@ -246,6 +254,7 @@
246
254
  :scope:has(.lbl-popover:hover) .target-popover.guide-box,
247
255
  :scope:has(.lbl-header:hover) .target-header.guide-box,
248
256
  :scope:has(.lbl-list:hover) .target-list.guide-box,
257
+ :scope:has(.lbl-selected:hover) .target-selected.guide-box,
249
258
  :scope:has(.lbl-item:hover) .target-item.guide-box,
250
259
  :scope:has(.lbl-active:hover) .target-active.guide-box,
251
260
  :scope:has(.lbl-image:hover) .target-image.guide-box,
@@ -263,12 +272,16 @@
263
272
  <feDropShadow dx="0" dy="8" stdDeviation="12" flood-opacity="0.12"/>
264
273
  </filter>
265
274
 
275
+ <clipPath id="logo-clip-house">
276
+ <circle cx="543" cy="176" r="19"/>
277
+ </clipPath>
278
+
266
279
  <clipPath id="logo-clip-madhouse">
267
- <circle cx="543" cy="180" r="19"/>
280
+ <circle cx="543" cy="246" r="19"/>
268
281
  </clipPath>
269
282
 
270
283
  <clipPath id="logo-clip-wph">
271
- <circle cx="543" cy="254" r="19"/>
284
+ <circle cx="543" cy="316" r="19"/>
272
285
  </clipPath>
273
286
  </defs>
274
287
 
@@ -291,14 +304,14 @@
291
304
  <!-- Input Text Area (label: & caret): ::part(input) -->
292
305
  <g class="comp-part target-input">
293
306
  <text class="mono-text" x="458" y="82" font-size="15" fill="var(--text-muted)" font-weight="600">label:</text>
294
- <line x1="540" y1="65" x2="540" y2="87" stroke="var(--c-active)" stroke-width="2.5"/>
307
+ <line x1="558" y1="65" x2="558" y2="87" stroke="var(--c-active)" stroke-width="2.5"/>
295
308
  </g>
296
309
 
297
- <!-- Highlight Pill for "hou": ::highlight(label) -->
310
+ <!-- Highlight Pill for "house": ::highlight(label) -->
298
311
  <g class="comp-part target-hl-val">
299
- <rect x="508" y="62" width="34" height="28" rx="5" fill="rgba(37, 99, 235, 0.14)"/>
300
- <line x1="512" y1="87" x2="538" y2="87" stroke="var(--c-control)" stroke-width="2" stroke-linecap="round"/>
301
- <text class="mono-text" x="512" y="82" font-size="15" fill="var(--c-control)" font-weight="600">hou</text>
312
+ <rect x="508" y="62" width="52" height="28" rx="5" fill="rgba(37, 99, 235, 0.14)"/>
313
+ <line x1="512" y1="87" x2="556" y2="87" stroke="var(--c-control)" stroke-width="2" stroke-linecap="round"/>
314
+ <text class="mono-text" x="512" y="82" font-size="15" fill="var(--c-control)" font-weight="600">house</text>
302
315
  </g>
303
316
 
304
317
  <!-- Clear Button: ::part(clear-button) -->
@@ -307,8 +320,8 @@
307
320
  <path d="M897 71 L907 81 M907 71 L897 81" stroke="var(--text-muted)" stroke-width="2" stroke-linecap="round"/>
308
321
  </g>
309
322
 
310
- <!-- Suggestions Popover Background Card (aligned with colored box of "hou" at x=508): ::part(popover) -->
311
- <rect class="component-card comp-part target-popover" x="508" y="94" width="350" height="204" rx="10" filter="url(#shadow)"/>
323
+ <!-- Suggestions Popover Background Card (aligned with colored box of "house" at x=508): ::part(popover) -->
324
+ <rect class="component-card comp-part target-popover" x="508" y="94" width="350" height="264" rx="10" filter="url(#shadow)"/>
312
325
 
313
326
  <!-- Popover Header: ::part(suggestions-header) -->
314
327
  <g class="comp-part target-header">
@@ -317,22 +330,30 @@
317
330
  <text class="ui-text" x="526" y="121" font-size="12" font-weight="700" letter-spacing="0.06em" fill="var(--text-muted)" style="text-transform: uppercase;">Record Label</text>
318
331
  </g>
319
332
 
320
- <!-- Item 1: "Madhouse Records": ::part(suggestion-item) -->
321
- <rect class="comp-part target-item" x="516" y="146" width="334" height="68" rx="8" fill="none"/>
333
+ <!-- Item 1 (Selected): "House": ::part(suggestion-item-selected) -->
334
+ <rect class="comp-part target-selected" x="516" y="144" width="334" height="64" rx="8" fill="var(--selected-item-bg)"/>
335
+ <g class="comp-part target-selected">
336
+ <image href="data:image/jpeg;base64,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" x="524" y="157" width="38" height="38" preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-clip-house)"/>
337
+ <circle cx="543" cy="176" r="19" fill="none" stroke="var(--border-color)" stroke-width="1.5"/>
338
+ </g>
339
+ <text class="ui-text comp-part target-selected" x="574" y="181" font-size="15" font-weight="600" fill="var(--text-color)">House</text>
340
+
341
+ <!-- Item 2: "Madhouse Records": ::part(suggestion-item) -->
342
+ <rect class="comp-part target-item" x="516" y="214" width="334" height="64" rx="8" fill="none"/>
322
343
  <g class="comp-part target-image target-item">
323
- <image href="data:image/jpeg;base64,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" x="524" y="161" width="38" height="38" preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-clip-madhouse)"/>
324
- <circle cx="543" cy="180" r="19" fill="none" stroke="var(--border-color)" stroke-width="1.5"/>
344
+ <image href="data:image/jpeg;base64,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" x="524" y="227" width="38" height="38" preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-clip-madhouse)"/>
345
+ <circle cx="543" cy="246" r="19" fill="none" stroke="var(--border-color)" stroke-width="1.5"/>
325
346
  </g>
326
- <text class="ui-text comp-part target-item" x="574" y="185" font-size="15" font-weight="600" fill="var(--text-color)">Madhouse Records</text>
347
+ <text class="ui-text comp-part target-item" x="574" y="251" font-size="15" font-weight="600" fill="var(--text-color)">Madhouse Records</text>
327
348
 
328
- <!-- Item 2 (Active/Highlighted): "We Play House Recordings": ::part(suggestion-item-active) -->
329
- <rect class="comp-part target-active" x="516" y="220" width="334" height="68" rx="8" fill="var(--active-item-bg)"/>
349
+ <!-- Item 3 (Active/Highlighted): "We Play House Recordings": ::part(suggestion-item-active) -->
350
+ <rect class="comp-part target-active" x="516" y="284" width="334" height="64" rx="8" fill="var(--active-item-bg)"/>
330
351
  <g class="comp-part target-active">
331
- <image href="data:image/jpeg;base64,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bEs5Vri4lkYvJNM6qoaR2JJIUADAACgAd14t8OWXjLwprPhHUZJIrTXLK4sZniIEix3MbRMULAjcAxIyCM9jXhPiHwRd6ifD974e8HnT9AtvEI1LWdHJto31GM2E1qspgSQwMIZzbTeW7gt5RcLvVA/IeIPhj401HRvEUGjaEtvpupeMPDupaZpcn2d0s7SxuLJr+5aIzJGiS+TNIYI33MCWIEkrqADuf2e/2Uvgj+zHoX9k/CzQEtryZAl1qlzifUbvH/PWcgHbnny0Cxg8hBX0bXyDpXw+8ZWvhv4X6VrvhibUbjwt4n1G81VfNs5IDDc2Wpp59qjzLts/tF1ELe3I82GIIhT93uNo/DrxriInRT/Za+PLTV9O07zbdjpWkxWsUcxOZPLAe6We4EcTOVWYKBkFVALXjX9jP4EfEr44x/Hz4i6M3iXXLaytrK2s75lk02EWzOyy/Z9oEjnfg+aXQYBCg819RNaWj2psHhRrZk8sxFRsMeNu3b0244xjGK+V9X+FviMeNNR8T+HNFVdN1rxFpkmraZdPD5Fzb2jWjJqtsqu6x3ELxMJAwRpos7gXSLOhY+DvGGm6lqc2p+Godf1yfxauoW2q3BiZI9JluE2NG/mpLE9laExCILiRkOAyys1AFLwD+xj8CPhX8cLn48/DXSG8N6zfWFxYXNjZMqabILiSORpVt9p8px5YAETImCTszzX1bXzV4D8EeKdA+LWoa+unOujag2smVtQS1e5tZLi7jlT7JeW7+ZJbXW0yeRcIzw4VQ8aqsR+laACiiigD/9P9/KKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/1P38ooooAKKKKACiiigAooooAKKKKACiiigAooooA//V/fyiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9k=" x="524" y="235" width="38" height="38" preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-clip-wph)"/>
332
- <circle cx="543" cy="254" r="19" fill="none" stroke="var(--border-color)" stroke-width="1.5"/>
352
+ <image href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCARXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAGSgAwAEAAAAAQAAAGQAAAAA/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY7PhCfv/AABEIAGQAZAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAICAgICAgMCAgMFAwMDBQYFBQUFBggGBgYGBggKCAgICAgICgoKCgoKCgoMDAwMDAwODg4ODg8PDw8PDw8PDw//2wBDAQICAgQEBAcEBAcQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/3QAEAAf/2gAMAwEAAhEDEQA/AP38ooooAKKKKACiiigAooooAKKKKACiiigAooooA//Q/fyiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9H9/Ko6nqEGk6bd6rcrI8NnDJM6xRtLIVjUsQkaAs7EDhVBJPAGavUUAfm4f+Csf7FIOD4qvwR/1Cbz/wCN0n/D2T9ij/oar/8A8FN5/wDG6/Gf/gqV+yv/AMKH+Nz/ABB8LWnk+DPiFJLeQCNcR2mo53XVvxwqsW82McDDMqjEZrwHVv2MfibpP7JWm/tYzxn+yL7UGhey8s+bFprkRQX7HtHJOGjxjoY3GVbgA/oct/8Agq5+xfd3EVra+JtRmmmZURE0e9ZmZjgKoEeSSeABX3h448Vf8If4D1/xslsbr+xNNutREDExGT7NC02wkglN23GSpx6dq/mo/wCCSv7K/wDwtj4sSfHHxbZ+Z4W+H8yNZrIuUutZIDxAZ6i2UiZvRzF1BNf0YfHb/kiHxD/7F3Vv/SSWgD5h/Zc/4KH/AAD/AGm0tdDtb7/hEvGcoAbRNTkVXlfuLSfhLgegG2TAyYwOa+86/gi8LeGvE/i/xBZeHPBum3Wr61eyBLa1sonmuJJOoCJGCxI68dOtf1ufsB/Dv9r74f8Aw9az/af8TxanbvFGNL0yc/a9UsVHUXF8rYYY4EZMpXj94uNlAD/jN/wUK+Ff7Pn7REfwO+LGn3Ol6bdadaXsWuwk3EMb3LyKUuLdV8xEXYPnTzDk8qAM19dS/F34Ww+Af+FqS+LdLXwd5XnDV/tcX2Ip6ibdtJzxgHOeMZ4r+Zz/AILFf8nep/2Lum/+jJ6+EZfg58eY/hInxGl8La2vw7NwZFvTBN/Z/mlQvn4+6FI+TzsbSfl3Z4oA/qW+B/8AwUJ+F/7Rf7Qt18E/hTpl1f6VY6XdX767cH7PHNJbyxIEgtmXzGjYSE75DGcjGwg5r7/r+WP/AII2/wDJ297/ANixqP8A6Pta/qcoAKKKKAP/0v38ooqOUKYnDJ5gKnKcHcMdOeOfegDxj4//AAB+Hv7Snw5uPhl8SreWXS5riC6SW3YR3EE1u+5XidlYKSpaNjjlHYd812+rfDzwZrXw/ufhZf6VC3hW6046S1gq7YRZGLyREoH3QqcLjkYBHIr5G+F3wn+JHhf4cav4d8Q+HW+16r4FsNKhgtpLOOCO8s7WaKS3uU89hJdPNKSLpXMTxbVIiMZMvUy/DvxvB4Bk0fSvD1wb2Ofw7dXyTNp1u2p2VjNE11pkbW0mx8Ik3Nx5aSeaImdkZ2UA9p+BvwV8Efs9/DHRvhT8PopE0jR0bEs5Vri4lkYvJNM6qoaR2JJIUADAACgAd14t8OWXjLwprPhHUZJIrTXLK4sZniIEix3MbRMULAjcAxIyCM9jXhPiHwRd6ifD974e8HnT9AtvEI1LWdHJto31GM2E1qspgSQwMIZzbTeW7gt5RcLvVA/IeIPhj401HRvEUGjaEtvpupeMPDupaZpcn2d0s7SxuLJr+5aIzJGiS+TNIYI33MCWIEkrqADuf2e/2Uvgj+zHoX9k/CzQEtryZAl1qlzifUbvH/PWcgHbnny0Cxg8hBX0bXyDpXw+8ZWvhv4X6VrvhibUbjwt4n1G81VfNs5IDDc2Wpp59qjzLts/tF1ELe3I82GIIhT93uNo/DrxriInRT/Za+PLTV9O07zbdjpWkxWsUcxOZPLAe6We4EcTOVWYKBkFVALXjX9jP4EfEr44x/Hz4i6M3iXXLaytrK2s75lk02EWzOyy/Z9oEjnfg+aXQYBCg819RNaWj2psHhRrZk8sxFRsMeNu3b0244xjGK+V9X+FviMeNNR8T+HNFVdN1rxFpkmraZdPD5Fzb2jWjJqtsqu6x3ELxMJAwRpos7gXSLOhY+DvGGm6lqc2p+Godf1yfxauoW2q3BiZI9JluE2NG/mpLE9laExCILiRkOAyys1AFLwD+xj8CPhX8cLn48/DXSG8N6zfWFxYXNjZMqabILiSORpVt9p8px5YAETImCTszzX1bXzV4D8EeKdA+LWoa+unOujag2smVtQS1e5tZLi7jlT7JeW7+ZJbXW0yeRcIzw4VQ8aqsR+laACiiigD/9P9/KKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/1P38ooooAKKKKACiiigAooooAKKKKACiiigAooooA//V/fyiiigAooooAKKKKACiiigAooooAKKKKACiiigD/9k=" x="524" y="297" width="38" height="38" preserveAspectRatio="xMidYMid slice" clip-path="url(#logo-clip-wph)"/>
353
+ <circle cx="543" cy="316" r="19" fill="none" stroke="var(--border-color)" stroke-width="1.5"/>
333
354
  </g>
334
355
  <g class="comp-part target-val target-active">
335
- <text class="ui-text" x="574" y="259" font-size="15" font-weight="600" fill="var(--text-color)">We Play House Recordings</text>
356
+ <text class="ui-text" x="574" y="321" font-size="15" font-weight="600" fill="var(--text-color)">We Play House Recordings</text>
336
357
  </g>
337
358
  </g>
338
359
 
@@ -343,7 +364,7 @@
343
364
 
344
365
  <!-- 1. Host Target -->
345
366
  <path class="guide-line target-host" d="M200 49 L395 49" stroke="var(--c-host)"/>
346
- <rect class="guide-box target-host" x="398" y="38" width="544" height="272" rx="16" stroke="var(--c-host)"/>
367
+ <rect class="guide-box target-host" x="398" y="38" width="544" height="330" rx="16" stroke="var(--c-host)"/>
347
368
  <circle class="guide-dot target-host" cx="395" cy="49" r="4" fill="var(--c-host)"/>
348
369
 
349
370
  <!-- 2. Control Target -->
@@ -361,10 +382,10 @@
361
382
  <rect class="guide-box target-input" x="454" y="58" width="395" height="36" rx="6" stroke="var(--c-input)"/>
362
383
  <circle class="guide-dot target-input" cx="454" cy="100" r="4" fill="var(--c-input)"/>
363
384
 
364
- <!-- 5. Highlight Label Target (around "hou") -->
365
- <path class="guide-line target-hl-val" d="M240 263 L525 263 L525 93" stroke="var(--c-hl-val)"/>
366
- <rect class="guide-box target-hl-val" x="504" y="58" width="42" height="34" rx="7" stroke="var(--c-hl-val)"/>
367
- <circle class="guide-dot target-hl-val" cx="525" cy="93" r="4" fill="var(--c-hl-val)"/>
385
+ <!-- 5. Highlight Label Target (around "house") -->
386
+ <path class="guide-line target-hl-val" d="M240 263 L534 263 L534 93" stroke="var(--c-hl-val)"/>
387
+ <rect class="guide-box target-hl-val" x="504" y="58" width="60" height="34" rx="7" stroke="var(--c-hl-val)"/>
388
+ <circle class="guide-dot target-hl-val" cx="534" cy="93" r="4" fill="var(--c-hl-val)"/>
368
389
 
369
390
  <!-- 6. Suggestions Header Target -->
370
391
  <path class="guide-line target-header" d="M310 331 L480 331 L480 116 L506 116" stroke="var(--c-header)"/>
@@ -372,39 +393,44 @@
372
393
  <circle class="guide-dot target-header" cx="506" cy="116" r="4" fill="var(--c-header)"/>
373
394
 
374
395
  <!-- 7. Suggestion Image Target -->
375
- <path class="guide-line target-image" d="M300 395 L495 395 L495 180 L520 180" stroke="var(--c-image)"/>
376
- <circle class="guide-box target-image" cx="543" cy="180" r="23" stroke="var(--c-image)"/>
377
- <circle class="guide-dot target-image" cx="520" cy="180" r="4" fill="var(--c-image)"/>
396
+ <path class="guide-line target-image" d="M300 395 L495 395 L495 246 L520 246" stroke="var(--c-image)"/>
397
+ <circle class="guide-box target-image" cx="543" cy="246" r="23" stroke="var(--c-image)"/>
398
+ <circle class="guide-dot target-image" cx="520" cy="246" r="4" fill="var(--c-image)"/>
378
399
 
379
400
  <!-- 8. Clear Button Target -->
380
- <path class="guide-line target-clear" d="M1005 73 L925 73" stroke="var(--c-clear)"/>
401
+ <path class="guide-line target-clear" d="M1005 63 L940 63 L922 76" stroke="var(--c-clear)"/>
381
402
  <circle class="guide-box target-clear" cx="902" cy="76" r="20" stroke="var(--c-clear)"/>
382
- <circle class="guide-dot target-clear" cx="925" cy="73" r="4" fill="var(--c-clear)"/>
403
+ <circle class="guide-dot target-clear" cx="922" cy="76" r="4" fill="var(--c-clear)"/>
383
404
 
384
405
  <!-- 9. Popover Target -->
385
- <path class="guide-line target-popover" d="M1005 125 L862 125" stroke="var(--c-popover)"/>
386
- <rect class="guide-box target-popover" x="504" y="90" width="358" height="212" rx="14" stroke="var(--c-popover)"/>
387
- <circle class="guide-dot target-popover" cx="862" cy="125" r="4" fill="var(--c-popover)"/>
406
+ <path class="guide-line target-popover" d="M1005 119 L862 119" stroke="var(--c-popover)"/>
407
+ <rect class="guide-box target-popover" x="504" y="90" width="358" height="272" rx="14" stroke="var(--c-popover)"/>
408
+ <circle class="guide-dot target-popover" cx="862" cy="119" r="4" fill="var(--c-popover)"/>
388
409
 
389
410
  <!-- 10. Suggestions List Target -->
390
- <path class="guide-line target-list" d="M1005 180 L875 180 L875 150 L854 150" stroke="var(--c-list)"/>
391
- <rect class="guide-box target-list" x="512" y="142" width="342" height="148" rx="8" stroke="var(--c-list)"/>
392
- <circle class="guide-dot target-list" cx="854" cy="150" r="4" fill="var(--c-list)"/>
411
+ <path class="guide-line target-list" d="M1005 175 L875 175 L875 148 L854 148" stroke="var(--c-list)"/>
412
+ <rect class="guide-box target-list" x="512" y="140" width="342" height="212" rx="8" stroke="var(--c-list)"/>
413
+ <circle class="guide-dot target-list" cx="854" cy="148" r="4" fill="var(--c-list)"/>
393
414
 
394
- <!-- 11. Suggestion Item Target (Item 1: Madhouse Records) -->
395
- <path class="guide-line target-item" d="M1005 240 L895 240 L895 180 L852 180" stroke="var(--c-item)"/>
396
- <rect class="guide-box target-item" x="514" y="144" width="338" height="72" rx="10" stroke="var(--c-item)"/>
397
- <circle class="guide-dot target-item" cx="852" cy="180" r="4" fill="var(--c-item)"/>
415
+ <!-- 11. Suggestion Item Selected Target (Item 1: House) -->
416
+ <path class="guide-line target-selected" d="M1005 231 L895 231 L895 176 L852 176" stroke="var(--c-selected)"/>
417
+ <rect class="guide-box target-selected" x="514" y="142" width="338" height="68" rx="10" stroke="var(--c-selected)"/>
418
+ <circle class="guide-dot target-selected" cx="852" cy="176" r="4" fill="var(--c-selected)"/>
398
419
 
399
- <!-- 12. Suggestion Item Active Target (Item 2: We Play House Recordings) -->
400
- <path class="guide-line target-active" d="M1005 300 L915 300 L915 254 L852 254" stroke="var(--c-active)"/>
401
- <rect class="guide-box target-active" x="514" y="218" width="338" height="72" rx="10" stroke="var(--c-active)"/>
402
- <circle class="guide-dot target-active" cx="852" cy="254" r="4" fill="var(--c-active)"/>
420
+ <!-- 12. Suggestion Item Target (Item 2: Madhouse Records) -->
421
+ <path class="guide-line target-item" d="M1005 287 L910 287 L910 246 L852 246" stroke="var(--c-item)"/>
422
+ <rect class="guide-box target-item" x="514" y="212" width="338" height="68" rx="10" stroke="var(--c-item)"/>
423
+ <circle class="guide-dot target-item" cx="852" cy="246" r="4" fill="var(--c-item)"/>
403
424
 
404
- <!-- 13. Suggestion Value Target ("We Play House Recordings" text) -->
405
- <path class="guide-line target-val" d="M1005 360 L935 360 L935 254 L770 254" stroke="var(--c-val-text)"/>
406
- <rect class="guide-box target-val" x="570" y="243" width="204" height="24" rx="6" stroke="var(--c-val-text)"/>
407
- <circle class="guide-dot target-val" cx="770" cy="254" r="4" fill="var(--c-val-text)"/>
425
+ <!-- 13. Suggestion Item Active Target (Item 3: We Play House Recordings) -->
426
+ <path class="guide-line target-active" d="M1005 343 L925 343 L925 316 L852 316" stroke="var(--c-active)"/>
427
+ <rect class="guide-box target-active" x="514" y="282" width="338" height="68" rx="10" stroke="var(--c-active)"/>
428
+ <circle class="guide-dot target-active" cx="852" cy="316" r="4" fill="var(--c-active)"/>
429
+
430
+ <!-- 14. Suggestion Value Target ("We Play House Recordings" text) -->
431
+ <path class="guide-line target-val" d="M1005 399 L940 399 L940 316 L770 316" stroke="var(--c-val-text)"/>
432
+ <rect class="guide-box target-val" x="570" y="305" width="204" height="24" rx="6" stroke="var(--c-val-text)"/>
433
+ <circle class="guide-dot target-val" cx="770" cy="316" r="4" fill="var(--c-val-text)"/>
408
434
 
409
435
 
410
436
  <!-- ===================================================================== -->
@@ -450,32 +476,37 @@
450
476
  <!-- CODE LABELS (RIGHT SIDE) -->
451
477
  <!-- ===================================================================== -->
452
478
  <g class="code-label lbl-clear">
453
- <rect class="label-hitbox" x="1005" y="58" width="225" height="30" rx="6"/>
454
- <text class="label-text" x="1015" y="78" fill="var(--c-clear)">::part(clear-button)</text>
479
+ <rect class="label-hitbox" x="1005" y="48" width="225" height="30" rx="6"/>
480
+ <text class="label-text" x="1015" y="68" fill="var(--c-clear)">::part(clear-button)</text>
455
481
  </g>
456
482
 
457
483
  <g class="code-label lbl-popover">
458
- <rect class="label-hitbox" x="1005" y="110" width="185" height="30" rx="6"/>
459
- <text class="label-text" x="1015" y="130" fill="var(--c-popover)">::part(popover)</text>
484
+ <rect class="label-hitbox" x="1005" y="104" width="185" height="30" rx="6"/>
485
+ <text class="label-text" x="1015" y="124" fill="var(--c-popover)">::part(popover)</text>
460
486
  </g>
461
487
 
462
488
  <g class="code-label lbl-list">
463
- <rect class="label-hitbox" x="1005" y="165" width="260" height="30" rx="6"/>
464
- <text class="label-text" x="1015" y="185" fill="var(--c-list)">::part(suggestions-list)</text>
489
+ <rect class="label-hitbox" x="1005" y="160" width="260" height="30" rx="6"/>
490
+ <text class="label-text" x="1015" y="180" fill="var(--c-list)">::part(suggestions-list)</text>
491
+ </g>
492
+
493
+ <g class="code-label lbl-selected">
494
+ <rect class="label-hitbox" x="1005" y="216" width="335" height="30" rx="6"/>
495
+ <text class="label-text" x="1015" y="236" fill="var(--c-selected)">::part(suggestion-item-selected)</text>
465
496
  </g>
466
497
 
467
498
  <g class="code-label lbl-item">
468
- <rect class="label-hitbox" x="1005" y="225" width="265" height="30" rx="6"/>
469
- <text class="label-text" x="1015" y="245" fill="var(--c-item)">::part(suggestion-item)</text>
499
+ <rect class="label-hitbox" x="1005" y="272" width="265" height="30" rx="6"/>
500
+ <text class="label-text" x="1015" y="292" fill="var(--c-item)">::part(suggestion-item)</text>
470
501
  </g>
471
502
 
472
503
  <g class="code-label lbl-active">
473
- <rect class="label-hitbox" x="1005" y="285" width="320" height="30" rx="6"/>
474
- <text class="label-text" x="1015" y="305" fill="var(--c-active)">::part(suggestion-item-active)</text>
504
+ <rect class="label-hitbox" x="1005" y="328" width="320" height="30" rx="6"/>
505
+ <text class="label-text" x="1015" y="348" fill="var(--c-active)">::part(suggestion-item-active)</text>
475
506
  </g>
476
507
 
477
508
  <g class="code-label lbl-val">
478
- <rect class="label-hitbox" x="1005" y="345" width="270" height="30" rx="6"/>
479
- <text class="label-text" x="1015" y="365" fill="var(--c-val-text)">::part(suggestion-value)</text>
509
+ <rect class="label-hitbox" x="1005" y="384" width="270" height="30" rx="6"/>
510
+ <text class="label-text" x="1015" y="404" fill="var(--c-val-text)">::part(suggestion-value)</text>
480
511
  </g>
481
512
  </svg>
@@ -8,6 +8,8 @@ import { highlightManager, isOpaqueRangeSupported, isHighlightSupported } from '
8
8
  import { getCaretCoordinates, positionPopover } from '../utils/positioning.js';
9
9
  import { setupContentEditableAdapter, isContentEditableFallbackActive } from '../utils/contenteditable-adapter.js';
10
10
 
11
+ const KEYWORD_SUGGESTION_DELAY = 300;
12
+
11
13
  const TEMPLATE = document.createElement('template');
12
14
  TEMPLATE.innerHTML = `
13
15
  <style>
@@ -224,6 +226,10 @@ TEMPLATE.innerHTML = `
224
226
  color: var(--ri-item-title-color, var(--rs-item-title-color, #0f172a));
225
227
  }
226
228
 
229
+ .suggestion-item.selected {
230
+ background-color: var(--ri-item-selected-bg, rgba(37, 99, 235, 0.06));
231
+ }
232
+
227
233
  .suggestion-item:hover,
228
234
  .suggestion-item.active {
229
235
  background-color: var(--ri-item-active-bg, var(--rs-item-active-bg, #f1f5f9));
@@ -283,6 +289,7 @@ TEMPLATE.innerHTML = `
283
289
  aria-autocomplete="list"
284
290
  aria-expanded="false"
285
291
  aria-haspopup="listbox"
292
+ aria-controls="ri-listbox"
286
293
  />
287
294
  <button part="clear-button" type="button" class="clear-button" aria-label="Clear search query" hidden>
288
295
  <svg viewBox="0 0 20 20" fill="currentColor">
@@ -296,13 +303,17 @@ TEMPLATE.innerHTML = `
296
303
  part="popover suggestions"
297
304
  class="popover"
298
305
  popover="manual"
299
- role="listbox"
300
- aria-label="Search suggestions"
301
306
  >
302
307
  <div part="suggestions-header" class="popover-header">
303
- <span part="suggestions-title" class="popover-title">Suggestions</span>
308
+ <span id="ri-listbox-label" part="suggestions-title" class="popover-title">Suggestions</span>
304
309
  </div>
305
- <ul part="suggestions-list" class="suggestions-list" role="presentation"></ul>
310
+ <ul
311
+ id="ri-listbox"
312
+ part="suggestions-list"
313
+ class="suggestions-list"
314
+ role="listbox"
315
+ aria-labelledby="ri-listbox-label"
316
+ ></ul>
306
317
  </div>
307
318
 
308
319
  <slot style="display: none;"></slot>
@@ -361,6 +372,8 @@ export class RichInput extends HTMLElement {
361
372
  'autofocus',
362
373
  'required',
363
374
  'highlight-quotes',
375
+ 'aria-label',
376
+ 'aria-labelledby',
364
377
  ];
365
378
  }
366
379
 
@@ -383,6 +396,7 @@ export class RichInput extends HTMLElement {
383
396
  editableDiv.setAttribute('aria-autocomplete', 'list');
384
397
  editableDiv.setAttribute('aria-expanded', 'false');
385
398
  editableDiv.setAttribute('aria-haspopup', 'listbox');
399
+ editableDiv.setAttribute('aria-controls', 'ri-listbox');
386
400
  editableDiv.setAttribute('spellcheck', 'false');
387
401
  editableDiv.setAttribute('tabindex', '0');
388
402
  existingInput.replaceWith(editableDiv);
@@ -401,6 +415,7 @@ export class RichInput extends HTMLElement {
401
415
  this._activeSuggestions = [];
402
416
  this._selectedIndex = -1;
403
417
  this._context = null;
418
+ this._suggestionTimeout = null;
404
419
  this._ownedRanges = [];
405
420
  this._invalidRanges = [];
406
421
  this._activeKeywordHighlightMap = new Map();
@@ -416,6 +431,7 @@ export class RichInput extends HTMLElement {
416
431
  this._onClick = this._onClick.bind(this);
417
432
  this._onSelectionChange = this._onSelectionChange.bind(this);
418
433
  this._onClearClick = this._onClearClick.bind(this);
434
+ this._onClearMouseDown = (e) => e.preventDefault();
419
435
  this._onSlotChange = this._onSlotChange.bind(this);
420
436
  this._onGlobalClick = this._onGlobalClick.bind(this);
421
437
  this._onGlobalResizeOrScroll = this._onGlobalResizeOrScroll.bind(this);
@@ -453,6 +469,7 @@ export class RichInput extends HTMLElement {
453
469
  this._input.addEventListener('focus', this._onFocus);
454
470
  this._input.addEventListener('blur', this._onBlur);
455
471
  this._input.addEventListener('click', this._onClick);
472
+ this._clearBtn.addEventListener('mousedown', this._onClearMouseDown);
456
473
  this._clearBtn.addEventListener('click', this._onClearClick);
457
474
 
458
475
  // Global events
@@ -475,6 +492,7 @@ export class RichInput extends HTMLElement {
475
492
  this._internals.setFormValue(this._input.value);
476
493
  }
477
494
 
495
+ this._syncAccessibleName();
478
496
  this._updateClearButton();
479
497
  this.updateHighlights();
480
498
  }
@@ -494,6 +512,7 @@ export class RichInput extends HTMLElement {
494
512
  this._input.removeEventListener('focus', this._onFocus);
495
513
  this._input.removeEventListener('blur', this._onBlur);
496
514
  this._input.removeEventListener('click', this._onClick);
515
+ this._clearBtn.removeEventListener('mousedown', this._onClearMouseDown);
497
516
  this._clearBtn.removeEventListener('click', this._onClearClick);
498
517
 
499
518
  document.removeEventListener('click', this._onGlobalClick);
@@ -518,6 +537,9 @@ export class RichInput extends HTMLElement {
518
537
  }
519
538
  } else if (name === 'placeholder') {
520
539
  this._input.placeholder = newValue || '';
540
+ this._syncAccessibleName();
541
+ } else if (name === 'aria-label' || name === 'aria-labelledby') {
542
+ this._syncAccessibleName();
521
543
  } else if (name === 'disabled') {
522
544
  this._input.disabled = newValue !== null;
523
545
  } else if (name === 'readonly') {
@@ -535,6 +557,25 @@ export class RichInput extends HTMLElement {
535
557
  }
536
558
  }
537
559
 
560
+ _syncAccessibleName() {
561
+ if (!this._input) return;
562
+ if (this.hasAttribute('aria-label')) {
563
+ this._input.setAttribute('aria-label', this.getAttribute('aria-label'));
564
+ } else if (this._internals?.labels?.length > 0) {
565
+ const labelText = Array.from(this._internals.labels)
566
+ .map((l) => l.textContent.trim())
567
+ .filter(Boolean)
568
+ .join(' ');
569
+ if (labelText) {
570
+ this._input.setAttribute('aria-label', labelText);
571
+ }
572
+ } else if (this.hasAttribute('placeholder')) {
573
+ this._input.setAttribute('aria-label', this.getAttribute('placeholder'));
574
+ } else {
575
+ this._input.setAttribute('aria-label', 'Search');
576
+ }
577
+ }
578
+
538
579
  // --- Form Associated Lifecycle ---
539
580
  formResetCallback() {
540
581
  this.value = this.getAttribute('value') || '';
@@ -915,8 +956,9 @@ export class RichInput extends HTMLElement {
915
956
  }
916
957
  }
917
958
 
918
- // Enter when popover closed triggers search/change
959
+ // Enter when popover closed (or no suggestion selected) triggers search/change
919
960
  if (e.key === 'Enter') {
961
+ this.hideSuggestions();
920
962
  this.dispatchEvent(new CustomEvent('search', {
921
963
  bubbles: true,
922
964
  composed: true,
@@ -937,18 +979,20 @@ export class RichInput extends HTMLElement {
937
979
  this._isFocused = true;
938
980
  this._lastCaretPosition = this._input.selectionStart;
939
981
  this.updateHighlights();
940
- // Optionally open suggestions if context matches
941
- if (this._input.value.length > 0) {
942
- this.updateSuggestions('focus');
943
- }
982
+ this.updateSuggestions('focus');
944
983
  }
945
984
 
946
985
  _onBlur() {
947
986
  this._isFocused = false;
948
987
  this._lastCaretPosition = -1;
988
+ if (this._suggestionTimeout) {
989
+ clearTimeout(this._suggestionTimeout);
990
+ this._suggestionTimeout = null;
991
+ }
949
992
  this.updateHighlights();
950
993
  // Delay closing so click events on popover items can fire
951
994
  setTimeout(() => {
995
+ if (this._isFocused) return;
952
996
  this.hideSuggestions();
953
997
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
954
998
  }, 150);
@@ -977,7 +1021,7 @@ export class RichInput extends HTMLElement {
977
1021
  _onClearClick() {
978
1022
  this.value = '';
979
1023
  this._input.focus();
980
- this.hideSuggestions();
1024
+ this.updateSuggestions('clear');
981
1025
  this.dispatchEvent(new Event('input', { bubbles: true, composed: true }));
982
1026
  this.dispatchEvent(new Event('change', { bubbles: true, composed: true }));
983
1027
  }
@@ -1052,6 +1096,11 @@ export class RichInput extends HTMLElement {
1052
1096
  }
1053
1097
 
1054
1098
  updateSuggestions(trigger = 'input') {
1099
+ if (this._suggestionTimeout) {
1100
+ clearTimeout(this._suggestionTimeout);
1101
+ this._suggestionTimeout = null;
1102
+ }
1103
+
1055
1104
  const caretPos = this._input.selectionStart;
1056
1105
  const context = getCaretContext(this._input.value, caretPos, this._configuredKeywords);
1057
1106
 
@@ -1071,17 +1120,69 @@ export class RichInput extends HTMLElement {
1071
1120
  return;
1072
1121
  }
1073
1122
 
1123
+ // Value suggestions always show immediately.
1124
+ // Keyword suggestions show immediately when:
1125
+ // - focusing/clearing an empty field
1126
+ // - typing characters that match a keyword (Boolean(context.query))
1127
+ // - explicitly triggered via the Down Arrow key
1128
+ // In other cases (at the start of a new token after a space when the field is not empty),
1129
+ // show after a small delay to prevent constant popups when typing regular sentences with spaces.
1130
+ const isEmptyField = this._input.value.length === 0;
1131
+ const shouldShowImmediately =
1132
+ context.mode === 'value' ||
1133
+ isEmptyField ||
1134
+ Boolean(context.query) ||
1135
+ trigger === 'arrow';
1136
+
1137
+ if (shouldShowImmediately) {
1138
+ this._showSuggestions(suggestions, context, trigger);
1139
+ } else {
1140
+ if (this._isPopoverOpen()) {
1141
+ this.hideSuggestions();
1142
+ }
1143
+ this._suggestionTimeout = setTimeout(() => {
1144
+ this._suggestionTimeout = null;
1145
+ const isFocused =
1146
+ this._isFocused ||
1147
+ this.shadowRoot?.activeElement === this._input ||
1148
+ document.activeElement === this ||
1149
+ document.activeElement === this._input ||
1150
+ Boolean(this.matches?.(':focus-within'));
1151
+ if (!isFocused) return;
1152
+
1153
+ const currentCaretPos = this._input.selectionStart;
1154
+ const currentContext = getCaretContext(this._input.value, currentCaretPos, this._configuredKeywords);
1155
+ this._context = currentContext;
1156
+ const currentSuggestions = getSuggestions(currentContext, this._configuredKeywords);
1157
+ if (currentSuggestions.length === 0) {
1158
+ this.hideSuggestions();
1159
+ return;
1160
+ }
1161
+ this._showSuggestions(currentSuggestions, currentContext, trigger);
1162
+ }, KEYWORD_SUGGESTION_DELAY);
1163
+ }
1164
+ }
1165
+
1166
+ _showSuggestions(suggestions, context, trigger) {
1074
1167
  this._activeSuggestions = suggestions;
1075
- this._selectedIndex = 0; // Pre-select first item for quick Enter/Tab
1168
+
1169
+ // Pre-select first item for quick Enter/Tab when filtering or in value mode or triggered via Down Arrow,
1170
+ // but leave unselected (-1) when showing full keyword list at the start of a new token so Enter/Tab aren't hijacked.
1171
+ const shouldPreselect =
1172
+ context.mode === 'value' ||
1173
+ Boolean(context.query) ||
1174
+ trigger === 'arrow';
1175
+ const existingSelectedIdx = suggestions.findIndex((s) => this._isSuggestionSelected(s));
1176
+ this._selectedIndex = existingSelectedIdx !== -1 ? existingSelectedIdx : (shouldPreselect ? 0 : -1); // Highlight matching item or first item for quick Enter/Tab
1076
1177
  this._renderSuggestions();
1077
1178
 
1078
1179
  // Show popover
1079
1180
  if (!this._isPopoverOpen()) {
1080
1181
  try {
1081
1182
  this._popover.showPopover();
1082
- this._input.setAttribute('aria-expanded', 'true');
1083
1183
  } catch (e) {}
1084
1184
  }
1185
+ this._input.setAttribute('aria-expanded', 'true');
1085
1186
 
1086
1187
  // Position popover at the start of the current OpaqueRange (or via mirror-div fallback when OpaqueRange is unsupported)
1087
1188
  const currentRange = this._getCurrentOpaqueRange();
@@ -1091,6 +1192,10 @@ export class RichInput extends HTMLElement {
1091
1192
  }
1092
1193
 
1093
1194
  hideSuggestions() {
1195
+ if (this._suggestionTimeout) {
1196
+ clearTimeout(this._suggestionTimeout);
1197
+ this._suggestionTimeout = null;
1198
+ }
1094
1199
  if (this._isPopoverOpen()) {
1095
1200
  try {
1096
1201
  this._popover.hidePopover();
@@ -1102,6 +1207,28 @@ export class RichInput extends HTMLElement {
1102
1207
  this._selectedIndex = -1;
1103
1208
  }
1104
1209
 
1210
+ _isSuggestionSelected(sug) {
1211
+ if (!this._context || !sug) return false;
1212
+
1213
+ if (sug.type === 'value' && this._context.mode === 'value' && this._context.token) {
1214
+ const currentVal = (this._context.token.innerValue ?? '').trim().toLowerCase();
1215
+ if (!currentVal) return false;
1216
+ const sugVal = (sug.value ?? '').trim().toLowerCase();
1217
+ const sugLabel = (sug.label ?? '').trim().toLowerCase();
1218
+ const sugDisplay = (sug.display ?? '').trim().toLowerCase();
1219
+ return currentVal === sugVal || currentVal === sugLabel || currentVal === sugDisplay;
1220
+ }
1221
+
1222
+ if (sug.type === 'keyword' && this._context.mode === 'keyword' && this._context.token?.type === 'keyword') {
1223
+ const currentKw = (this._context.token.keywordLower ?? '').trim().toLowerCase();
1224
+ if (!currentKw) return false;
1225
+ const sugId = (sug.id ?? '').trim().toLowerCase();
1226
+ return currentKw === sugId;
1227
+ }
1228
+
1229
+ return false;
1230
+ }
1231
+
1105
1232
  _renderSuggestions() {
1106
1233
  if (this._popoverTitle) {
1107
1234
  let title = 'Suggestions';
@@ -1117,12 +1244,17 @@ export class RichInput extends HTMLElement {
1117
1244
  this._suggestionsList.replaceChildren();
1118
1245
 
1119
1246
  this._activeSuggestions.forEach((sug, idx) => {
1247
+ const isAct = idx === this._selectedIndex;
1248
+ const isSel = this._isSuggestionSelected(sug);
1120
1249
  const li = document.createElement('li');
1121
- li.className = `suggestion-item${idx === this._selectedIndex ? ' active' : ''}`;
1250
+ li.className = `suggestion-item${isAct ? ' active' : ''}${isSel ? ' selected' : ''}`;
1122
1251
  li.id = `ri-opt-${idx}`;
1123
1252
  li.setAttribute('role', 'option');
1124
- li.setAttribute('aria-selected', idx === this._selectedIndex ? 'true' : 'false');
1125
- li.setAttribute('part', `suggestion-item${idx === this._selectedIndex ? ' suggestion-item-active' : ''}`);
1253
+ li.setAttribute('aria-selected', isSel ? 'true' : 'false');
1254
+ const parts = ['suggestion-item'];
1255
+ if (isAct) parts.push('suggestion-item-active');
1256
+ if (isSel) parts.push('suggestion-item-selected');
1257
+ li.setAttribute('part', parts.join(' '));
1126
1258
 
1127
1259
  if (sug.image) {
1128
1260
  const img = sug.image.cloneNode(true);
@@ -1174,7 +1306,11 @@ export class RichInput extends HTMLElement {
1174
1306
  _moveSelection(delta) {
1175
1307
  if (this._activeSuggestions.length === 0) return;
1176
1308
  const len = this._activeSuggestions.length;
1177
- this._selectedIndex = (this._selectedIndex + delta + len) % len;
1309
+ if (this._selectedIndex === -1) {
1310
+ this._selectedIndex = delta > 0 ? 0 : len - 1;
1311
+ } else {
1312
+ this._selectedIndex = (this._selectedIndex + delta + len) % len;
1313
+ }
1178
1314
  this._updateActiveSuggestion();
1179
1315
 
1180
1316
  // Scroll active item into view
@@ -1188,12 +1324,21 @@ export class RichInput extends HTMLElement {
1188
1324
  const items = this._suggestionsList.children;
1189
1325
  for (let i = 0; i < items.length; i++) {
1190
1326
  const isAct = i === this._selectedIndex;
1327
+ const isSel = this._isSuggestionSelected(this._activeSuggestions[i]);
1191
1328
  items[i].classList.toggle('active', isAct);
1192
- items[i].setAttribute('aria-selected', isAct ? 'true' : 'false');
1329
+ items[i].classList.toggle('selected', isSel);
1330
+ items[i].setAttribute('aria-selected', isSel ? 'true' : 'false');
1331
+ const parts = ['suggestion-item'];
1332
+ if (isAct) parts.push('suggestion-item-active');
1333
+ if (isSel) parts.push('suggestion-item-selected');
1334
+ items[i].setAttribute('part', parts.join(' '));
1193
1335
  if (isAct) {
1194
1336
  this._input.setAttribute('aria-activedescendant', items[i].id);
1195
1337
  }
1196
1338
  }
1339
+ if (this._selectedIndex === -1) {
1340
+ this._input.removeAttribute('aria-activedescendant');
1341
+ }
1197
1342
  }
1198
1343
 
1199
1344
  _applySelectedSuggestion() {
@@ -1224,12 +1369,9 @@ export class RichInput extends HTMLElement {
1224
1369
  composed: true,
1225
1370
  detail: selectDetail,
1226
1371
  }));
1227
- // If a keyword was selected (e.g. `mix:`), immediately show value suggestions
1228
- if (suggestion.type === 'keyword') {
1229
- this.updateSuggestions('keyword-selected');
1230
- } else {
1231
- this.hideSuggestions();
1232
- }
1372
+ // Immediately show value suggestions when a keyword was selected (e.g. `mix:`),
1373
+ // or keyword suggestions when a value was selected (since cursor is now after a space at a new token)
1374
+ this.updateSuggestions(suggestion.type === 'keyword' ? 'keyword-selected' : 'value-selected');
1233
1375
  }
1234
1376
  }
1235
1377
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rich-input",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
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",
@@ -31,5 +31,8 @@
31
31
  "bugs": {
32
32
  "url": "https://github.com/bramus/rich-input/issues"
33
33
  },
34
- "homepage": "https://github.com/bramus/rich-input#readme"
34
+ "homepage": "https://github.com/bramus/rich-input#readme",
35
+ "devDependencies": {
36
+ "puppeteer": "^25.11.0"
37
+ }
35
38
  }
@@ -168,11 +168,13 @@ export function getCaretContext(inputStr, caretPos, configuredKeywords) {
168
168
  }
169
169
  }
170
170
 
171
- // If caret is in whitespace or between tokens
171
+ // If caret is in whitespace or empty input (at the start of a new token)
172
172
  if (!activeToken || activeToken.type === 'whitespace') {
173
- // Check if the previous token was a colon without value or if we're in open space
174
173
  return {
175
- mode: 'none',
174
+ mode: 'keyword',
175
+ query: '',
176
+ replaceStart: caretPos,
177
+ replaceEnd: caretPos,
176
178
  caretPos,
177
179
  tokens,
178
180
  };
@@ -252,7 +254,7 @@ export function getSuggestions(context, configuredKeywords) {
252
254
  for (const [id, kw] of configuredKeywords.entries()) {
253
255
  const idLower = id.toLowerCase();
254
256
  const labelLower = (kw.label || '').toLowerCase();
255
- const matches = !q || idLower.startsWith(q) || labelLower.startsWith(q) || idLower.includes(q);
257
+ const matches = !q || idLower.startsWith(q) || labelLower.startsWith(q);
256
258
 
257
259
  if (matches) {
258
260
  suggestions.push({
@@ -325,6 +327,9 @@ export function applySuggestion(inputStr, suggestion, context) {
325
327
  // If after text starts with colon, remove it to avoid `mix::`
326
328
  if (after.startsWith(':')) {
327
329
  after = after.slice(1);
330
+ } else if (context.token?.type !== 'keyword' && after.length > 0 && !/^\s/.test(after)) {
331
+ // Ensure space before following token so it doesn't become the value of this keyword
332
+ after = ' ' + after;
328
333
  }
329
334
  const newValue = before + insertText + after;
330
335
  const newCaret = before.length + insertText.length;
@@ -333,12 +338,13 @@ export function applySuggestion(inputStr, suggestion, context) {
333
338
 
334
339
  // When inserting a value (e.g. `"We Play House Recordings"`)
335
340
  // Add a trailing space if after does not already start with whitespace
336
- if (after.length === 0 || !/^\s/.test(after)) {
341
+ const hasLeadingSpaceAfter = /^\s/.test(after);
342
+ if (after.length === 0 || !hasLeadingSpaceAfter) {
337
343
  insertText += ' ';
338
344
  }
339
345
 
340
346
  const newValue = before + insertText + after;
341
- const newCaret = before.length + insertText.length;
347
+ const newCaret = before.length + insertText.length + (hasLeadingSpaceAfter ? 1 : 0);
342
348
  return { newValue, newCaret };
343
349
  }
344
350