@sveltia/ui 0.72.2 → 0.73.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 (89) hide show
  1. package/dist/components/alert/alert.svelte +29 -5
  2. package/dist/components/alert/alert.svelte.d.ts +8 -4
  3. package/dist/components/alert/infobar.svelte +21 -5
  4. package/dist/components/alert/infobar.svelte.d.ts +10 -4
  5. package/dist/components/button/button.svelte +5 -1
  6. package/dist/components/button/select-button-group.svelte +1 -1
  7. package/dist/components/calendar/calendar.d.ts +1 -4
  8. package/dist/components/calendar/calendar.js +17 -0
  9. package/dist/components/calendar/calendar.svelte +67 -11
  10. package/dist/components/checkbox/checkbox-group.svelte +3 -1
  11. package/dist/components/checkbox/checkbox.svelte +3 -1
  12. package/dist/components/dialog/dialog.svelte +14 -2
  13. package/dist/components/dialog/prompt-dialog.svelte +9 -2
  14. package/dist/components/dialog/prompt-dialog.svelte.d.ts +4 -2
  15. package/dist/components/disclosure/disclosure.svelte +2 -1
  16. package/dist/components/drawer/drawer.svelte +28 -3
  17. package/dist/components/drawer/drawer.svelte.d.ts +16 -2
  18. package/dist/components/grid/grid-body.svelte +3 -1
  19. package/dist/components/grid/grid-foot.svelte +3 -1
  20. package/dist/components/grid/grid-head.svelte +3 -1
  21. package/dist/components/listbox/option-group.svelte +2 -1
  22. package/dist/components/listbox/option.svelte +4 -0
  23. package/dist/components/menu/menu-item-group.svelte +3 -1
  24. package/dist/components/radio/radio.svelte +21 -3
  25. package/dist/components/radio/radio.svelte.d.ts +12 -2
  26. package/dist/components/resizable-pane/resizable-handle.svelte +12 -0
  27. package/dist/components/select/combobox.svelte +69 -1
  28. package/dist/components/select/select-tags.svelte +34 -23
  29. package/dist/components/slider/slider.d.ts +6 -0
  30. package/dist/components/slider/slider.js +40 -0
  31. package/dist/components/slider/slider.svelte +45 -11
  32. package/dist/components/slider/slider.svelte.d.ts +14 -2
  33. package/dist/components/switch/switch.svelte +1 -1
  34. package/dist/components/table/table-body.svelte +3 -1
  35. package/dist/components/table/table-foot.svelte +3 -1
  36. package/dist/components/table/table-head.svelte +3 -1
  37. package/dist/components/text-editor/code-editor.svelte +22 -1
  38. package/dist/components/text-editor/code-editor.svelte.d.ts +28 -0
  39. package/dist/components/text-editor/shiki/version.d.ts +1 -1
  40. package/dist/components/text-editor/shiki/version.js +1 -1
  41. package/dist/components/text-editor/text-editor.svelte +23 -0
  42. package/dist/components/text-editor/text-editor.svelte.d.ts +28 -0
  43. package/dist/components/text-field/number-input.svelte +7 -17
  44. package/dist/components/text-field/search-bar.svelte +1 -0
  45. package/dist/components/text-field/text-input.svelte +1 -1
  46. package/dist/components/toast/toast.svelte +58 -4
  47. package/dist/components/toast/toast.svelte.d.ts +4 -2
  48. package/dist/components/util/app-shell.svelte +289 -5
  49. package/dist/components/util/popup.svelte +1 -1
  50. package/dist/locales/ar.yaml +20 -0
  51. package/dist/locales/bg.yaml +20 -0
  52. package/dist/locales/ca.yaml +20 -0
  53. package/dist/locales/cs.yaml +20 -0
  54. package/dist/locales/da.yaml +20 -0
  55. package/dist/locales/de.yaml +20 -0
  56. package/dist/locales/el.yaml +20 -0
  57. package/dist/locales/en-CA.yaml +20 -0
  58. package/dist/locales/en-GB.yaml +20 -0
  59. package/dist/locales/en-US.yaml +20 -0
  60. package/dist/locales/es-CO.yaml +20 -0
  61. package/dist/locales/fa.yaml +20 -0
  62. package/dist/locales/fi.yaml +20 -0
  63. package/dist/locales/fr.yaml +20 -0
  64. package/dist/locales/hr.yaml +20 -0
  65. package/dist/locales/it.yaml +20 -0
  66. package/dist/locales/ja.yaml +20 -0
  67. package/dist/locales/ko.yaml +20 -0
  68. package/dist/locales/nl.yaml +20 -0
  69. package/dist/locales/pl.yaml +20 -0
  70. package/dist/locales/pt-BR.yaml +20 -0
  71. package/dist/locales/pt-PT.yaml +20 -0
  72. package/dist/locales/ru.yaml +20 -0
  73. package/dist/locales/sv.yaml +20 -0
  74. package/dist/locales/tr.yaml +20 -0
  75. package/dist/locales/uk.yaml +20 -0
  76. package/dist/locales/vi.yaml +20 -0
  77. package/dist/locales/zh-CN.yaml +20 -0
  78. package/dist/locales/zh-TW.yaml +20 -0
  79. package/dist/services/group.svelte.js +60 -0
  80. package/dist/services/popup.svelte.js +24 -1
  81. package/dist/services/select.svelte.d.ts +5 -0
  82. package/dist/services/select.svelte.js +8 -0
  83. package/dist/services/type-ahead.d.ts +26 -0
  84. package/dist/services/type-ahead.js +81 -0
  85. package/dist/styles/core.scss +14 -3
  86. package/dist/styles/variables.scss +118 -1
  87. package/dist/typedefs.d.ts +7 -1
  88. package/dist/typedefs.js +4 -1
  89. package/package.json +3 -3
