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 +9 -2
- package/assets/rich-input-parts.svg +92 -61
- package/components/rich-input.js +165 -23
- package/package.json +5 -2
- package/utils/query-parser.js +12 -6
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
|
|
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
|
|
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
|
|
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 (
|
|
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="
|
|
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="
|
|
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="
|
|
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 "
|
|
310
|
+
<!-- Highlight Pill for "house": ::highlight(label) -->
|
|
298
311
|
<g class="comp-part target-hl-val">
|
|
299
|
-
<rect x="508" y="62" width="
|
|
300
|
-
<line x1="512" y1="87" x2="
|
|
301
|
-
<text class="mono-text" x="512" y="82" font-size="15" fill="var(--c-control)" font-weight="600">
|
|
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 "
|
|
311
|
-
<rect class="component-card comp-part target-popover" x="508" y="94" width="350" height="
|
|
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: "
|
|
321
|
-
<rect class="comp-part target-
|
|
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="
|
|
324
|
-
<circle cx="543" cy="
|
|
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="
|
|
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
|
|
329
|
-
<rect class="comp-part target-active" x="516" y="
|
|
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="
|
|
332
|
-
<circle cx="543" cy="
|
|
352
|
+
<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="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="
|
|
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="
|
|
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 "
|
|
365
|
-
<path class="guide-line target-hl-val" d="M240 263
|
|
366
|
-
<rect class="guide-box target-hl-val" x="504" y="58" width="
|
|
367
|
-
<circle class="guide-dot target-hl-val" cx="
|
|
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
|
|
376
|
-
<circle class="guide-box target-image" cx="543" cy="
|
|
377
|
-
<circle class="guide-dot target-image" cx="520" cy="
|
|
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
|
|
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="
|
|
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
|
|
386
|
-
<rect class="guide-box target-popover" x="504" y="90" width="358" height="
|
|
387
|
-
<circle class="guide-dot target-popover" cx="862" cy="
|
|
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
|
|
391
|
-
<rect class="guide-box target-list" x="512" y="
|
|
392
|
-
<circle class="guide-dot target-list" cx="854" cy="
|
|
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:
|
|
395
|
-
<path class="guide-line target-
|
|
396
|
-
<rect class="guide-box target-
|
|
397
|
-
<circle class="guide-dot target-
|
|
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
|
|
400
|
-
<path class="guide-line target-
|
|
401
|
-
<rect class="guide-box target-
|
|
402
|
-
<circle class="guide-dot target-
|
|
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
|
|
405
|
-
<path class="guide-line target-
|
|
406
|
-
<rect class="guide-box target-
|
|
407
|
-
<circle class="guide-dot target-
|
|
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="
|
|
454
|
-
<text class="label-text" x="1015" y="
|
|
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="
|
|
459
|
-
<text class="label-text" x="1015" y="
|
|
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="
|
|
464
|
-
<text class="label-text" x="1015" y="
|
|
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="
|
|
469
|
-
<text class="label-text" x="1015" y="
|
|
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="
|
|
474
|
-
<text class="label-text" x="1015" y="
|
|
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="
|
|
479
|
-
<text class="label-text" x="1015" y="
|
|
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>
|
package/components/rich-input.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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${
|
|
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',
|
|
1125
|
-
|
|
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
|
-
|
|
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].
|
|
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
|
-
//
|
|
1228
|
-
|
|
1229
|
-
|
|
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.
|
|
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
|
}
|
package/utils/query-parser.js
CHANGED
|
@@ -168,11 +168,13 @@ export function getCaretContext(inputStr, caretPos, configuredKeywords) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// If caret is in whitespace or
|
|
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: '
|
|
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)
|
|
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
|
-
|
|
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
|
|