@f-ewald/components 0.7.0 → 1.0.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.
Files changed (46) hide show
  1. package/README.md +70 -47
  2. package/custom-elements.json +2236 -966
  3. package/dist/calendar-entry.d.ts +33 -0
  4. package/dist/calendar-entry.d.ts.map +1 -0
  5. package/dist/calendar-entry.js +64 -0
  6. package/dist/calendar-entry.js.map +1 -0
  7. package/dist/calendar-month.d.ts +67 -0
  8. package/dist/calendar-month.d.ts.map +1 -0
  9. package/dist/calendar-month.js +455 -0
  10. package/dist/calendar-month.js.map +1 -0
  11. package/dist/calendar-year.d.ts +43 -0
  12. package/dist/calendar-year.d.ts.map +1 -0
  13. package/dist/calendar-year.js +136 -0
  14. package/dist/calendar-year.js.map +1 -0
  15. package/dist/form-select.d.ts +21 -2
  16. package/dist/form-select.d.ts.map +1 -1
  17. package/dist/form-select.js +431 -27
  18. package/dist/form-select.js.map +1 -1
  19. package/dist/index.d.ts +3 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +3 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/map-circle.d.ts +3 -0
  24. package/dist/map-circle.d.ts.map +1 -1
  25. package/dist/map-circle.js +3 -0
  26. package/dist/map-circle.js.map +1 -1
  27. package/dist/tokens.css +4 -0
  28. package/dist/tokens.d.ts.map +1 -1
  29. package/dist/tokens.js +3 -0
  30. package/dist/tokens.js.map +1 -1
  31. package/dist/utils/calendar.d.ts +77 -0
  32. package/dist/utils/calendar.d.ts.map +1 -0
  33. package/dist/utils/calendar.js +135 -0
  34. package/dist/utils/calendar.js.map +1 -0
  35. package/docs/calendar-entry.md +53 -0
  36. package/docs/calendar-month.md +77 -0
  37. package/docs/calendar-year.md +53 -0
  38. package/docs/form-select.md +15 -3
  39. package/docs/map-circle.md +4 -0
  40. package/llms.txt +117 -28
  41. package/package.json +10 -2
  42. package/dist/map-point.d.ts +0 -31
  43. package/dist/map-point.d.ts.map +0 -1
  44. package/dist/map-point.js +0 -83
  45. package/dist/map-point.js.map +0 -1
  46. package/docs/map-point.md +0 -44
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { LitElement, css, html, nothing } from "lit";
7
+ import { LitElement, css, html, nothing, } from "lit";
8
8
  import { customElement, property, state } from "lit/decorators.js";
9
9
  import { iconChevronRight } from "./icons.js";
10
10
  import { tokens } from "./tokens.js";
@@ -21,6 +21,13 @@ import { tokens } from "./tokens.js";
21
21
  * bar, a status picker) keep shrink-to-fit auto-width unchanged. To make an
22
22
  * instance full-width, size the host itself: `form-select { width: 100%; }`.
23
23
  *
24
+ * Set `searchable` to replace the button trigger with an editable combobox
25
+ * that filters the predefined options by case-insensitive label infix. Typed
26
+ * text is only a query: `value` changes exclusively when an actual option is
27
+ * selected, and an uncommitted query is discarded when the list closes.
28
+ * Each option may also provide a pre-rendered `icon` and square `iconSize`;
29
+ * iconless options reserve no leading space.
30
+ *
24
31
  * @element form-select
25
32
  * @fires change - Fired with `{ value: string }` when a different option is picked.
26
33
  */
@@ -35,11 +42,25 @@ let FormSelect = class FormSelect extends LitElement {
35
42
  this.label = "";
36
43
  /** Disables the trigger, preventing the popover from opening. */
37
44
  this.disabled = false;
45
+ /**
46
+ * Enables editable, case-insensitive infix filtering by option label.
47
+ * Typed text never becomes the selected `value`.
48
+ */
49
+ this.searchable = false;
38
50
  this._open = false;
39
51
  this._activeIndex = -1;
52
+ this._query = null;
53
+ this.#listboxPointerDown = false;
54
+ this.#suppressNextBlur = false;
55
+ this.#restoringSearchFocus = false;
56
+ this.#searchSelection = null;
57
+ this.#isComposing = false;
58
+ this.#compositionJustEnded = false;
59
+ this.#compositionEndTimer = null;
60
+ this.#blurTimer = null;
40
61
  this.#onWindowMousedown = (e) => {
41
62
  if (!e.composedPath().includes(this))
42
- this._open = false;
63
+ this.#close();
43
64
  };