@@ -18,6 +18,26 @@ expand: Näytä
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Hylkää
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Virhe
24
+ warning: Varoitus
25
+ info: Tiedoksi
26
+ success: Onnistui
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: laajennettava osio
31
+ option_group: vaihtoehtoryhmä
32
+ menu_item_group: valikkokohtien ryhmä
33
+ checkbox_group: valintaruuturyhmä
34
+ table_head: taulukon otsikko
35
+ table_body: taulukon sisältö
36
+ table_foot: taulukon alatunniste
37
+ grid_head: ruudukon otsikko
38
+ grid_body: ruudukon sisältö
39
+ grid_foot: ruudukon alatunniste
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Emoji-ehdotukset
23
43
 
@@ -18,6 +18,26 @@ expand: Développer
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Ignorer
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Erreur
24
+ warning: Avertissement
25
+ info: Information
26
+ success: Succès
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: section dépliable
31
+ option_group: groupe d’options
32
+ menu_item_group: groupe d’éléments de menu
33
+ checkbox_group: groupe de cases à cocher
34
+ table_head: en-tête de tableau
35
+ table_body: corps de tableau
36
+ table_foot: pied de tableau
37
+ grid_head: en-tête de grille
38
+ grid_body: corps de grille
39
+ grid_foot: pied de grille
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Suggestions d’émojis
23
43
 
@@ -18,6 +18,26 @@ expand: Proširi
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Odbaci
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Pogreška
24
+ warning: Upozorenje
25
+ info: Informacija
26
+ success: Uspjeh
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: proširivi odjeljak
31
+ option_group: grupa opcija
32
+ menu_item_group: grupa stavki izbornika
33
+ checkbox_group: grupa potvrdnih okvira
34
+ table_head: zaglavlje tablice
35
+ table_body: tijelo tablice
36
+ table_foot: podnožje tablice
37
+ grid_head: zaglavlje rešetke
38
+ grid_body: tijelo rešetke
39
+ grid_foot: podnožje rešetke
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Prijedlozi emojija
23
43
 
@@ -18,6 +18,26 @@ expand: Espandi
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Ignora
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Errore
24
+ warning: Avviso
25
+ info: Informazione
26
+ success: Operazione riuscita
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: sezione espandibile
31
+ option_group: gruppo di opzioni
32
+ menu_item_group: gruppo di voci di menu
33
+ checkbox_group: gruppo di caselle di controllo
34
+ table_head: intestazione tabella
35
+ table_body: corpo tabella
36
+ table_foot: piè di tabella
37
+ grid_head: intestazione griglia
38
+ grid_body: corpo griglia
39
+ grid_foot: piè di griglia
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Suggerimenti Emoji
23
43
 
