@lilydesignsystem/svelte-headless 0.1.0 → 0.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.
Files changed (157) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/components/AotearoaNationalHealthIndexInput/AotearoaNationalHealthIndexInput.svelte +55 -0
  3. package/dist/components/AotearoaNationalHealthIndexInput/AotearoaNationalHealthIndexInput.svelte.d.ts +10 -0
  4. package/dist/components/AotearoaNationalHealthIndexView/AotearoaNationalHealthIndexView.svelte +40 -0
  5. package/dist/components/AotearoaNationalHealthIndexView/AotearoaNationalHealthIndexView.svelte.d.ts +8 -0
  6. package/dist/components/AreaChart/AreaChart.svelte +42 -3
  7. package/dist/components/AreaChart/AreaChart.svelte.d.ts +4 -0
  8. package/dist/components/ArgentinaCodigoUnicoDeIdentificacionLaboralInput/ArgentinaCodigoUnicoDeIdentificacionLaboralInput.svelte +55 -0
  9. package/dist/components/ArgentinaCodigoUnicoDeIdentificacionLaboralInput/ArgentinaCodigoUnicoDeIdentificacionLaboralInput.svelte.d.ts +10 -0
  10. package/dist/components/ArgentinaCodigoUnicoDeIdentificacionLaboralView/ArgentinaCodigoUnicoDeIdentificacionLaboralView.svelte +40 -0
  11. package/dist/components/ArgentinaCodigoUnicoDeIdentificacionLaboralView/ArgentinaCodigoUnicoDeIdentificacionLaboralView.svelte.d.ts +8 -0
  12. package/dist/components/BarChart/BarChart.svelte +42 -3
  13. package/dist/components/BarChart/BarChart.svelte.d.ts +4 -0
  14. package/dist/components/BharatAadhaarInput/BharatAadhaarInput.svelte +55 -0
  15. package/dist/components/BharatAadhaarInput/BharatAadhaarInput.svelte.d.ts +10 -0
  16. package/dist/components/BharatAadhaarView/BharatAadhaarView.svelte +40 -0
  17. package/dist/components/BharatAadhaarView/BharatAadhaarView.svelte.d.ts +8 -0
  18. package/dist/components/BrasilCartaoNacionalDeSaudeInput/BrasilCartaoNacionalDeSaudeInput.svelte +55 -0
  19. package/dist/components/BrasilCartaoNacionalDeSaudeInput/BrasilCartaoNacionalDeSaudeInput.svelte.d.ts +10 -0
  20. package/dist/components/BrasilCartaoNacionalDeSaudeView/BrasilCartaoNacionalDeSaudeView.svelte +40 -0
  21. package/dist/components/BrasilCartaoNacionalDeSaudeView/BrasilCartaoNacionalDeSaudeView.svelte.d.ts +8 -0
  22. package/dist/components/CalendarDayTable/CalendarDayTable.svelte +71 -0
  23. package/dist/components/CalendarDayTable/CalendarDayTable.svelte.d.ts +13 -0
  24. package/dist/components/CalendarMonthTable/CalendarMonthTable.svelte +71 -0
  25. package/dist/components/CalendarMonthTable/CalendarMonthTable.svelte.d.ts +13 -0
  26. package/dist/components/CalendarWeekTable/CalendarWeekTable.svelte +71 -0
  27. package/dist/components/CalendarWeekTable/CalendarWeekTable.svelte.d.ts +13 -0
  28. package/dist/components/CalendarYearTable/CalendarYearTable.svelte +71 -0
  29. package/dist/components/CalendarYearTable/CalendarYearTable.svelte.d.ts +13 -0
  30. package/dist/components/CanadaSocialInsuranceNumberInput/CanadaSocialInsuranceNumberInput.svelte +55 -0
  31. package/dist/components/CanadaSocialInsuranceNumberInput/CanadaSocialInsuranceNumberInput.svelte.d.ts +10 -0
  32. package/dist/components/CanadaSocialInsuranceNumberView/CanadaSocialInsuranceNumberView.svelte +40 -0
  33. package/dist/components/CanadaSocialInsuranceNumberView/CanadaSocialInsuranceNumberView.svelte.d.ts +8 -0
  34. package/dist/components/ChileRolUnicoNacionalInput/ChileRolUnicoNacionalInput.svelte +55 -0
  35. package/dist/components/ChileRolUnicoNacionalInput/ChileRolUnicoNacionalInput.svelte.d.ts +10 -0
  36. package/dist/components/ChileRolUnicoNacionalView/ChileRolUnicoNacionalView.svelte +40 -0
  37. package/dist/components/ChileRolUnicoNacionalView/ChileRolUnicoNacionalView.svelte.d.ts +8 -0
  38. package/dist/components/ColumnChart/ColumnChart.svelte +42 -3
  39. package/dist/components/ColumnChart/ColumnChart.svelte.d.ts +4 -0
  40. package/dist/components/EmptyState/EmptyState.svelte +47 -0
  41. package/dist/components/EmptyState/EmptyState.svelte.d.ts +11 -0
  42. package/dist/components/FileTree/FileTree.svelte +210 -0
  43. package/dist/components/FileTree/FileTree.svelte.d.ts +11 -0
  44. package/dist/components/GanttTable/GanttTable.svelte +5 -5
  45. package/dist/components/GanttTableTD/GanttTableTD.svelte +2 -2
  46. package/dist/components/GanttTableTH/GanttTableTH.svelte +3 -3
  47. package/dist/components/GanttTableTbody/GanttTableTbody.svelte +5 -5
  48. package/dist/components/GanttTableTbody/GanttTableTbody.svelte.d.ts +1 -1
  49. package/dist/components/GanttTableTfoot/GanttTableTfoot.svelte +5 -5
  50. package/dist/components/GanttTableTfoot/GanttTableTfoot.svelte.d.ts +1 -1
  51. package/dist/components/GanttTableThead/GanttTableThead.svelte +4 -4
  52. package/dist/components/GanttTableThead/GanttTableThead.svelte.d.ts +1 -1
  53. package/dist/components/GanttTableTr/GanttTableTr.svelte +8 -8
  54. package/dist/components/GaugeChart/GaugeChart.svelte +63 -0
  55. package/dist/components/GaugeChart/GaugeChart.svelte.d.ts +13 -0
  56. package/dist/components/HangukJuminDeungnokBeonhoInput/HangukJuminDeungnokBeonhoInput.svelte +55 -0
  57. package/dist/components/HangukJuminDeungnokBeonhoInput/HangukJuminDeungnokBeonhoInput.svelte.d.ts +10 -0
  58. package/dist/components/HangukJuminDeungnokBeonhoView/HangukJuminDeungnokBeonhoView.svelte +40 -0
  59. package/dist/components/HangukJuminDeungnokBeonhoView/HangukJuminDeungnokBeonhoView.svelte.d.ts +8 -0
  60. package/dist/components/HeatmapChart/HeatmapChart.svelte +63 -0
  61. package/dist/components/HeatmapChart/HeatmapChart.svelte.d.ts +13 -0
  62. package/dist/components/IconButton/IconButton.svelte +17 -2
  63. package/dist/components/IconButton/IconButton.svelte.d.ts +5 -1
  64. package/dist/components/IndonesiaNomorIndukKependudukanInput/IndonesiaNomorIndukKependudukanInput.svelte +55 -0
  65. package/dist/components/IndonesiaNomorIndukKependudukanInput/IndonesiaNomorIndukKependudukanInput.svelte.d.ts +10 -0
  66. package/dist/components/IndonesiaNomorIndukKependudukanView/IndonesiaNomorIndukKependudukanView.svelte +40 -0
  67. package/dist/components/IndonesiaNomorIndukKependudukanView/IndonesiaNomorIndukKependudukanView.svelte.d.ts +8 -0
  68. package/dist/components/KbdShortcut/KbdShortcut.svelte +49 -0
  69. package/dist/components/KbdShortcut/KbdShortcut.svelte.d.ts +12 -0
  70. package/dist/components/LineChart/LineChart.svelte +42 -3
  71. package/dist/components/LineChart/LineChart.svelte.d.ts +4 -0
  72. package/dist/components/Listbox/Listbox.svelte +213 -34
  73. package/dist/components/Listbox/Listbox.svelte.d.ts +24 -1
  74. package/dist/components/LuxembourgMatriculeInput/LuxembourgMatriculeInput.svelte +55 -0
  75. package/dist/components/LuxembourgMatriculeInput/LuxembourgMatriculeInput.svelte.d.ts +10 -0
  76. package/dist/components/LuxembourgMatriculeView/LuxembourgMatriculeView.svelte +40 -0
  77. package/dist/components/LuxembourgMatriculeView/LuxembourgMatriculeView.svelte.d.ts +8 -0
  78. package/dist/components/MagyarorszagTajSzamInput/MagyarorszagTajSzamInput.svelte +55 -0
  79. package/dist/components/MagyarorszagTajSzamInput/MagyarorszagTajSzamInput.svelte.d.ts +10 -0
  80. package/dist/components/MagyarorszagTajSzamView/MagyarorszagTajSzamView.svelte +40 -0
  81. package/dist/components/MagyarorszagTajSzamView/MagyarorszagTajSzamView.svelte.d.ts +8 -0
  82. package/dist/components/MexicoClaveUnicaDeRegistroDePoblacionInput/MexicoClaveUnicaDeRegistroDePoblacionInput.svelte +55 -0
  83. package/dist/components/MexicoClaveUnicaDeRegistroDePoblacionInput/MexicoClaveUnicaDeRegistroDePoblacionInput.svelte.d.ts +10 -0
  84. package/dist/components/MexicoClaveUnicaDeRegistroDePoblacionView/MexicoClaveUnicaDeRegistroDePoblacionView.svelte +40 -0
  85. package/dist/components/MexicoClaveUnicaDeRegistroDePoblacionView/MexicoClaveUnicaDeRegistroDePoblacionView.svelte.d.ts +8 -0
  86. package/dist/components/MisrAlRaqmAlQawmiInput/MisrAlRaqmAlQawmiInput.svelte +55 -0
  87. package/dist/components/MisrAlRaqmAlQawmiInput/MisrAlRaqmAlQawmiInput.svelte.d.ts +10 -0
  88. package/dist/components/MisrAlRaqmAlQawmiView/MisrAlRaqmAlQawmiView.svelte +40 -0
  89. package/dist/components/MisrAlRaqmAlQawmiView/MisrAlRaqmAlQawmiView.svelte.d.ts +8 -0
  90. package/dist/components/MultiSelect/MultiSelect.svelte +70 -0
  91. package/dist/components/MultiSelect/MultiSelect.svelte.d.ts +19 -0
  92. package/dist/components/MultiSelectWithExtras/MultiSelectWithExtras.svelte +80 -0
  93. package/dist/components/MultiSelectWithExtras/MultiSelectWithExtras.svelte.d.ts +23 -0
  94. package/dist/components/NihonKojinBangoInput/NihonKojinBangoInput.svelte +55 -0
  95. package/dist/components/NihonKojinBangoInput/NihonKojinBangoInput.svelte.d.ts +10 -0
  96. package/dist/components/NihonKojinBangoView/NihonKojinBangoView.svelte +40 -0
  97. package/dist/components/NihonKojinBangoView/NihonKojinBangoView.svelte.d.ts +8 -0
  98. package/dist/components/OneTimePasswordInput/OneTimePasswordInput.svelte +85 -0
  99. package/dist/components/OneTimePasswordInput/OneTimePasswordInput.svelte.d.ts +22 -0
  100. package/dist/components/OsterreichSozialversicherungsnummerInput/OsterreichSozialversicherungsnummerInput.svelte +55 -0
  101. package/dist/components/OsterreichSozialversicherungsnummerInput/OsterreichSozialversicherungsnummerInput.svelte.d.ts +10 -0
  102. package/dist/components/OsterreichSozialversicherungsnummerView/OsterreichSozialversicherungsnummerView.svelte +40 -0
  103. package/dist/components/OsterreichSozialversicherungsnummerView/OsterreichSozialversicherungsnummerView.svelte.d.ts +8 -0
  104. package/dist/components/PilipinasPhilhealthIdentificationNumberInput/PilipinasPhilhealthIdentificationNumberInput.svelte +55 -0
  105. package/dist/components/PilipinasPhilhealthIdentificationNumberInput/PilipinasPhilhealthIdentificationNumberInput.svelte.d.ts +10 -0
  106. package/dist/components/PilipinasPhilhealthIdentificationNumberView/PilipinasPhilhealthIdentificationNumberView.svelte +40 -0
  107. package/dist/components/PilipinasPhilhealthIdentificationNumberView/PilipinasPhilhealthIdentificationNumberView.svelte.d.ts +8 -0
  108. package/dist/components/PrathetThaiLekPrajamTuaPrachachonInput/PrathetThaiLekPrajamTuaPrachachonInput.svelte +55 -0
  109. package/dist/components/PrathetThaiLekPrajamTuaPrachachonInput/PrathetThaiLekPrajamTuaPrachachonInput.svelte.d.ts +10 -0
  110. package/dist/components/PrathetThaiLekPrajamTuaPrachachonView/PrathetThaiLekPrajamTuaPrachachonView.svelte +40 -0
  111. package/dist/components/PrathetThaiLekPrajamTuaPrachachonView/PrathetThaiLekPrajamTuaPrachachonView.svelte.d.ts +8 -0
  112. package/dist/components/RadarChart/RadarChart.svelte +63 -0
  113. package/dist/components/RadarChart/RadarChart.svelte.d.ts +13 -0
  114. package/dist/components/RossiyaSnilsInput/RossiyaSnilsInput.svelte +55 -0
  115. package/dist/components/RossiyaSnilsInput/RossiyaSnilsInput.svelte.d.ts +10 -0
  116. package/dist/components/RossiyaSnilsView/RossiyaSnilsView.svelte +40 -0
  117. package/dist/components/RossiyaSnilsView/RossiyaSnilsView.svelte.d.ts +8 -0
  118. package/dist/components/SankeyChart/SankeyChart.svelte +63 -0
  119. package/dist/components/SankeyChart/SankeyChart.svelte.d.ts +13 -0
  120. package/dist/components/ScatterChart/ScatterChart.svelte +42 -3
  121. package/dist/components/ScatterChart/ScatterChart.svelte.d.ts +4 -0
  122. package/dist/components/SchweizAhvNummerInput/SchweizAhvNummerInput.svelte +55 -0
  123. package/dist/components/SchweizAhvNummerInput/SchweizAhvNummerInput.svelte.d.ts +10 -0
  124. package/dist/components/SchweizAhvNummerView/SchweizAhvNummerView.svelte +40 -0
  125. package/dist/components/SchweizAhvNummerView/SchweizAhvNummerView.svelte.d.ts +8 -0
  126. package/dist/components/ShowMore/ShowMore.svelte +64 -0
  127. package/dist/components/ShowMore/ShowMore.svelte.d.ts +15 -0
  128. package/dist/components/SingaporeNationalRegistrationIdentityCardInput/SingaporeNationalRegistrationIdentityCardInput.svelte +55 -0
  129. package/dist/components/SingaporeNationalRegistrationIdentityCardInput/SingaporeNationalRegistrationIdentityCardInput.svelte.d.ts +10 -0
  130. package/dist/components/SingaporeNationalRegistrationIdentityCardView/SingaporeNationalRegistrationIdentityCardView.svelte +40 -0
  131. package/dist/components/SingaporeNationalRegistrationIdentityCardView/SingaporeNationalRegistrationIdentityCardView.svelte.d.ts +8 -0
  132. package/dist/components/SouthAfricaIdentityNumberInput/SouthAfricaIdentityNumberInput.svelte +55 -0
  133. package/dist/components/SouthAfricaIdentityNumberInput/SouthAfricaIdentityNumberInput.svelte.d.ts +10 -0
  134. package/dist/components/SouthAfricaIdentityNumberView/SouthAfricaIdentityNumberView.svelte +40 -0
  135. package/dist/components/SouthAfricaIdentityNumberView/SouthAfricaIdentityNumberView.svelte.d.ts +8 -0
  136. package/dist/components/Thinking/Thinking.svelte +58 -0
  137. package/dist/components/Thinking/Thinking.svelte.d.ts +15 -0
  138. package/dist/components/TurkiyeTcKimlikNumarasiInput/TurkiyeTcKimlikNumarasiInput.svelte +55 -0
  139. package/dist/components/TurkiyeTcKimlikNumarasiInput/TurkiyeTcKimlikNumarasiInput.svelte.d.ts +10 -0
  140. package/dist/components/TurkiyeTcKimlikNumarasiView/TurkiyeTcKimlikNumarasiView.svelte +40 -0
  141. package/dist/components/TurkiyeTcKimlikNumarasiView/TurkiyeTcKimlikNumarasiView.svelte.d.ts +8 -0
  142. package/dist/components/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivInput/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivInput.svelte +55 -0
  143. package/dist/components/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivInput/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivInput.svelte.d.ts +10 -0
  144. package/dist/components/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivView/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivView.svelte +40 -0
  145. package/dist/components/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivView/UkrayinaReyestratsiyniyNomerOblikovoyiKartkyPlatnykaPodatkivView.svelte.d.ts +8 -0
  146. package/dist/components/YisraelTeudatZehutInput/YisraelTeudatZehutInput.svelte +55 -0
  147. package/dist/components/YisraelTeudatZehutInput/YisraelTeudatZehutInput.svelte.d.ts +10 -0
  148. package/dist/components/YisraelTeudatZehutView/YisraelTeudatZehutView.svelte +40 -0
  149. package/dist/components/YisraelTeudatZehutView/YisraelTeudatZehutView.svelte.d.ts +8 -0
  150. package/dist/components/ZhongguoJuminShenfenzhengHaomaInput/ZhongguoJuminShenfenzhengHaomaInput.svelte +55 -0
  151. package/dist/components/ZhongguoJuminShenfenzhengHaomaInput/ZhongguoJuminShenfenzhengHaomaInput.svelte.d.ts +10 -0
  152. package/dist/components/ZhongguoJuminShenfenzhengHaomaView/ZhongguoJuminShenfenzhengHaomaView.svelte +40 -0
  153. package/dist/components/ZhongguoJuminShenfenzhengHaomaView/ZhongguoJuminShenfenzhengHaomaView.svelte.d.ts +8 -0
  154. package/dist/index.d.ts +64 -0
  155. package/dist/index.js +64 -0
  156. package/index.md +1 -1
  157. package/package.json +9 -8