44
65
  }
45
66
  static { this.styles = [
@@ -78,12 +99,56 @@ let FormSelect = class FormSelect extends LitElement {
78
99
  border-color: var(--ui-primary, #4f46e5);
79
100
  box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
80
101
  }
102
+ .search-trigger {
103
+ display: flex;
104
+ align-items: center;
105
+ justify-content: space-between;
106
+ gap: 0.35rem;
107
+ width: 100%;
108
+ box-sizing: border-box;
109
+ color: var(--ui-text, #0f172a);
110
+ background: var(--ui-surface, #fff);
111
+ border: 1px solid var(--ui-border, #e2e8f0);
112
+ border-radius: var(--ui-radius-sm, 0.25rem);
113
+ cursor: text;
114
+ }
115
+ .search-trigger:hover:not(.disabled) {
116
+ background: var(--ui-surface-muted, #f8fafc);
117
+ }
118
+ .search-trigger:focus-within {
119
+ border-color: var(--ui-primary, #4f46e5);
120
+ box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
121
+ }
122
+ .search-trigger.disabled {
123
+ cursor: not-allowed;
124
+ opacity: 0.6;
125
+ }
126
+ .search-trigger.has-icon input.search-input {
127
+ padding-left: 0;
128
+ }
129
+ input.search-input {
130
+ min-width: 0;
131
+ flex: 1;
132
+ box-sizing: border-box;
133
+ padding: 0.3rem 0 0.3rem 0.5rem;
134
+ color: inherit;
135
+ background: transparent;
136
+ border: 0;
137
+ outline: 0;
138
+ font: inherit;
139
+ }
81
140
  .chevron {
82
141
  display: flex;
142
+ flex: 0 0 auto;
143
+ margin-right: 0.5rem;
83
144
  color: var(--ui-text-muted, #64748b);
145
+ pointer-events: none;
84
146
  transform: rotate(90deg);
85
147
  transition: transform 0.1s ease;
86
148
  }
149
+ button.trigger .chevron {
150
+ margin-right: 0;
151
+ }
87
152
  :host([open]) .chevron {
88
153
  transform: rotate(-90deg);
89
154
  }
@@ -95,15 +160,26 @@ let FormSelect = class FormSelect extends LitElement {
95
160
  min-width: 100%;
96
161
  max-height: 40vh;
97
162
  overflow-y: auto;
163
+ scrollbar-gutter: stable;
98
164
  margin: 2px 0 0;
99
165
  padding: 4px 0;
100
166
  list-style: none;
101
167
  white-space: nowrap;
168
+ color: var(--ui-text, #0f172a);
102
169
  background: var(--ui-surface, #fff);
103
170
  border: 1px solid var(--ui-border, #e2e8f0);
104
171
  border-radius: var(--ui-radius-sm, 0.25rem);
105
172
  box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));
106
173
  }
174
+ ul.options::-webkit-scrollbar {
175
+ width: 0.75rem;
176
+ }
177
+ ul.options::-webkit-scrollbar-thumb {
178
+ background: var(--ui-border, #e2e8f0);
179
+ border: 0.2rem solid transparent;
180
+ border-radius: 999px;
181
+ background-clip: padding-box;
182
+ }
107
183
  li {
108
184
  padding: 0.35rem 0.6rem;
109
185
  cursor: pointer;
@@ -116,34 +192,136 @@ let FormSelect = class FormSelect extends LitElement {
116
192
  font-weight: 600;
117
193
  color: var(--ui-primary, #4f46e5);
118
194
  }
195
+ .option-content {
196
+ display: inline-flex;
197
+ min-width: 0;
198
+ align-items: center;
199
+ gap: 0.4rem;
200
+ }
201
+ li .option-content {
202
+ display: flex;
203
+ width: 100%;
204
+ }
205
+ .option-icon {
206
+ display: inline-flex;
207
+ width: var(--form-select-icon-size);
208
+ height: var(--form-select-icon-size);
209
+ flex: 0 0 var(--form-select-icon-size);
210
+ align-items: center;
211
+ justify-content: center;
212
+ }
213
+ .option-icon > svg {
214
+ width: 100%;
215
+ height: 100%;
216
+ }
217
+ .selected-icon {
218
+ margin-left: 0.5rem;
219
+ }
220
+ .option-label {
221
+ min-width: 0;
222
+ overflow: hidden;
223
+ text-overflow: ellipsis;
224
+ white-space: nowrap;
225
+ }
226
+ li.no-options {
227
+ padding: 0.35rem 0.6rem;
228
+ color: var(--ui-text-muted, #64748b);
229
+ cursor: default;
230
+ font-style: italic;
231
+ }
119
232
  `,
120
233
  ]; }
234
+ #listboxPointerDown;
235
+ #suppressNextBlur;
236
+ #restoringSearchFocus;
237
+ #searchSelection;
238
+ #isComposing;
239
+ #compositionJustEnded;
240
+ #compositionEndTimer;
241
+ #blurTimer;
121
242
  disconnectedCallback() {
122
243
  super.disconnectedCallback();
123
244
  window.removeEventListener("mousedown", this.#onWindowMousedown, true);
245
+ if (this.#blurTimer)
246
+ clearTimeout(this.#blurTimer);
247
+ if (this.#compositionEndTimer)
248
+ clearTimeout(this.#compositionEndTimer);
249
+ this.#listboxPointerDown = false;
250
+ this.#suppressNextBlur = false;
251
+ this.#searchSelection = null;
252
+ this.#isComposing = false;
253
+ this.#compositionJustEnded = false;
254
+ this.#close();
124
255
  }
125
256
  updated(changed) {
126
- if (!changed.has("_open"))
257
+ if (changed.has("_open")) {
258
+ this.toggleAttribute("open", this._open);
259
+ if (this._open) {
260
+ window.addEventListener("mousedown", this.#onWindowMousedown, true);
261
+ }
262
+ else {
263
+ window.removeEventListener("mousedown", this.#onWindowMousedown, true);
264
+ }
265
+ }
266
+ if ((changed.has("disabled") && this.disabled) || changed.has("searchable")) {
267
+ this.#close();
127
268
  return;
128
- this.toggleAttribute("open", this._open);
129
- if (this._open) {
130
- window.addEventListener("mousedown", this.#onWindowMousedown, true);
131
269
  }
132
- else {
133
- window.removeEventListener("mousedown", this.#onWindowMousedown, true);
270
+ if (changed.has("options") && this._open) {
271
+ this._activeIndex = this.#initialActiveIndex();
272
+ }
273
+ else if (changed.has("value") && this._open && this._query === null) {
274
+ this._activeIndex = this.#initialActiveIndex();
275
+ }
276
+ if ((changed.has("_activeIndex") || changed.has("_query") || changed.has("options")) &&
277
+ this._open &&
278
+ this._activeIndex >= 0) {
279
+ this.renderRoot
280
+ .querySelector(`#form-select-option-${this._activeIndex}`)
281
+ ?.scrollIntoView({ block: "nearest", inline: "nearest" });
134
282
  }
135
283
  }
136
284
  #onWindowMousedown;
137
285
  #toggle() {
138
286
  if (this.disabled)
139
287
  return;
140
- this._open = !this._open;
141
- if (this._open) {
142
- this._activeIndex = Math.max(0, this.options.findIndex((o) => o.value === this.value));
143
- }
288
+ if (this._open)
289
+ this.#close();
290
+ else
291
+ this.#open();
144
292
  }
145
- #select(option) {
293
+ #open() {
294
+ if (this.disabled)
295
+ return;
296
+ this._query = null;
297
+ this._open = true;
298
+ this._activeIndex = this.#initialActiveIndex();
299
+ }
300
+ #close() {
146
301
  this._open = false;
302
+ this._query = null;
303
+ this._activeIndex = -1;
304
+ this.#searchSelection = null;
305
+ }
306
+ #initialActiveIndex() {
307
+ const options = this.#visibleOptions();
308
+ if (options.length === 0)
309
+ return -1;
310
+ if (this._query !== null)
311
+ return 0;
312
+ const selectedIndex = options.findIndex((option) => option.value === this.value);
313
+ return selectedIndex >= 0 ? selectedIndex : 0;
314
+ }
315
+ #visibleOptions() {
316
+ if (!this.searchable || this._query === null)
317
+ return this.options;
318
+ const needle = this._query.trim().toLocaleLowerCase();
319
+ if (!needle)
320
+ return this.options;
321
+ return this.options.filter((option) => option.label.toLocaleLowerCase().includes(needle));
322
+ }
323
+ #select(option) {
324
+ this.#close();
147
325
  if (option.value === this.value)
148
326
  return;
149
327
  this.value = option.value;
@@ -165,43 +343,253 @@ let FormSelect = class FormSelect extends LitElement {
165
343
  }
166
344
  else if (e.key === "Escape" && this._open) {
167
345
  e.preventDefault();
168
- this._open = false;
346
+ this.#close();
169
347
  }
170
348
  }
171
349
  #moveActive(delta) {
172
- if (this.options.length === 0)
350
+ const options = this.#visibleOptions();
351
+ if (options.length === 0)
173
352
  return;
174
- const n = this.options.length;
353
+ const n = options.length;
175
354
  this._activeIndex = (this._activeIndex + delta + n) % n;
176
355
  }
177
356
  #confirmActive() {
178
- const option = this.options[this._activeIndex];
357
+ const options = this.#visibleOptions();
358
+ const option = options[this._activeIndex] ?? options[0];
179
359
  if (option)
180
360
  this.#select(option);
181
361
  }
362
+ #onSearchFocus(e) {
363
+ if (this.disabled)
364
+ return;
365
+ if (this.#blurTimer) {
366
+ clearTimeout(this.#blurTimer);
367
+ this.#blurTimer = null;
368
+ }
369
+ if (!this._open)
370
+ this.#open();
371
+ if (!this.#restoringSearchFocus)
372
+ e.currentTarget.select();
373
+ }
374
+ #onSearchClick(e) {
375
+ if (!this._open)
376
+ this.#open();
377
+ if (this._query === null)
378
+ e.currentTarget.select();
379
+ }
380
+ #onSearchMousedown(e) {
381
+ if (e.button !== 0)
382
+ e.preventDefault();
383
+ }
384
+ #onSearchInput(e) {
385
+ this._query = e.currentTarget.value;
386
+ this._open = true;
387
+ const options = this.#visibleOptions();
388
+ this._activeIndex = options.length > 0 ? 0 : -1;
389
+ }
390
+ #onSearchKeydown(e) {
391
+ if (e.isComposing || e.keyCode === 229 || this.#isComposing || this.#compositionJustEnded) {
392
+ return;
393
+ }
394
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
395
+ e.preventDefault();
396
+ if (!this._open) {
397
+ this.#open();
398
+ return;
399
+ }
400
+ this.#moveActive(e.key === "ArrowDown" ? 1 : -1);
401
+ }
402
+ else if (e.key === "Enter" && this._open) {
403
+ e.preventDefault();
404
+ this.#confirmActive();
405
+ }
406
+ else if (e.key === "Escape" && this._open) {
407
+ e.preventDefault();
408
+ this.#close();
409
+ }
410
+ }
411
+ #onSearchBlur() {
412
+ if (this.#blurTimer)
413
+ clearTimeout(this.#blurTimer);
414
+ this.#blurTimer = setTimeout(() => {
415
+ this.#blurTimer = null;
416
+ if (!this._open)
417
+ return;
418
+ if (!this.#listboxPointerDown && !this.#suppressNextBlur)
419
+ this.#close();
420
+ });
421
+ }
422
+ #focusSearchInput(e) {
423
+ if (e.button !== 0 ||
424
+ this.disabled ||
425
+ e.composedPath()[0] instanceof HTMLInputElement) {
426
+ return;
427
+ }
428
+ e.preventDefault();
429
+ const input = this.renderRoot.querySelector("input.search-input");
430
+ if (!this._open)
431
+ this.#open();
432
+ input?.focus();
433
+ input?.select();
434
+ }
435
+ #onCompositionStart() {
436
+ if (this.#compositionEndTimer)
437
+ clearTimeout(this.#compositionEndTimer);
438
+ this.#compositionEndTimer = null;
439
+ this.#compositionJustEnded = false;
440
+ this.#isComposing = true;
441
+ }
442
+ #onCompositionEnd() {
443
+ this.#isComposing = false;
444
+ this.#compositionJustEnded = true;
445
+ if (this.#compositionEndTimer)
446
+ clearTimeout(this.#compositionEndTimer);
447
+ this.#compositionEndTimer = setTimeout(() => {
448
+ this.#compositionJustEnded = false;
449
+ this.#compositionEndTimer = null;
450
+ });
451
+ }
452
+ #onListboxMousedown(e) {
453
+ if (e.button !== 0)
454
+ return;
455
+ this.#listboxPointerDown = true;
456
+ this.#suppressNextBlur = true;
457
+ const input = this.renderRoot.querySelector("input.search-input");
458
+ this.#searchSelection = input
459
+ ? [input.selectionStart, input.selectionEnd]
460
+ : null;
461
+ window.addEventListener("mouseup", () => {
462
+ this.#listboxPointerDown = false;
463
+ if (this._open) {
464
+ const searchInput = this.renderRoot.querySelector("input.search-input");
465
+ if (searchInput) {
466
+ this.#restoringSearchFocus = true;
467
+ searchInput.focus({ preventScroll: true });
468
+ this.#restoringSearchFocus = false;
469
+ const [start, end] = this.#searchSelection ?? [null, null];
470
+ if (start !== null && end !== null)
471
+ searchInput.setSelectionRange(start, end);
472
+ }
473
+ }
474
+ this.#searchSelection = null;
475
+ setTimeout(() => {
476
+ this.#suppressNextBlur = false;
477
+ });
478
+ }, { capture: true, once: true });
479
+ }
480
+ #onOptionMousedown(e, option) {
481
+ if (e.button !== 0)
482
+ return;
483
+ const optionElement = e.currentTarget;
484
+ const listbox = optionElement.parentElement;
485
+ if (listbox) {
486
+ const scrollbarWidth = listbox.offsetWidth - listbox.clientWidth;
487
+ const bounds = listbox.getBoundingClientRect();
488
+ const isRtl = getComputedStyle(listbox).direction === "rtl";
489
+ const inScrollbarGutter = isRtl
490
+ ? e.clientX <= bounds.left + scrollbarWidth
491
+ : e.clientX >= bounds.right - scrollbarWidth;
492
+ if (scrollbarWidth > 0 && inScrollbarGutter)
493
+ return;
494
+ }
495
+ e.preventDefault();
496
+ this.#select(option);
497
+ }
498
+ #optionIconSize(option) {
499
+ const size = option.iconSize ?? 16;
500
+ return Number.isFinite(size) && size > 0 ? size : 16;
501
+ }
502
+ #renderOptionIcon(option, className = "option-icon") {
503
+ if (!option.icon)
504
+ return nothing;
505
+ return html `
506
+ <span
507
+ class=${className}
508
+ style=${`--form-select-icon-size: ${this.#optionIconSize(option)}px`}
509
+ aria-hidden="true"
510
+ >
511
+ ${option.icon}
512
+ </span>
513
+ `;
514
+ }
515
+ #renderOptionContent(option) {
516
+ return html `
517
+ <span class="option-content">
518
+ ${this.#renderOptionIcon(option)}
519
+ <span class="option-label">${option.label}</span>
520
+ </span>
521
+ `;
522
+ }
182
523
  renderListbox() {
183
524
  if (!this._open)
184
525
  return nothing;
526
+ const options = this.#visibleOptions();
185
527
  return html `
186
- <ul class="options" role="listbox">
187
- ${this.options.map((o, i) => html `
528
+ <ul
529
+ id="form-select-listbox"
530
+ class="options"
531
+ role="listbox"
532
+ @mousedown=${(e) => this.#onListboxMousedown(e)}
533
+ >
534
+ ${options.map((o, i) => html `
188
535
  <li
536
+ id=${`form-select-option-${i}`}
189
537
  role="option"
190
538
  aria-selected=${o.value === this.value}
191
539
  class=${i === this._activeIndex ? "active" : ""}
192
- @mousedown=${(e) => {
193
- e.preventDefault();
194
- this.#select(o);
195
- }}
540
+ @mousedown=${(e) => this.#onOptionMousedown(e, o)}
196
541
  >
197
- ${o.label}
542
+ ${this.#renderOptionContent(o)}
198
543
  </li>
199
544
  `)}
545
+ ${options.length === 0
546
+ ? html `<li class="no-options" role="presentation"><span role="status">No options found</span></li>`
547
+ : nothing}
200
548
  </ul>
201
549
  `;
202
550
  }
203
- render() {
204
- const current = this.options.find((o) => o.value === this.value);
551
+ renderSearchTrigger(current) {
552
+ const displayValue = this._query ?? current?.label ?? this.value;
553
+ const showSelectedIcon = this._query === null && Boolean(current?.icon);
554
+ const activeDescendant = this._open && this._activeIndex >= 0
555
+ ? `form-select-option-${this._activeIndex}`
556
+ : nothing;
557
+ return html `
558
+ <div
559
+ class="search-trigger ${this.disabled ? "disabled" : ""} ${showSelectedIcon
560
+ ? "has-icon"
561
+ : ""}"
562
+ @mousedown=${(e) => this.#focusSearchInput(e)}
563
+ >
564
+ ${showSelectedIcon && current
565
+ ? this.#renderOptionIcon(current, "option-icon selected-icon")
566
+ : nothing}
567
+ <input
568
+ type="text"
569
+ class="search-input"
570
+ role="combobox"
571
+ aria-autocomplete="list"
572
+ aria-expanded=${this._open}
573
+ aria-controls="form-select-listbox"
574
+ aria-activedescendant=${activeDescendant}
575
+ aria-label=${this.label || "Select an option"}
576
+ autocomplete="off"
577
+ ?disabled=${this.disabled}
578
+ .value=${displayValue}
579
+ @mousedown=${(e) => this.#onSearchMousedown(e)}
580
+ @focus=${(e) => this.#onSearchFocus(e)}
581
+ @click=${(e) => this.#onSearchClick(e)}
582
+ @input=${(e) => this.#onSearchInput(e)}
583
+ @compositionstart=${() => this.#onCompositionStart()}
584
+ @compositionend=${() => this.#onCompositionEnd()}
585
+ @keydown=${(e) => this.#onSearchKeydown(e)}
586
+ @blur=${() => this.#onSearchBlur()}
587
+ />
588
+ <span class="chevron">${iconChevronRight(14)}</span>
589
+ </div>
590
+ `;
591
+ }
592
+ renderButtonTrigger(current) {
205
593
  return html `
206
594
  <button
207
595
  type="button"
@@ -213,9 +601,19 @@ let FormSelect = class FormSelect extends LitElement {
213
601
  @click=${() => this.#toggle()}
214
602
  @keydown=${(e) => this.#onTriggerKeydown(e)}
215
603
  >
216
- <span>${current?.label ?? this.value}</span>
604
+ ${current
605
+ ? this.#renderOptionContent(current)
606
+ : html `<span class="option-label">${this.value}</span>`}
217
607
  <span class="chevron">${iconChevronRight(14)}</span>
218
608
  </button>
609
+ `;
610
+ }
611
+ render() {
612
+ const current = this.options.find((o) => o.value === this.value);
613
+ return html `
614
+ ${this.searchable
615
+ ? this.renderSearchTrigger(current)
616
+ : this.renderButtonTrigger(current)}
219
617
  ${this.renderListbox()}
220
618
  `;
221
619
  }
@@ -232,12 +630,18 @@ __decorate([
232
630
  __decorate([
233
631
  property({ type: Boolean })
234
632
  ], FormSelect.prototype, "disabled", void 0);
633
+ __decorate([
634
+ property({ type: Boolean, reflect: true })
635
+ ], FormSelect.prototype, "searchable", void 0);
235
636
  __decorate([
236
637
  state()
237
638
  ], FormSelect.prototype, "_open", void 0);
238
639
  __decorate([
239
640
  state()
240
641
  ], FormSelect.prototype, "_activeIndex", void 0);
642
+ __decorate([
643
+ state()
644
+ ], FormSelect.prototype, "_query", void 0);
241
645
  FormSelect = __decorate([
242
646
  customElement("form-select")
243
647
  ], FormSelect);