@@ -18,6 +18,26 @@ expand: 広げる
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: 閉じる
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: エラー
24
+ warning: 警告
25
+ info: 情報
26
+ success: 成功
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: 折りたたみセクション
31
+ option_group: オプショングループ
32
+ menu_item_group: メニュー項目グループ
33
+ checkbox_group: チェックボックスグループ
34
+ table_head: テーブルヘッダー
35
+ table_body: テーブル本体
36
+ table_foot: テーブルフッター
37
+ grid_head: グリッドヘッダー
38
+ grid_body: グリッド本体
39
+ grid_foot: グリッドフッター
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: 絵文字の候補
23
43
 
@@ -18,6 +18,26 @@ expand: 펼치기
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: 닫기
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: 오류
24
+ warning: 경고
25
+ info: 정보
26
+ success: 성공
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: 펼치기 섹션
31
+ option_group: 옵션 그룹
32
+ menu_item_group: 메뉴 항목 그룹
33
+ checkbox_group: 체크박스 그룹
34
+ table_head: 표 머리글
35
+ table_body: 표 본문
36
+ table_foot: 표 바닥글
37
+ grid_head: 그리드 머리글
38
+ grid_body: 그리드 본문
39
+ grid_foot: 그리드 바닥글
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: 이모지 제안
23
43
 
@@ -18,6 +18,26 @@ expand: Uitvouwen
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Sluiten
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Fout
24
+ warning: Waarschuwing
25
+ info: Informatie
26
+ success: Gelukt
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: uitklapbare sectie
31
+ option_group: optiegroep
32
+ menu_item_group: menu-itemgroep
33
+ checkbox_group: selectievakjesgroep
34
+ table_head: tabelkop
35
+ table_body: tabelinhoud
36
+ table_foot: tabelvoet
37
+ grid_head: rasterkop
38
+ grid_body: rasterinhoud
39
+ grid_foot: rastervoet
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Emoji-suggesties
23
43
 
@@ -18,6 +18,26 @@ expand: Rozwiń
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Odrzuć
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Błąd
24
+ warning: Ostrzeżenie
25
+ info: Informacja
26
+ success: Sukces
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: sekcja rozwijana
31
+ option_group: grupa opcji
32
+ menu_item_group: grupa pozycji menu
33
+ checkbox_group: grupa pól wyboru
34
+ table_head: nagłówek tabeli
35
+ table_body: treść tabeli
36
+ table_foot: stopka tabeli
37
+ grid_head: nagłówek siatki
38
+ grid_body: treść siatki
39
+ grid_foot: stopka siatki
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Propozycje emoji
23
43
 
@@ -18,6 +18,26 @@ expand: Expandir
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Dispensar
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Erro
24
+ warning: Aviso
25
+ info: Informação
26
+ success: Sucesso
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: seção expansível
31
+ option_group: grupo de opções
32
+ menu_item_group: grupo de itens de menu
33
+ checkbox_group: grupo de caixas de seleção
34
+ table_head: cabeçalho da tabela
35
+ table_body: corpo da tabela
36
+ table_foot: rodapé da tabela
37
+ grid_head: cabeçalho da grade
38
+ grid_body: corpo da grade
39
+ grid_foot: rodapé da grade
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Sugestões de emoji
23
43
 
@@ -18,6 +18,26 @@ expand: Expandir
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Dispensar
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Erro
24
+ warning: Aviso
25
+ info: Informação
26
+ success: Sucesso
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: secção expansível
31
+ option_group: grupo de opções
32
+ menu_item_group: grupo de itens de menu
33
+ checkbox_group: grupo de caixas de verificação
34
+ table_head: cabeçalho da tabela
35
+ table_body: corpo da tabela
36
+ table_foot: rodapé da tabela
37
+ grid_head: cabeçalho da grelha
38
+ grid_body: corpo da grelha
39
+ grid_foot: rodapé da grelha
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Sugestões de emoji
23
43
 