@@ -2,15 +2,48 @@
2
2
  // Listbox component
3
3
  //
4
4
  // A headless listbox that presents a list of selectable options using the ARIA
5
- // listbox role with full keyboard navigation. It renders a <div> with
6
- // role="listbox" and manages focus movement between child option elements via
7
- // arrow keys. Used when users need to select one or more items from a visible
8
- // list, such as settings panels, filter selections, or multi-select interfaces.
5
+ // listbox role with full keyboard navigation. Two navigation models, chosen via
6
+ // `navigation`:
7
+ //
8
+ // "roving-focus" (default, unchanged since this component's introduction) —
9
+ // real DOM focus moves between child `[role="option"]` elements; arrows wrap
10
+ // at the ends; no typeahead, paging, or activation callback.
11
+ //
12
+ // "active-descendant" (added for consumers needing the full WAI-ARIA APG
13
+ // listbox keyboard contract, e.g. an icon-button-triggered picker) — the
14
+ // listbox root itself holds real focus and tracks a virtual cursor via
15
+ // `aria-activedescendant`, mirroring `activeIndex` (bindable) so the
16
+ // consumer's own each-block can render `data-active`/`aria-selected` on the
17
+ // option at that index. Adds `clamp` (vs. wrap), typeahead, PageUp/PageDown
18
+ // paging, and `onActivate`/`onEscape`/`onTabOut` callbacks so the consumer
19
+ // decides what "select" / "cancel" / "leave" actually do.
20
+ //
21
+ // Used when users need to select one or more items from a visible list, such
22
+ // as settings panels, filter selections, or multi-select interfaces.
9
23
  //
10
24
  // Props:
11
25
  // className — string, optional. CSS class name.
12
26
  // label — string, required. Accessible name applied via aria-label.
13
27
  // children — Snippet, required. Option elements (should have role="option" and tabindex="-1").
28
+ // navigation — "roving-focus" | "active-descendant", default "roving-focus".
29
+ // ref — HTMLElement | undefined, bindable. The rendered root, for a consumer
30
+ // that needs to call .focus() on it (active-descendant mode only).
31
+ // activeIndex — number, bindable, default -1. The virtual cursor position
32
+ // (active-descendant mode only); -1 means no option is active.
33
+ // clamp — boolean, default false. Arrow keys clamp at the ends instead of
34
+ // wrapping (active-descendant mode only; roving-focus always wraps).
35
+ // typeahead — boolean, default false. Printable characters move the cursor
36
+ // to the next option whose text starts with the typed buffer, cycling on a
37
+ // repeated character (active-descendant mode only).
38
+ // pageSize — number, default 10. PageUp/PageDown move the cursor by this
39
+ // many options, clamped (active-descendant mode only).
40
+ // onActivate — (index: number) => void, optional. Enter/Space on the active
41
+ // option (active-descendant mode only).
42
+ // onEscape — () => void, optional. Escape pressed (active-descendant mode only).
43
+ // onTabOut — (event: KeyboardEvent) => void, optional. Tab pressed, called
44
+ // BEFORE the browser processes the key (not prevented) so the consumer can
45
+ // move focus first — e.g. to the trigger button — before Tab's default
46
+ // action computes the next stop from wherever focus ends up (active-descendant mode only).
14
47
  // ...restProps — additional HTML attributes spread onto the <div>.