@@ -18,6 +18,26 @@ expand: Развернуть
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Отклонить
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Ошибка
24
+ warning: Предупреждение
25
+ info: Информация
26
+ success: Успешно
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: раскрывающийся раздел
31
+ option_group: группа вариантов
32
+ menu_item_group: группа пунктов меню
33
+ checkbox_group: группа флажков
34
+ table_head: заголовок таблицы
35
+ table_body: тело таблицы
36
+ table_foot: нижняя часть таблицы
37
+ grid_head: заголовок сетки
38
+ grid_body: тело сетки
39
+ grid_foot: нижняя часть сетки
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Предложения эмодзи
23
43
 
@@ -18,6 +18,26 @@ expand: Fäll ut
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Avfärda
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Fel
24
+ warning: Varning
25
+ info: Information
26
+ success: Lyckades
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: utfällbar sektion
31
+ option_group: alternativgrupp
32
+ menu_item_group: grupp med menyalternativ
33
+ checkbox_group: kryssrutegrupp
34
+ table_head: tabellhuvud
35
+ table_body: tabellkropp
36
+ table_foot: tabellfot
37
+ grid_head: rutnätshuvud
38
+ grid_body: rutnätskropp
39
+ grid_foot: rutnätsfot
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Emojiförslag
23
43
 
@@ -18,6 +18,26 @@ expand: Genişlet
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Kapat
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Hata
24
+ warning: Uyarı
25
+ info: Bilgi
26
+ success: Başarılı
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: genişletilebilir bölüm
31
+ option_group: seçenek grubu
32
+ menu_item_group: menü öğesi grubu
33
+ checkbox_group: onay kutusu grubu
34
+ table_head: tablo başlığı
35
+ table_body: tablo gövdesi
36
+ table_foot: tablo altbilgisi
37
+ grid_head: ızgara başlığı
38
+ grid_body: ızgara gövdesi
39
+ grid_foot: ızgara altbilgisi
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Emoji Önerileri
23
43
 
@@ -18,6 +18,26 @@ expand: Розгорнути
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Відхилити
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Помилка
24
+ warning: Попередження
25
+ info: Інформація
26
+ success: Успішно
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: розгортаний розділ
31
+ option_group: група варіантів
32
+ menu_item_group: група пунктів меню
33
+ checkbox_group: група прапорців
34
+ table_head: заголовок таблиці
35
+ table_body: тіло таблиці
36
+ table_foot: нижня частина таблиці
37
+ grid_head: заголовок сітки
38
+ grid_body: тіло сітки
39
+ grid_foot: нижня частина сітки
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Пропозиції емодзі
23
43
 
@@ -18,6 +18,26 @@ expand: Mở rộng
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: Đóng
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: Lỗi
24
+ warning: Cảnh báo
25
+ info: Thông tin
26
+ success: Thành công
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: phần có thể mở rộng
31
+ option_group: nhóm tùy chọn
32
+ menu_item_group: nhóm mục menu
33
+ checkbox_group: nhóm hộp kiểm
34
+ table_head: đầu bảng
35
+ table_body: thân bảng
36
+ table_foot: chân bảng
37
+ grid_head: đầu lưới
38
+ grid_body: thân lưới
39
+ grid_foot: chân lưới
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: Gợi ý biểu tượng cảm xúc
23
43
 
@@ -18,6 +18,26 @@ expand: 展开
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: 关闭
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: 错误
24
+ warning: 警告
25
+ info: 信息
26
+ success: 成功
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: 可展开区域
31
+ option_group: 选项组
32
+ menu_item_group: 菜单项组
33
+ checkbox_group: 复选框组
34
+ table_head: 表头
35
+ table_body: 表体
36
+ table_foot: 表尾
37
+ grid_head: 网格表头
38
+ grid_body: 网格表体
39
+ grid_foot: 网格表尾
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: 表情符号建议
23
43
 
@@ -18,6 +18,26 @@ expand: 展開
18
18
  # Infobar/toast dismiss button label
19
19
  dismiss: 關閉