15
48
  //
16
49
  // Syntax:
@@ -19,30 +52,40 @@
19
52
  // </Listbox>
20
53
  //
21
54
  // Examples:
22
- // <!-- Basic listbox with static options -->
55
+ // <!-- Basic listbox with static options (roving-focus, unchanged default) -->
23
56
  // <Listbox label="Fruits">
24
57
  // <div role="option" tabindex="-1">Apple</div>
25
58
  // <div role="option" tabindex="-1">Banana</div>
26
59
  // </Listbox>
27
60
  //
28
- // <!-- Listbox with dynamic selection -->
29
- // <Listbox label="Select a color">
30
- // {#each colors as color}
31
- // <div role="option" tabindex="-1" aria-selected={selected === color}
32
- // onclick={() => selected = color}>{color}</div>
61
+ // <!-- active-descendant mode: consumer owns rendering each option's
62
+ // id/aria-selected/data-active from the bound activeIndex -->
63
+ // <Listbox
64
+ // label="Fruits"
65
+ // navigation="active-descendant"
66
+ // clamp
67
+ // bind:activeIndex
68
+ // onActivate={(i) => choose(fruits[i])}
69
+ // >
70
+ // {#each fruits as fruit, i}
71
+ // <div role="option" id={`fruit-${i}`} aria-selected={i === activeIndex}
72
+ // data-active={i === activeIndex ? "" : undefined}>{fruit}</div>
33
73
  // {/each}
34
74
  // </Listbox>
35
75
  //
36
76
  // Keyboard:
37
- // - ArrowDown: move focus to next option, wrapping from last to first
38
- // - ArrowUp: move focus to previous option, wrapping from first to last
39
- // - Home: move focus to the first option
40
- // - End: move focus to the last option
77
+ // roving-focus: ArrowDown/ArrowUp move focus and wrap; Home/End jump.
78
+ // active-descendant: ArrowDown/ArrowUp move the cursor (wrap unless `clamp`);
79
+ // Home/End jump; PageUp/PageDown move by `pageSize` (clamped); typeahead
80
+ // when `typeahead` is set; Enter/Space calls `onActivate`; Escape calls
81
+ // `onEscape`; Tab calls `onTabOut` without being prevented.
41
82
  //
42
83
  // Accessibility:
43
84
  // - role="listbox" identifies the container as a listbox widget
44
85
  // - aria-label provides an accessible name describing the listbox purpose
45
- // - Child elements should use role="option" and optionally aria-selected
86
+ // - roving-focus: child elements should use role="option" and optionally aria-selected
87
+ // - active-descendant: the root carries aria-activedescendant and tabindex="-1";
88
+ // the consumer's option elements carry the matching id
46
89
  //
47
90
  // Internationalization:
48
91
  // - The label prop accepts any translated string
@@ -51,8 +94,12 @@
51
94
  //
52
95
  // Claude rules:
53
96
  // - Headless: no CSS, no styles — consumer provides all styling
54
- // - Arrow keys wrap around at boundaries
55
- // - Consumer handles selection state externally
97
+ // - roving-focus (default): arrow keys wrap around at boundaries, consumer
98
+ // handles selection state externally — unchanged from this component's
99
+ // original behaviour, so existing consumers of the default mode see no
100
+ // difference.
101
+ // - active-descendant: opt-in via `navigation="active-descendant"`; every
102
+ // new prop is inert unless that mode is selected.
56
103
  //
57
104
  // References:
58
105
  // - WAI-ARIA Listbox Pattern: https://www.w3.org/WAI/ARIA/apg/patterns/listbox/
@@ -61,61 +108,193 @@
61
108
 
62
109
  let {
63
110
  class: className = "",
111
+ baseClass = "listbox",
112
+ as = "div",
64
113
  label,
65
114
  children,
115
+ navigation = "roving-focus",
116
+ ref = $bindable<HTMLElement | undefined>(undefined),
117
+ activeIndex = $bindable(-1),
118
+ clamp = false,
119
+ typeahead = false,
120
+ pageSize = 10,
121
+ onActivate,
122
+ onEscape,
123
+ onTabOut,
66
124
  ...restProps
67
125
  }: {
126
+ /** Base class token, replacing "listbox" outright (not appended). */
127
+ baseClass?: string;
128
+ /** Root element tag. Default "div" (unchanged). A consumer whose spec
129
+ * requires e.g. a `<ul>` root sets `as="ul"`. */
130
+ as?: string;
68
131
  /** Accessible label. */
69
132
  label: string;
70
133
  /** Option elements. */
71
134
  children: Snippet;
135
+ /** Navigation/focus model. Default "roving-focus" (unchanged legacy behaviour). */
136
+ navigation?: "roving-focus" | "active-descendant";
137
+ /** The rendered root element. Bindable. */
138
+ ref?: HTMLElement;
139
+ /** Virtual cursor position (active-descendant mode). Bindable, -1 = none. */
140
+ activeIndex?: number;
141
+ /** Arrow keys clamp instead of wrap (active-descendant mode). */
142
+ clamp?: boolean;
143
+ /** Printable-character typeahead (active-descendant mode). */
144
+ typeahead?: boolean;
145
+ /** PageUp/PageDown step size (active-descendant mode). */
146
+ pageSize?: number;
147
+ /** Enter/Space on the active option (active-descendant mode). */
148
+ onActivate?: (index: number) => void;
149
+ /** Escape pressed (active-descendant mode). */
150
+ onEscape?: () => void;
151
+ /** Tab pressed, called before the key is processed (active-descendant mode). */
152
+ onTabOut?: (event: KeyboardEvent) => void;
72
153
  [key: string]: unknown;
73
154
  } = $props();
74
155
 
75
- let listRef: HTMLElement | undefined = $state(undefined);
156
+ function options(): HTMLElement[] {
157
+ return ref ? Array.from(ref.querySelectorAll<HTMLElement>("[role='option']")) : [];
158
+ }
76
159
 