20
20
 
21
+ # Alert & infobar status, read out by screen readers before the message (visually hidden)
22
+ alert:
23
+ error: 錯誤
24
+ warning: 警告
25
+ info: 資訊
26
+ success: 成功
27
+
28
+ # Role descriptions, read out by screen readers in place of the generic “group” role
29
+ role_descriptions:
30
+ disclosure: 可展開區塊
31
+ option_group: 選項群組
32
+ menu_item_group: 選單項目群組
33
+ checkbox_group: 核取方塊群組
34
+ table_head: 表格標頭
35
+ table_body: 表格內容
36
+ table_foot: 表格頁尾
37
+ grid_head: 網格標頭
38
+ grid_body: 網格內容
39
+ grid_foot: 網格頁尾
40
+
21
41
  # Emoji suggestion listbox aria-label, shared by the text fields and the text editor
22
42
  emoji_suggestions: 表情符號建議
23
43
 
@@ -2,6 +2,7 @@ import { isRTL } from '@sveltia/i18n';
2
2
  import { generateElementId } from '@sveltia/utils/element';
3
3
  import { sleep } from '@sveltia/utils/misc';
4
4
  import { getSelectedItemDetail } from './select.svelte.js';
5
+ import { findTypeAheadMatch, TypeAhead } from './type-ahead.js';
5
6
 
6
7
  /**
7
8
  * @import { Attachment } from 'svelte/attachments';
@@ -200,6 +201,12 @@ export class Group {
200
201
  */
201
202
  #hiddenState = new WeakMap();
202
203
 
204
+ /**
205
+ * Keystroke buffer for type-ahead.
206
+ * @type {TypeAhead}
207
+ */
208
+ #typeAhead = new TypeAhead();
209
+
203
210
  /**
204
211
  * Get the normalized value a member is searched by, computing it only when the underlying raw
205
212
  * value has changed since the last call.
@@ -802,6 +809,58 @@ export class Group {
802
809
  event.preventDefault();
803
810
  }
804
811
 
812
+ // Home, End and type-ahead only apply to keystrokes on the group itself or on a member. A text
813
+ // field nested in a menu, say, keeps them for its own caret and content.
814
+ const fromMember = target === this.parent || target.matches(this.selector);
815
+
816
+ // Home and End jump to the ends of the group, in any layout
817
+ if (key === 'Home' || key === 'End') {
818
+ if (!fromMember) {
819
+ return;
820
+ }
821
+
822
+ event.preventDefault();
823
+
824
+ const newTarget = activeMembers[key === 'Home' ? 0 : activeMembers.length - 1];
825
+
826
+ if (newTarget && newTarget !== currentTarget) {
827
+ this.selectTarget(event, newTarget);
828
+ }
829
+
830
+ return;
831
+ }
832
+
833
+ // Type-ahead: a printable character moves to the next member whose label starts with what has
834
+ // been typed so far, as in a native `<select>` and per the Listbox and Menu patterns. This goes
835
+ // by the visible label, not the search value, which may hold synonyms for filtering — and by
836
+ // the label element rather than the whole text, which would take in icon ligature names.
837
+ if (key.length === 1 && key !== ' ' && fromMember && (this.role === 'listbox' || isMenu)) {
838
+ // Swallow the key whether or not it matches, as a native `<select>` does. Left to the
839
+ // browser, a printable key on a non-editable element starts Firefox’s find-as-you-type.
840
+ event.preventDefault();
841
+
842
+ const labels = activeMembers.map((member) =>
843
+ normalize(
844
+ member.dataset.label ??
845
+ member.querySelector('.label')?.textContent ??
846
+ member.textContent ??
847
+ '',
848
+ ),
849
+ );
850
+
851
+ const index = findTypeAheadMatch(
852
+ labels,
853
+ this.#typeAhead.push(key),
854
+ currentTarget ? activeMembers.indexOf(currentTarget) : -1,
855
+ );
856
+
857
+ if (index !== -1 && activeMembers[index] !== currentTarget) {
858
+ this.selectTarget(event, activeMembers[index]);
859
+ }
860
+
861
+ return;
862
+ }
863
+
805
864
  if (key === 'Enter') {
806
865
  currentTarget?.click(); // Also close the popup if needed
807
866
 
@@ -929,6 +988,7 @@ export class Group {
929
988
  * Clean up event listeners.
930
989
  */