77
- function onkeydown(event: KeyboardEvent) {
78
- if (!listRef) return;
79
- const options = Array.from(
80
- listRef.querySelectorAll<HTMLElement>("[role='option']"),
81
- );
160
+ // ---------------------------------------------------------------
161
+ // roving-focus (default, unchanged): real DOM focus per option, wraps.
162
+ // ---------------------------------------------------------------
163
+
164
+ function onRovingFocusKeydown(event: KeyboardEvent) {
165
+ const opts = options();
82
166
  const current = document.activeElement as HTMLElement;
83
- const index = options.indexOf(current);
167
+ const index = opts.indexOf(current);
84
168
  switch (event.key) {
85
169
  case "ArrowDown": {
86
170
  event.preventDefault();
87
- const next = index < options.length - 1 ? index + 1 : 0;
88
- options[next]?.focus();
171
+ const next = index < opts.length - 1 ? index + 1 : 0;
172
+ opts[next]?.focus();
89
173
  break;
90
174
  }
91
175
  case "ArrowUp": {
92
176
  event.preventDefault();
93
- const prev = index > 0 ? index - 1 : options.length - 1;
94
- options[prev]?.focus();
177
+ const prev = index > 0 ? index - 1 : opts.length - 1;
178
+ opts[prev]?.focus();
95
179
  break;
96
180
  }
97
181
  case "Home": {
98
182
  event.preventDefault();
99
- options[0]?.focus();
183
+ opts[0]?.focus();
100
184
  break;
101
185
  }
102
186
  case "End": {
103
187
  event.preventDefault();
104
- options[options.length - 1]?.focus();
188
+ opts[opts.length - 1]?.focus();
105
189
  break;
106
190
  }
107
191
  }
108
192
  }
193
+
194
+ // ---------------------------------------------------------------
195
+ // active-descendant (opt-in): virtual cursor, clamp/wrap, typeahead, paging.
196
+ // ---------------------------------------------------------------
197
+
198
+ let typeaheadBuffer = "";
199
+ let typeaheadTimer: ReturnType<typeof setTimeout> | undefined;
200
+
201
+ function moveActive(delta: number) {
202
+ const count = options().length;
203
+ if (count === 0) return;
204
+ const next = activeIndex + delta;
205
+ activeIndex = clamp ? Math.min(Math.max(next, 0), count - 1) : ((next % count) + count) % count;
206
+ }
207
+
208
+ function runTypeahead(char: string) {
209
+ const opts = options();
210
+ if (opts.length === 0) return;
211
+ const lower = char.toLowerCase();
212
+ const sameCharRun = typeaheadBuffer === "" || [...typeaheadBuffer].every((c) => c === lower);
213
+ typeaheadBuffer += lower;
214
+ clearTimeout(typeaheadTimer);
215
+ typeaheadTimer = setTimeout(() => (typeaheadBuffer = ""), 500);
216
+ const query = sameCharRun ? lower : typeaheadBuffer;
217
+ const anchor = activeIndex < 0 ? 0 : activeIndex;
218
+ const start = sameCharRun ? anchor + 1 : anchor;
219
+ for (let n = 0; n < opts.length; n++) {
220
+ const i = (start + n) % opts.length;
221
+ if ((opts[i].textContent ?? "").trim().toLowerCase().startsWith(query)) {
222
+ activeIndex = i;
223
+ return;
224
+ }
225
+ }
226
+ }
227
+
228
+ function onActiveDescendantKeydown(event: KeyboardEvent) {
229
+ switch (event.key) {
230
+ case "ArrowDown":
231
+ event.preventDefault();
232
+ moveActive(1);
233
+ break;
234
+ case "ArrowUp":
235
+ event.preventDefault();
236
+ moveActive(-1);
237
+ break;
238
+ case "Home":
239
+ event.preventDefault();
240
+ activeIndex = options().length ? 0 : -1;
241
+ break;
242
+ case "End":
243
+ event.preventDefault();
244
+ activeIndex = options().length - 1;
245
+ break;
246
+ case "PageDown":
247
+ event.preventDefault();
248
+ moveActive(pageSize);
249
+ break;
250
+ case "PageUp":
251
+ event.preventDefault();
252
+ moveActive(-pageSize);
253
+ break;
254
+ case "Enter":
255
+ case " ":
256
+ event.preventDefault();
257
+ if (activeIndex >= 0) onActivate?.(activeIndex);
258
+ break;
259
+ case "Escape":
260
+ event.preventDefault();
261
+ onEscape?.();
262
+ break;
263
+ case "Tab":
264
+ // Not prevented: the consumer's onTabOut (e.g. moving focus to a
265
+ // trigger button) runs first, so the browser's default Tab
266
+ // proceeds from wherever focus ends up, not from this element.
267
+ onTabOut?.(event);
268
+ break;
269
+ default:
270
+ if (typeahead && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
271
+ runTypeahead(event.key);
272
+ }
273
+ }
274
+ }
275
+
276
+ function onkeydown(event: KeyboardEvent) {
277
+ if (navigation === "active-descendant") onActiveDescendantKeydown(event);
278
+ else onRovingFocusKeydown(event);
279
+ }
280
+
281
+ const activeId = $derived.by(() => {
282
+ if (navigation !== "active-descendant" || activeIndex < 0) return undefined;
283
+ return options()[activeIndex]?.id || undefined;
284
+ });
109
285
  </script>
110
286
 
111
287
  <!-- Listbox.svelte -->
112
- <div
113
- class={`listbox ${className}`}
288
+ <svelte:element
289
+ this={as}
290
+ class={`${baseClass} ${className}`}
114
291
  role="listbox"
115
292
  aria-label={label}
116
- bind:this={listRef}
293
+ tabindex={navigation === "active-descendant" ? -1 : undefined}
294
+ aria-activedescendant={activeId}
295
+ bind:this={ref}
117
296
  {onkeydown}
118
297
  {...restProps}
119
298
  >
120
299
  {@render children?.()}
121
- </div>
300
+ </svelte:element>
@@ -1,11 +1,34 @@
1
1
  import type { Snippet } from "svelte";
2
2
  type $$ComponentProps = {
3
+ /** Base class token, replacing "listbox" outright (not appended). */
4
+ baseClass?: string;
5
+ /** Root element tag. Default "div" (unchanged). A consumer whose spec
6
+ * requires e.g. a `<ul>` root sets `as="ul"`. */
7
+ as?: string;
3
8
  /** Accessible label. */
4
9
  label: string;
5
10
  /** Option elements. */
6
11
  children: Snippet;
12
+ /** Navigation/focus model. Default "roving-focus" (unchanged legacy behaviour). */
13
+ navigation?: "roving-focus" | "active-descendant";
14
+ /** The rendered root element. Bindable. */
15
+ ref?: HTMLElement;
16
+ /** Virtual cursor position (active-descendant mode). Bindable, -1 = none. */
17
+ activeIndex?: number;
18
+ /** Arrow keys clamp instead of wrap (active-descendant mode). */
19
+ clamp?: boolean;
20
+ /** Printable-character typeahead (active-descendant mode). */
21
+ typeahead?: boolean;
22
+ /** PageUp/PageDown step size (active-descendant mode). */
23
+ pageSize?: number;
24
+ /** Enter/Space on the active option (active-descendant mode). */
25
+ onActivate?: (index: number) => void;
26
+ /** Escape pressed (active-descendant mode). */
27
+ onEscape?: () => void;
28
+ /** Tab pressed, called before the key is processed (active-descendant mode). */
29
+ onTabOut?: (event: KeyboardEvent) => void;
7
30
  [key: string]: unknown;
8
31
  };
9
- declare const Listbox: import("svelte").Component<$$ComponentProps, {}, "">;
32
+ declare const Listbox: import("svelte").Component<$$ComponentProps, {}, "ref" | "activeIndex">;
10
33
  type Listbox = ReturnType<typeof Listbox>;
11
34
  export default Listbox;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ // LuxembourgMatriculeInput component
3
+ //
4
+ // A headless input for entering Luxembourg's Numéro d'Identification Nationale (Matricule).
5
+ // Format: Thirteen digits in the form YYYYMMDDNNNCC: the first eight digits encode date of birth (YYYYMMDD); the next three are a sequence number; the twelfth digit is a Luhn (Modulus-10) check digit computed over the first eleven digits; the thirteenth digit is a second, independent check digit computed with the Verhoeff algorithm over the first twelve digits.
6
+ //
7
+ // Props:
8
+ // className — string, optional. CSS class name.
9
+ // label — string, required. Accessible label for screen readers via aria-label.
10
+ // value — string, default "". Bindable input value; supports bind:value.
11
+ // required — boolean, default false. Whether the input is required for form submission.
12
+ // disabled — boolean, default false. Whether the input is disabled.
13
+ // ...restProps — additional HTML attributes spread onto the <input>.
14
+ //
15
+ // Syntax:
16
+ // <LuxembourgMatriculeInput label="Numéro d'Identification Nationale (Matricule)" bind:value />
17
+ //
18
+ // Accessibility:
19
+ // - aria-label provides the accessible name for screen readers
20
+ // - autocomplete="off" protects sensitive identifiers
21
+ // - required and disabled states are conveyed to assistive technology
22
+ //
23
+ // Internationalization:
24
+ // - The label prop externalizes user-facing text for translation
25
+ //
26
+ // References:
27
+ // - https://ccss.public.lu/fr/glossaire/numero-identification-national/matricule-national.html
28
+
29
+ let {
30
+ class: className = "",
31
+ label,
32
+ value = $bindable(""),
33
+ required = false,
34
+ disabled = false,
35
+ ...restProps
36
+ }: {
37
+ label: string;
38
+ value?: string;
39
+ required?: boolean;
40
+ disabled?: boolean;
41
+ [key: string]: unknown;
42
+ } = $props();
43
+ </script>
44
+
45
+ <!-- LuxembourgMatriculeInput.svelte -->
46
+ <input
47
+ class={`luxembourg-matricule-input ${className}`}
48
+ type="text"
49
+ aria-label={label}
50
+ autocomplete="off"
51
+ bind:value
52
+ {required}
53
+ {disabled}
54
+ {...restProps}
55
+ />
@@ -0,0 +1,10 @@
1
+ type $$ComponentProps = {
2
+ label: string;
3
+ value?: string;
4
+ required?: boolean;
5
+ disabled?: boolean;
6
+ [key: string]: unknown;
7
+ };
8
+ declare const LuxembourgMatriculeInput: import("svelte").Component<$$ComponentProps, {}, "value">;
9
+ type LuxembourgMatriculeInput = ReturnType<typeof LuxembourgMatriculeInput>;
10
+ export default LuxembourgMatriculeInput;
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ // LuxembourgMatriculeView component
3
+ //
4
+ // A headless display component for showing Luxembourg's
5
+ // Numéro d'Identification Nationale (Matricule) in a read-only format.
6
+ // Format: Thirteen digits in the form YYYYMMDDNNNCC: the first eight digits encode date of birth (YYYYMMDD); the next three are a sequence number; the twelfth digit is a Luhn (Modulus-10) check digit computed over the first eleven digits; the thirteenth digit is a second, independent check digit computed with the Verhoeff algorithm over the first twelve digits.
7
+ //
8
+ // Props:
9
+ // className — string, optional. CSS class name.
10
+ // label — string, required. Accessible label for screen readers via aria-label.
11
+ // value — string, default "". The identifier string to display.
12
+ // ...restProps — additional HTML attributes spread onto the <span>.
13
+ //
14
+ // Syntax:
15
+ // <LuxembourgMatriculeView label="Numéro d'Identification Nationale (Matricule)" value={value} />
16
+ //
17
+ // Accessibility:
18
+ // - aria-label provides the accessible name so screen readers announce the purpose
19
+ //
20
+ // References:
21
+ // - https://ccss.public.lu/fr/glossaire/numero-identification-national/matricule-national.html
22
+
23
+ let {
24
+ class: className = "",
25
+ label,
26
+ value = "",
27
+ ...restProps
28
+ }: {
29
+ label: string;
30
+ value?: string;
31
+ [key: string]: unknown;
32
+ } = $props();
33
+ </script>
34
+
35
+ <!-- LuxembourgMatriculeView.svelte -->
36
+ <span
37
+ class={`luxembourg-matricule-view ${className}`}
38
+ aria-label={label}
39
+ {...restProps}>{value}</span
40
+ >
@@ -0,0 +1,8 @@
1
+ type $$ComponentProps = {
2
+ label: string;
3
+ value?: string;
4
+ [key: string]: unknown;
5
+ };
6
+ declare const LuxembourgMatriculeView: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type LuxembourgMatriculeView = ReturnType<typeof LuxembourgMatriculeView>;
8
+ export default LuxembourgMatriculeView;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ // MagyarorszagTajSzamInput component
3
+ //
4
+ // A headless input for entering Hungary's Társadalombiztosítási Azonosító Jel (TAJ).
5
+ // Format: Nine digits, displayed as SSS SSS SSK. The first eight digits are a simple issued-in-order serial number; the ninth is a check digit computed by multiplying the first eight digits by alternating weights 3 and 7, summing the products, and taking the result Modulus 10 — an algorithm unique to Hungary, distinct from Luhn.
6
+ //
7
+ // Props:
8
+ // className — string, optional. CSS class name.
9
+ // label — string, required. Accessible label for screen readers via aria-label.
10
+ // value — string, default "". Bindable input value; supports bind:value.
11
+ // required — boolean, default false. Whether the input is required for form submission.
12
+ // disabled — boolean, default false. Whether the input is disabled.
13
+ // ...restProps — additional HTML attributes spread onto the <input>.
14
+ //
15
+ // Syntax:
16
+ // <MagyarorszagTajSzamInput label="Társadalombiztosítási Azonosító Jel (TAJ)" bind:value />
17
+ //
18
+ // Accessibility:
19
+ // - aria-label provides the accessible name for screen readers
20
+ // - autocomplete="off" protects sensitive identifiers
21
+ // - required and disabled states are conveyed to assistive technology
22
+ //
23
+ // Internationalization:
24
+ // - The label prop externalizes user-facing text for translation
25
+ //
26
+ // References:
27
+ // - https://hu.wikipedia.org/wiki/T%C3%A1rsadalombiztos%C3%ADt%C3%A1si_azonos%C3%ADt%C3%B3_jel
28
+
29
+ let {
30
+ class: className = "",
31
+ label,
32
+ value = $bindable(""),
33
+ required = false,
34
+ disabled = false,
35
+ ...restProps
36
+ }: {
37
+ label: string;
38
+ value?: string;
39
+ required?: boolean;
40
+ disabled?: boolean;
41
+ [key: string]: unknown;
42
+ } = $props();
43
+ </script>
44
+
45
+ <!-- MagyarorszagTajSzamInput.svelte -->
46
+ <input
47
+ class={`magyarorszag-taj-szam-input ${className}`}
48
+ type="text"
49
+ aria-label={label}
50
+ autocomplete="off"
51
+ bind:value
52
+ {required}
53
+ {disabled}
54
+ {...restProps}
55
+ />
@@ -0,0 +1,10 @@
1
+ type $$ComponentProps = {
2
+ label: string;
3
+ value?: string;
4
+ required?: boolean;
5
+ disabled?: boolean;
6
+ [key: string]: unknown;
7
+ };
8
+ declare const MagyarorszagTajSzamInput: import("svelte").Component<$$ComponentProps, {}, "value">;
9
+ type MagyarorszagTajSzamInput = ReturnType<typeof MagyarorszagTajSzamInput>;
10
+ export default MagyarorszagTajSzamInput;
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ // MagyarorszagTajSzamView component
3
+ //
4
+ // A headless display component for showing Hungary's
5
+ // Társadalombiztosítási Azonosító Jel (TAJ) in a read-only format.
6
+ // Format: Nine digits, displayed as SSS SSS SSK. The first eight digits are a simple issued-in-order serial number; the ninth is a check digit computed by multiplying the first eight digits by alternating weights 3 and 7, summing the products, and taking the result Modulus 10 — an algorithm unique to Hungary, distinct from Luhn.
7
+ //
8
+ // Props:
9
+ // className — string, optional. CSS class name.
10
+ // label — string, required. Accessible label for screen readers via aria-label.
11
+ // value — string, default "". The identifier string to display.
12
+ // ...restProps — additional HTML attributes spread onto the <span>.
13
+ //
14
+ // Syntax:
15
+ // <MagyarorszagTajSzamView label="Társadalombiztosítási Azonosító Jel (TAJ)" value={value} />
16
+ //
17
+ // Accessibility:
18
+ // - aria-label provides the accessible name so screen readers announce the purpose
19
+ //
20
+ // References:
21
+ // - https://hu.wikipedia.org/wiki/T%C3%A1rsadalombiztos%C3%ADt%C3%A1si_azonos%C3%ADt%C3%B3_jel
22
+
23
+ let {
24
+ class: className = "",
25
+ label,
26
+ value = "",
27
+ ...restProps
28
+ }: {
29
+ label: string;
30
+ value?: string;
31
+ [key: string]: unknown;
32
+ } = $props();
33
+ </script>
34
+
35
+ <!-- MagyarorszagTajSzamView.svelte -->
36
+ <span
37
+ class={`magyarorszag-taj-szam-view ${className}`}
38
+ aria-label={label}
39
+ {...restProps}>{value}</span
40
+ >
@@ -0,0 +1,8 @@
1
+ type $$ComponentProps = {
2
+ label: string;
3
+ value?: string;
4
+ [key: string]: unknown;
5
+ };
6
+ declare const MagyarorszagTajSzamView: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type MagyarorszagTajSzamView = ReturnType<typeof MagyarorszagTajSzamView>;
8
+ export default MagyarorszagTajSzamView;
@@ -0,0 +1,55 @@
1
+ <script lang="ts">
2
+ // MexicoClaveUnicaDeRegistroDePoblacionInput component
3
+ //
4
+ // A headless input for entering Mexico's Clave Única de Registro de Población (CURP).
5
+ // Format: Eighteen-character alphanumeric code built from name, date of birth, sex, and state of birth: first letter of the first surname plus its first internal vowel; first letter of the second surname (or X if none); first letter of the given name; six-digit date of birth (YYMMDD); H or M for sex (X for non-binary); a two-letter state code (NE for those born abroad); a consonant from each surname and the given name; then two further disambiguating characters. No trailing check digit.
6
+ //
7
+ // Props:
8
+ // className — string, optional. CSS class name.
9
+ // label — string, required. Accessible label for screen readers via aria-label.
10
+ // value — string, default "". Bindable input value; supports bind:value.
11
+ // required — boolean, default false. Whether the input is required for form submission.
12
+ // disabled — boolean, default false. Whether the input is disabled.
13
+ // ...restProps — additional HTML attributes spread onto the <input>.
14
+ //
15
+ // Syntax:
16
+ // <MexicoClaveUnicaDeRegistroDePoblacionInput label="Clave Única de Registro de Población (CURP)" bind:value />
17
+ //
18
+ // Accessibility:
19
+ // - aria-label provides the accessible name for screen readers
20
+ // - autocomplete="off" protects sensitive identifiers
21
+ // - required and disabled states are conveyed to assistive technology
22
+ //
23
+ // Internationalization:
24
+ // - The label prop externalizes user-facing text for translation
25
+ //
26
+ // References:
27
+ // - https://en.wikipedia.org/wiki/Unique_Population_Registry_Code
28
+
29
+ let {
30
+ class: className = "",
31
+ label,
32
+ value = $bindable(""),
33
+ required = false,
34
+ disabled = false,
35
+ ...restProps
36
+ }: {
37
+ label: string;
38
+ value?: string;
39
+ required?: boolean;
40
+ disabled?: boolean;
41
+ [key: string]: unknown;
42
+ } = $props();
43
+ </script>
44
+
45
+ <!-- MexicoClaveUnicaDeRegistroDePoblacionInput.svelte -->
46
+ <input
47
+ class={`mexico-clave-unica-de-registro-de-poblacion-input ${className}`}
48
+ type="text"
49
+ aria-label={label}
50
+ autocomplete="off"
51
+ bind:value
52
+ {required}
53
+ {disabled}
54
+ {...restProps}
55
+ />