931
990
  destroy() {
991
+ this.#typeAhead.reset();
932
992
  this.observer.disconnect();
933
993
  this.parent.removeEventListener('click', this._onClick);
934
994
  this.parent.removeEventListener('keydown', this._onKeyDown);
@@ -115,10 +115,33 @@ class Popup {
115
115
  const { key, ctrlKey, metaKey, shiftKey, altKey } = event;
116
116
  const hasModifier = shiftKey || altKey || ctrlKey || metaKey;
117
117
 
118
- if (!this.isDisabled && !this.isReadOnly && ['Enter', ' '].includes(key) && !hasModifier) {
118
+ if (this.isDisabled || this.isReadOnly) {
119
+ return;
120
+ }
121
+
122
+ if (['Enter', ' '].includes(key) && !hasModifier) {
119
123
  event.preventDefault();
120
124
  event.stopPropagation();
121
125
  this.open = !this.open;
126
+
127
+ return;
128
+ }
129
+
130
+ // The arrow keys open a listbox or menu, the way they do a native `<select>`; Alt+Down is the
131
+ // combobox convention (APG Select-Only Combobox, Menu Button). They never close one: inside
132
+ // the popup they belong to the list. A menu item that opens a submenu is left alone: there
133
+ // the arrows move through the parent menu, and the submenu opens with the inline arrow.
134
+ if (
135
+ ['ArrowDown', 'ArrowUp'].includes(key) &&
136
+ !(shiftKey || ctrlKey || metaKey) &&
137
+ (!altKey || key === 'ArrowDown') &&
138
+ ['listbox', 'menu'].includes(anchorElement.getAttribute('aria-haspopup') ?? '') &&
139
+ !anchorElement.matches('[role^="menuitem"]') &&
140
+ !this.open
141
+ ) {
142
+ event.preventDefault();
143
+ event.stopPropagation();
144
+ this.open = true;
122
145
  }
123
146
  });
124
147
 
@@ -20,6 +20,11 @@ export class OptionRegistry {
20
20
  * @returns {number} Count.
21
21
  */
22
22
  get count(): number;
23
+ /**
24
+ * Registered options, in registration order.
25
+ * @returns {OptionEntry[]} Entries.
26
+ */
27
+ get entries(): OptionEntry[];
23
28
  /**
24
29
  * The option that is currently marked as selected, if any.
25
30
  * @returns {OptionEntry | undefined} Matching option.
@@ -42,6 +42,14 @@ export class OptionRegistry {
42
42
  return this.#entries.length;
43
43
  }
44
44
 
45
+ /**
46
+ * Registered options, in registration order.
47
+ * @returns {OptionEntry[]} Entries.
48
+ */
49
+ get entries() {
50
+ return this.#entries;
51
+ }
52
+
45
53
  /**
46
54
  * The option that is currently marked as selected, if any.
47
55
  * @returns {OptionEntry | undefined} Matching option.
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Type-ahead support shared by the composite widgets: the collapsed select-only combobox, and the
3
+ * listbox and menu groups.
4
+ */
5
+ /**
6
+ * How long, in milliseconds, successive keystrokes keep adding up to one type-ahead prefix.
7
+ */
8
+ export const TYPE_AHEAD_TIMEOUT: 500;
9
+ /**
10
+ * Keystroke buffer behind type-ahead: printable keys typed in quick succession make up a prefix,
11
+ * which is dropped again after a short pause.
12
+ */
13
+ export class TypeAhead {
14
+ /**
15
+ * Add a keystroke to the prefix.
16
+ * @param {string} key Printable key.
17
+ * @returns {string} Current prefix.
18
+ */
19
+ push(key: string): string;
20
+ /**
21
+ * Drop the prefix.
22
+ */
23
+ reset(): void;
24
+ #private;
25
+ }
26
+ export function findTypeAheadMatch(labels: string[], prefix: string, currentIndex: number): number;