@human-kit/svelte-components 1.0.0-alpha.2 → 1.0.0-alpha.20

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 (394) hide show
  1. package/dist/FOCUS_STATE_CONTRACT.md +63 -0
  2. package/dist/FOCUS_STATE_REVIEW_TEMPLATE.md +70 -0
  3. package/dist/button/README.md +48 -0
  4. package/dist/button/TODO.md +13 -0
  5. package/dist/button/index.d.ts +5 -0
  6. package/dist/button/index.js +4 -0
  7. package/dist/button/index.parts.d.ts +1 -0
  8. package/dist/button/index.parts.js +1 -0
  9. package/dist/button/root/README.md +43 -0
  10. package/dist/button/root/button-root.svelte +362 -0
  11. package/dist/button/root/button-root.svelte.d.ts +21 -0
  12. package/dist/button/root/button-test.svelte +76 -0
  13. package/dist/button/root/button-test.svelte.d.ts +11 -0
  14. package/dist/calendar/README.md +2 -1
  15. package/dist/calendar/TODO.md +21 -107
  16. package/dist/calendar/body-cell/README.md +15 -0
  17. package/dist/calendar/body-cell/calendar-body-cell.svelte +116 -41
  18. package/dist/calendar/grid/README.md +13 -0
  19. package/dist/calendar/grid-body/README.md +13 -0
  20. package/dist/calendar/grid-header/README.md +13 -0
  21. package/dist/calendar/header-cell/README.md +14 -0
  22. package/dist/calendar/heading/README.md +13 -0
  23. package/dist/calendar/index.d.ts +3 -3
  24. package/dist/calendar/index.js +3 -3
  25. package/dist/calendar/root/README.md +24 -0
  26. package/dist/calendar/root/calendar-root-test.svelte +4 -0
  27. package/dist/calendar/root/calendar-root-test.svelte.d.ts +1 -0
  28. package/dist/calendar/root/calendar-root.svelte +3 -0
  29. package/dist/calendar/root/calendar-root.svelte.d.ts +1 -0
  30. package/dist/calendar/root/context.d.ts +4 -0
  31. package/dist/calendar/root/context.js +28 -25
  32. package/dist/calendar/root/date-utils.d.ts +1 -1
  33. package/dist/calendar/root/date-utils.js +16 -26
  34. package/dist/calendar/trigger-next/README.md +14 -0
  35. package/dist/calendar/trigger-next/calendar-trigger-next.svelte +9 -4
  36. package/dist/calendar/trigger-next/calendar-trigger-next.svelte.d.ts +2 -1
  37. package/dist/calendar/trigger-previous/README.md +14 -0
  38. package/dist/calendar/trigger-previous/calendar-trigger-previous.svelte +9 -4
  39. package/dist/calendar/trigger-previous/calendar-trigger-previous.svelte.d.ts +2 -1
  40. package/dist/checkbox/README.md +53 -0
  41. package/dist/checkbox/TODO.md +16 -0
  42. package/dist/checkbox/index.d.ts +6 -0
  43. package/dist/checkbox/index.js +6 -0
  44. package/dist/checkbox/index.parts.d.ts +2 -0
  45. package/dist/checkbox/index.parts.js +2 -0
  46. package/dist/checkbox/indicator/README.md +23 -0
  47. package/dist/checkbox/indicator/checkbox-indicator.svelte +43 -0
  48. package/dist/checkbox/indicator/checkbox-indicator.svelte.d.ts +10 -0
  49. package/dist/checkbox/root/README.md +47 -0
  50. package/dist/checkbox/root/checkbox-label-test.svelte +10 -0
  51. package/dist/checkbox/root/checkbox-label-test.svelte.d.ts +18 -0
  52. package/dist/checkbox/root/checkbox-root.svelte +386 -0
  53. package/dist/checkbox/root/checkbox-root.svelte.d.ts +29 -0
  54. package/dist/checkbox/root/checkbox-test.svelte +59 -0
  55. package/dist/checkbox/root/checkbox-test.svelte.d.ts +18 -0
  56. package/dist/checkbox/root/context.d.ts +21 -0
  57. package/dist/checkbox/root/context.js +15 -0
  58. package/dist/clock/README.md +75 -0
  59. package/dist/clock/axis/README.md +24 -0
  60. package/dist/clock/axis/clock-axis.svelte +37 -0
  61. package/dist/clock/axis/clock-axis.svelte.d.ts +8 -0
  62. package/dist/clock/hooks/use-wheel-scroll.svelte.d.ts +16 -0
  63. package/dist/clock/hooks/use-wheel-scroll.svelte.js +336 -0
  64. package/dist/clock/index.d.ts +10 -0
  65. package/dist/clock/index.js +10 -0
  66. package/dist/clock/index.parts.d.ts +4 -0
  67. package/dist/clock/index.parts.js +4 -0
  68. package/dist/clock/root/README.md +38 -0
  69. package/dist/clock/root/clock-root-test.svelte +62 -0
  70. package/dist/clock/root/clock-root-test.svelte.d.ts +14 -0
  71. package/dist/clock/root/clock-root.svelte +329 -0
  72. package/dist/clock/root/clock-root.svelte.d.ts +25 -0
  73. package/dist/clock/root/context.d.ts +22 -0
  74. package/dist/clock/root/context.js +15 -0
  75. package/dist/clock/root/resolve-visible-columns.d.ts +7 -0
  76. package/dist/clock/root/resolve-visible-columns.js +16 -0
  77. package/dist/clock/root/time-utils.d.ts +48 -0
  78. package/dist/clock/root/time-utils.js +314 -0
  79. package/dist/clock/root/wheel-options.d.ts +17 -0
  80. package/dist/clock/root/wheel-options.js +63 -0
  81. package/dist/clock/wheel-column/README.md +25 -0
  82. package/dist/clock/wheel-column/clock-wheel-column-bindable-test.svelte +16 -0
  83. package/dist/clock/wheel-column/clock-wheel-column-bindable-test.svelte.d.ts +3 -0
  84. package/dist/clock/wheel-column/clock-wheel-column-custom-snippet-test.svelte +29 -0
  85. package/dist/clock/wheel-column/clock-wheel-column-custom-snippet-test.svelte.d.ts +6 -0
  86. package/dist/clock/wheel-column/clock-wheel-column-default-height-test.svelte +11 -0
  87. package/dist/clock/wheel-column/clock-wheel-column-default-height-test.svelte.d.ts +3 -0
  88. package/dist/clock/wheel-column/clock-wheel-column-test.svelte +38 -0
  89. package/dist/clock/wheel-column/clock-wheel-column-test.svelte.d.ts +12 -0
  90. package/dist/clock/wheel-column/clock-wheel-column-tp-test.svelte +38 -0
  91. package/dist/clock/wheel-column/clock-wheel-column-tp-test.svelte.d.ts +12 -0
  92. package/dist/clock/wheel-column/clock-wheel-column-untagged-snippet-test.svelte +29 -0
  93. package/dist/clock/wheel-column/clock-wheel-column-untagged-snippet-test.svelte.d.ts +6 -0
  94. package/dist/clock/wheel-column/clock-wheel-column.svelte +499 -0
  95. package/dist/clock/wheel-column/clock-wheel-column.svelte.d.ts +17 -0
  96. package/dist/clock/wheel-item/README.md +17 -0
  97. package/dist/clock/wheel-item/clock-wheel-item.svelte +49 -0
  98. package/dist/clock/wheel-item/clock-wheel-item.svelte.d.ts +17 -0
  99. package/dist/combobox/README.md +8 -2
  100. package/dist/combobox/TODO.md +28 -175
  101. package/dist/combobox/button/README.md +8 -3
  102. package/dist/combobox/button/combobox-button-test.svelte +27 -0
  103. package/dist/combobox/button/combobox-button-test.svelte.d.ts +6 -0
  104. package/dist/combobox/button/combobox-button.svelte +10 -11
  105. package/dist/combobox/clear/README.md +21 -0
  106. package/dist/combobox/clear/combobox-clear-test.svelte +34 -0
  107. package/dist/combobox/clear/combobox-clear-test.svelte.d.ts +3 -0
  108. package/dist/combobox/clear/combobox-clear.svelte +61 -0
  109. package/dist/combobox/clear/combobox-clear.svelte.d.ts +9 -0
  110. package/dist/combobox/index.d.ts +5 -3
  111. package/dist/combobox/index.js +5 -3
  112. package/dist/combobox/index.parts.d.ts +2 -0
  113. package/dist/combobox/index.parts.js +2 -0
  114. package/dist/combobox/input/combobox-input.svelte +44 -12
  115. package/dist/combobox/item/combobox-item-implicit-text-test.svelte +1 -1
  116. package/dist/combobox/item/combobox-listboxitem.svelte +14 -11
  117. package/dist/combobox/item-indicator/combobox-item-indicator.svelte +4 -15
  118. package/dist/combobox/list/combobox-listbox.svelte +1 -0
  119. package/dist/combobox/list/combobox-listbox.svelte.d.ts +2 -1
  120. package/dist/combobox/popover/README.md +18 -4
  121. package/dist/combobox/popover/combobox-popover-props-test.svelte +38 -0
  122. package/dist/combobox/popover/combobox-popover-props-test.svelte.d.ts +11 -0
  123. package/dist/combobox/popover/combobox-popover.svelte +166 -23
  124. package/dist/combobox/popover/combobox-popover.svelte.d.ts +3 -3
  125. package/dist/combobox/popover/combobox-scrollable-list-test.svelte +23 -0
  126. package/dist/combobox/popover/combobox-scrollable-list-test.svelte.d.ts +18 -0
  127. package/dist/combobox/root/README.md +1 -0
  128. package/dist/combobox/root/combobox-multiselect-test.svelte +5 -3
  129. package/dist/combobox/root/combobox-multiselect-test.svelte.d.ts +1 -0
  130. package/dist/combobox/root/combobox-numeric-string-id-test.svelte +1 -1
  131. package/dist/combobox/root/combobox-test.svelte +23 -4
  132. package/dist/combobox/root/combobox-test.svelte.d.ts +2 -0
  133. package/dist/combobox/root/combobox.svelte +119 -13
  134. package/dist/combobox/root/combobox.svelte.d.ts +1 -0
  135. package/dist/combobox/root/context.d.ts +19 -1
  136. package/dist/combobox/tag-remove/combobox-tag-remove.svelte +3 -2
  137. package/dist/combobox/trigger/README.md +21 -0
  138. package/dist/combobox/trigger/combobox-trigger.svelte +56 -0
  139. package/dist/combobox/trigger/combobox-trigger.svelte.d.ts +9 -0
  140. package/dist/datepicker/README.md +100 -0
  141. package/dist/datepicker/TODO.md +28 -0
  142. package/dist/datepicker/calendar/README.md +19 -0
  143. package/dist/datepicker/calendar/date-picker-calendar-unsafe-props-test.svelte +60 -0
  144. package/dist/datepicker/calendar/date-picker-calendar-unsafe-props-test.svelte.d.ts +3 -0
  145. package/dist/datepicker/calendar/date-picker-calendar.svelte +65 -0
  146. package/dist/datepicker/calendar/date-picker-calendar.svelte.d.ts +10 -0
  147. package/dist/datepicker/index.d.ts +18 -0
  148. package/dist/datepicker/index.js +18 -0
  149. package/dist/datepicker/index.parts.d.ts +14 -0
  150. package/dist/datepicker/index.parts.js +14 -0
  151. package/dist/datepicker/input/README.md +15 -0
  152. package/dist/datepicker/input/date-picker-input.svelte +108 -0
  153. package/dist/datepicker/input/date-picker-input.svelte.d.ts +11 -0
  154. package/dist/datepicker/internal/strict-props.d.ts +2 -0
  155. package/dist/datepicker/internal/strict-props.js +28 -0
  156. package/dist/datepicker/popover/README.md +20 -0
  157. package/dist/datepicker/popover/date-picker-popover-handler-test.svelte +57 -0
  158. package/dist/datepicker/popover/date-picker-popover-handler-test.svelte.d.ts +3 -0
  159. package/dist/datepicker/popover/date-picker-popover-unsafe-props-test.svelte +45 -0
  160. package/dist/datepicker/popover/date-picker-popover-unsafe-props-test.svelte.d.ts +18 -0
  161. package/dist/datepicker/popover/date-picker-popover.svelte +87 -0
  162. package/dist/datepicker/popover/date-picker-popover.svelte.d.ts +7 -0
  163. package/dist/datepicker/root/README.md +38 -0
  164. package/dist/datepicker/root/context.d.ts +43 -0
  165. package/dist/datepicker/root/context.js +15 -0
  166. package/dist/datepicker/root/date-picker-bindable-empty-test.svelte +24 -0
  167. package/dist/datepicker/root/date-picker-bindable-empty-test.svelte.d.ts +3 -0
  168. package/dist/datepicker/root/date-picker-bindable-test.svelte +41 -0
  169. package/dist/datepicker/root/date-picker-bindable-test.svelte.d.ts +3 -0
  170. package/dist/datepicker/root/date-picker-empty-test.svelte +47 -0
  171. package/dist/datepicker/root/date-picker-empty-test.svelte.d.ts +3 -0
  172. package/dist/datepicker/root/date-picker-locale-typing-test.svelte +47 -0
  173. package/dist/datepicker/root/date-picker-locale-typing-test.svelte.d.ts +3 -0
  174. package/dist/datepicker/root/date-picker-open-cancel-test.svelte +54 -0
  175. package/dist/datepicker/root/date-picker-open-cancel-test.svelte.d.ts +8 -0
  176. package/dist/datepicker/root/date-picker-root.svelte +495 -0
  177. package/dist/datepicker/root/date-picker-root.svelte.d.ts +24 -0
  178. package/dist/datepicker/root/date-picker-test.svelte +86 -0
  179. package/dist/datepicker/root/date-picker-test.svelte.d.ts +13 -0
  180. package/dist/datepicker/root/date-utils.d.ts +17 -0
  181. package/dist/datepicker/root/date-utils.js +138 -0
  182. package/dist/datepicker/root/draft-evaluation.d.ts +13 -0
  183. package/dist/datepicker/root/draft-evaluation.js +56 -0
  184. package/dist/datepicker/root/focus-controller.d.ts +3 -0
  185. package/dist/datepicker/root/focus-controller.js +15 -0
  186. package/dist/datepicker/root/open-change.d.ts +5 -0
  187. package/dist/datepicker/root/open-change.js +13 -0
  188. package/dist/datepicker/root/open-controller.d.ts +7 -0
  189. package/dist/datepicker/root/open-controller.js +15 -0
  190. package/dist/datepicker/root/segment-controller.d.ts +8 -0
  191. package/dist/datepicker/root/segment-controller.js +53 -0
  192. package/dist/datepicker/root/segment-state.d.ts +18 -0
  193. package/dist/datepicker/root/segment-state.js +134 -0
  194. package/dist/datepicker/root/value-commit.d.ts +4 -0
  195. package/dist/datepicker/root/value-commit.js +8 -0
  196. package/dist/datepicker/segment/README.md +14 -0
  197. package/dist/datepicker/segment/date-picker-segment.svelte +319 -0
  198. package/dist/datepicker/segment/date-picker-segment.svelte.d.ts +9 -0
  199. package/dist/datepicker/trigger/README.md +14 -0
  200. package/dist/datepicker/trigger/date-picker-trigger.svelte +110 -0
  201. package/dist/datepicker/trigger/date-picker-trigger.svelte.d.ts +9 -0
  202. package/dist/dialog/content/dialog-content.svelte +6 -6
  203. package/dist/dialog/index.d.ts +3 -3
  204. package/dist/dialog/index.js +2 -2
  205. package/dist/dialog/root/context.d.ts +2 -1
  206. package/dist/dialog/root/dialog-root.svelte +9 -2
  207. package/dist/hooks/use-virtual-focus.svelte.js +3 -1
  208. package/dist/index.d.ts +31 -17
  209. package/dist/index.js +31 -17
  210. package/dist/input/README.md +38 -0
  211. package/dist/input/TODO.md +12 -0
  212. package/dist/input/input-test.svelte +43 -0
  213. package/dist/input/input-test.svelte.d.ts +12 -0
  214. package/dist/input/input.svelte +151 -7
  215. package/dist/input/input.svelte.d.ts +8 -2
  216. package/dist/listbox/index.d.ts +3 -3
  217. package/dist/listbox/index.js +3 -3
  218. package/dist/listbox/item/README.md +2 -1
  219. package/dist/listbox/item/listbox-item.svelte +260 -6
  220. package/dist/listbox/item/listbox-item.svelte.d.ts +6 -0
  221. package/dist/listbox/root/context.d.ts +6 -0
  222. package/dist/listbox/root/context.js +23 -13
  223. package/dist/listbox/root/listbox-test.svelte +14 -2
  224. package/dist/listbox/root/listbox-test.svelte.d.ts +1 -0
  225. package/dist/listbox/root/listbox.svelte +49 -2
  226. package/dist/listbox/root/listbox.svelte.d.ts +4 -2
  227. package/dist/popover/README.md +10 -0
  228. package/dist/popover/content/README.md +11 -0
  229. package/dist/popover/content/popover-content-standalone-test.svelte +28 -0
  230. package/dist/popover/content/popover-content-standalone-test.svelte.d.ts +6 -0
  231. package/dist/popover/content/popover-content-test.svelte +32 -2
  232. package/dist/popover/content/popover-content-test.svelte.d.ts +3 -1
  233. package/dist/popover/content/popover-content.svelte +277 -24
  234. package/dist/popover/content/popover-content.svelte.d.ts +5 -1
  235. package/dist/popover/index.d.ts +3 -3
  236. package/dist/popover/index.js +3 -5
  237. package/dist/popover/root/README.md +10 -15
  238. package/dist/popover/root/context.d.ts +16 -7
  239. package/dist/popover/root/context.js +0 -2
  240. package/dist/popover/root/focus-state.d.ts +4 -0
  241. package/dist/popover/root/focus-state.js +33 -0
  242. package/dist/popover/root/popover-root.svelte +90 -17
  243. package/dist/popover/root/popover-root.svelte.d.ts +2 -1
  244. package/dist/popover/root/popover-test.svelte +2 -1
  245. package/dist/popover/root/popover-test.svelte.d.ts +2 -1
  246. package/dist/popover/trigger/popover-trigger-button.svelte +8 -7
  247. package/dist/popover/trigger/popover-trigger.svelte +14 -5
  248. package/dist/portal/portal.svelte +3 -1
  249. package/dist/primitives/click-outside.d.ts +1 -1
  250. package/dist/primitives/click-outside.js +1 -1
  251. package/dist/primitives/floating.js +12 -4
  252. package/dist/primitives/focus-trap.d.ts +7 -2
  253. package/dist/primitives/focus-trap.js +50 -17
  254. package/dist/primitives/index.d.ts +1 -0
  255. package/dist/primitives/index.js +1 -0
  256. package/dist/primitives/input-modality.d.ts +7 -0
  257. package/dist/primitives/input-modality.js +125 -0
  258. package/dist/primitives/keyboard-navigation.d.ts +1 -0
  259. package/dist/primitives/keyboard-navigation.js +17 -0
  260. package/dist/table/IMPLEMENTATION_NOTES.md +9 -0
  261. package/dist/table/PLAN-HIDDEN-COLUMNS.md +152 -0
  262. package/dist/table/PLAN.md +1336 -0
  263. package/dist/table/README.md +143 -0
  264. package/dist/table/SELECTION_CHECKBOX_PLAN.md +234 -0
  265. package/dist/table/TODO.md +138 -0
  266. package/dist/table/body/README.md +26 -0
  267. package/dist/table/body/table-body.svelte +24 -0
  268. package/dist/table/body/table-body.svelte.d.ts +4 -0
  269. package/dist/table/cell/README.md +27 -0
  270. package/dist/table/cell/table-cell.svelte +265 -0
  271. package/dist/table/cell/table-cell.svelte.d.ts +4 -0
  272. package/dist/table/checkbox/README.md +40 -0
  273. package/dist/table/checkbox/table-checkbox-test.svelte +128 -0
  274. package/dist/table/checkbox/table-checkbox-test.svelte.d.ts +18 -0
  275. package/dist/table/checkbox/table-checkbox.svelte +235 -0
  276. package/dist/table/checkbox/table-checkbox.svelte.d.ts +4 -0
  277. package/dist/table/checkbox-indicator/README.md +31 -0
  278. package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte +15 -0
  279. package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte.d.ts +4 -0
  280. package/dist/table/column/README.md +36 -0
  281. package/dist/table/column/table-column.svelte +79 -0
  282. package/dist/table/column/table-column.svelte.d.ts +4 -0
  283. package/dist/table/column-header-cell/README.md +30 -0
  284. package/dist/table/column-header-cell/table-column-header-cell.svelte +271 -0
  285. package/dist/table/column-header-cell/table-column-header-cell.svelte.d.ts +4 -0
  286. package/dist/table/column-resizer/README.md +33 -0
  287. package/dist/table/column-resizer/table-column-resizer-fixed-width-test.svelte +57 -0
  288. package/dist/table/column-resizer/table-column-resizer-fixed-width-test.svelte.d.ts +3 -0
  289. package/dist/table/column-resizer/table-column-resizer-freeze-layout-test.svelte +52 -0
  290. package/dist/table/column-resizer/table-column-resizer-freeze-layout-test.svelte.d.ts +3 -0
  291. package/dist/table/column-resizer/table-column-resizer-narrow-min-width-test.svelte +76 -0
  292. package/dist/table/column-resizer/table-column-resizer-narrow-min-width-test.svelte.d.ts +3 -0
  293. package/dist/table/column-resizer/table-column-resizer-overflow-test.svelte +64 -0
  294. package/dist/table/column-resizer/table-column-resizer-overflow-test.svelte.d.ts +3 -0
  295. package/dist/table/column-resizer/table-column-resizer-padded-container-test.svelte +67 -0
  296. package/dist/table/column-resizer/table-column-resizer-padded-container-test.svelte.d.ts +3 -0
  297. package/dist/table/column-resizer/table-column-resizer-sandbox-overflow-test.svelte +87 -0
  298. package/dist/table/column-resizer/table-column-resizer-sandbox-overflow-test.svelte.d.ts +3 -0
  299. package/dist/table/column-resizer/table-column-resizer-selection-column-test.svelte +84 -0
  300. package/dist/table/column-resizer/table-column-resizer-selection-column-test.svelte.d.ts +3 -0
  301. package/dist/table/column-resizer/table-column-resizer-test.svelte +77 -0
  302. package/dist/table/column-resizer/table-column-resizer-test.svelte.d.ts +3 -0
  303. package/dist/table/column-resizer/table-column-resizer-three-column-relative-test.svelte +64 -0
  304. package/dist/table/column-resizer/table-column-resizer-three-column-relative-test.svelte.d.ts +3 -0
  305. package/dist/table/column-resizer/table-column-resizer.svelte +610 -0
  306. package/dist/table/column-resizer/table-column-resizer.svelte.d.ts +4 -0
  307. package/dist/table/empty-state/README.md +27 -0
  308. package/dist/table/empty-state/table-empty-state.svelte +33 -0
  309. package/dist/table/empty-state/table-empty-state.svelte.d.ts +4 -0
  310. package/dist/table/footer/README.md +26 -0
  311. package/dist/table/footer/table-footer.svelte +13 -0
  312. package/dist/table/footer/table-footer.svelte.d.ts +4 -0
  313. package/dist/table/header/README.md +26 -0
  314. package/dist/table/header/table-header.svelte +13 -0
  315. package/dist/table/header/table-header.svelte.d.ts +4 -0
  316. package/dist/table/index.d.ts +18 -0
  317. package/dist/table/index.js +17 -0
  318. package/dist/table/index.parts.d.ts +13 -0
  319. package/dist/table/index.parts.js +13 -0
  320. package/dist/table/root/README.md +66 -0
  321. package/dist/table/root/context.d.ts +228 -0
  322. package/dist/table/root/context.js +2111 -0
  323. package/dist/table/root/table-reorder-test.svelte +64 -0
  324. package/dist/table/root/table-reorder-test.svelte.d.ts +3 -0
  325. package/dist/table/root/table-root.svelte +553 -0
  326. package/dist/table/root/table-root.svelte.d.ts +4 -0
  327. package/dist/table/root/table-test.svelte +206 -0
  328. package/dist/table/root/table-test.svelte.d.ts +29 -0
  329. package/dist/table/row/README.md +29 -0
  330. package/dist/table/row/table-row.svelte +244 -0
  331. package/dist/table/row/table-row.svelte.d.ts +4 -0
  332. package/dist/table/sort-trigger/README.md +45 -0
  333. package/dist/table/sort-trigger/table-sort-trigger.svelte +183 -0
  334. package/dist/table/sort-trigger/table-sort-trigger.svelte.d.ts +4 -0
  335. package/dist/table/types.d.ts +95 -0
  336. package/dist/table/types.js +1 -0
  337. package/dist/table/utils/handle-body-keydown.d.ts +13 -0
  338. package/dist/table/utils/handle-body-keydown.js +67 -0
  339. package/dist/table/utils/visually-hidden-style.d.ts +1 -0
  340. package/dist/table/utils/visually-hidden-style.js +1 -0
  341. package/dist/test-utils/focus-contract.d.ts +3 -0
  342. package/dist/test-utils/focus-contract.js +26 -0
  343. package/dist/timepicker/IMPLEMENTATION_PLAN.md +254 -0
  344. package/dist/timepicker/README.md +97 -0
  345. package/dist/timepicker/TODO.md +86 -0
  346. package/dist/timepicker/clock/README.md +14 -0
  347. package/dist/timepicker/clock/time-picker-clock-test.svelte +45 -0
  348. package/dist/timepicker/clock/time-picker-clock-test.svelte.d.ts +11 -0
  349. package/dist/timepicker/clock/time-picker-clock.svelte +65 -0
  350. package/dist/timepicker/clock/time-picker-clock.svelte.d.ts +10 -0
  351. package/dist/timepicker/index.d.ts +14 -0
  352. package/dist/timepicker/index.js +14 -0
  353. package/dist/timepicker/index.parts.d.ts +8 -0
  354. package/dist/timepicker/index.parts.js +8 -0
  355. package/dist/timepicker/input/README.md +15 -0
  356. package/dist/timepicker/input/time-picker-input-forwarding-test.svelte +40 -0
  357. package/dist/timepicker/input/time-picker-input-forwarding-test.svelte.d.ts +3 -0
  358. package/dist/timepicker/input/time-picker-input.svelte +109 -0
  359. package/dist/timepicker/input/time-picker-input.svelte.d.ts +11 -0
  360. package/dist/timepicker/internal/strict-props.d.ts +4 -0
  361. package/dist/timepicker/internal/strict-props.js +51 -0
  362. package/dist/timepicker/popover/README.md +20 -0
  363. package/dist/timepicker/popover/time-picker-popover-unsafe-props-test.svelte +22 -0
  364. package/dist/timepicker/popover/time-picker-popover-unsafe-props-test.svelte.d.ts +3 -0
  365. package/dist/timepicker/popover/time-picker-popover.svelte +89 -0
  366. package/dist/timepicker/popover/time-picker-popover.svelte.d.ts +7 -0
  367. package/dist/timepicker/root/README.md +42 -0
  368. package/dist/timepicker/root/context.d.ts +51 -0
  369. package/dist/timepicker/root/context.js +15 -0
  370. package/dist/timepicker/root/time-picker-12h-test.svelte +22 -0
  371. package/dist/timepicker/root/time-picker-12h-test.svelte.d.ts +3 -0
  372. package/dist/timepicker/root/time-picker-bindable-test.svelte +25 -0
  373. package/dist/timepicker/root/time-picker-bindable-test.svelte.d.ts +3 -0
  374. package/dist/timepicker/root/time-picker-empty-test.svelte +20 -0
  375. package/dist/timepicker/root/time-picker-empty-test.svelte.d.ts +3 -0
  376. package/dist/timepicker/root/time-picker-root.svelte +625 -0
  377. package/dist/timepicker/root/time-picker-root.svelte.d.ts +28 -0
  378. package/dist/timepicker/root/time-picker-test.svelte +72 -0
  379. package/dist/timepicker/root/time-picker-test.svelte.d.ts +15 -0
  380. package/dist/timepicker/root/time-utils.d.ts +1 -0
  381. package/dist/timepicker/root/time-utils.js +3 -0
  382. package/dist/timepicker/segment/README.md +14 -0
  383. package/dist/timepicker/segment/time-picker-segment.svelte +365 -0
  384. package/dist/timepicker/segment/time-picker-segment.svelte.d.ts +9 -0
  385. package/dist/timepicker/trigger/README.md +14 -0
  386. package/dist/timepicker/trigger/time-picker-trigger-forwarding-test.svelte +35 -0
  387. package/dist/timepicker/trigger/time-picker-trigger-forwarding-test.svelte.d.ts +3 -0
  388. package/dist/timepicker/trigger/time-picker-trigger.svelte +122 -0
  389. package/dist/timepicker/trigger/time-picker-trigger.svelte.d.ts +9 -0
  390. package/dist/utils/date-only.d.ts +11 -0
  391. package/dist/utils/date-only.js +53 -0
  392. package/dist/utils/index.d.ts +1 -0
  393. package/dist/utils/index.js +1 -0
  394. package/package.json +31 -1
@@ -3,6 +3,11 @@
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
4
  import { useListBoxContext } from '../root/context';
5
5
  import { onMount, onDestroy } from 'svelte';
6
+ import {
7
+ focusWithModality,
8
+ shouldShowFocusVisible,
9
+ trackInteractionModality
10
+ } from '../../primitives/input-modality';
6
11
 
7
12
  /**
8
13
  * Props for the ListBox.Item component.
@@ -26,14 +31,20 @@
26
31
  disableFocusHandling?: boolean;
27
32
  /** Override the focused state. When provided, this value is used instead of internal focus tracking. */
28
33
  isFocusedOverride?: boolean;
34
+ /** Override the focus-visible presentation state. */
35
+ isFocusVisibleOverride?: boolean;
29
36
  /** Override the select behavior. When provided, called instead of default listbox selection. */
30
37
  onItemSelect?: (id: string | number, label: string) => void;
31
38
  /** Callback with resolved text value when mounted (from prop or rendered content). */
32
39
  onResolvedTextValue?: (label: string) => void;
40
+ /** Callback when pointer hover should move logical focus to this item. */
41
+ onItemHoverStart?: (id: string | number, label: string) => void;
33
42
  /** Whether to scroll this item into view when focused. Useful for virtual focus patterns. */
34
43
  scrollOnFocus?: boolean;
35
44
  /** Additional disabled state from parent. */
36
45
  isParentDisabled?: boolean;
46
+ /** Override the visual pressed state. When provided, this value is used instead of internal press tracking. */
47
+ pressed?: boolean;
37
48
  };
38
49
 
39
50
  let {
@@ -46,10 +57,13 @@
46
57
  customId,
47
58
  disableFocusHandling = false,
48
59
  isFocusedOverride,
60
+ isFocusVisibleOverride,
49
61
  onItemSelect,
50
62
  onResolvedTextValue,
63
+ onItemHoverStart,
51
64
  scrollOnFocus = false,
52
65
  isParentDisabled = false,
66
+ pressed: pressedOverride,
53
67
  ...restProps
54
68
  }: ListBoxItemProps = $props();
55
69
 
@@ -58,7 +72,12 @@
58
72
  let elementRef: HTMLElement;
59
73
  let isSelected = $state(false);
60
74
  let isFocused = $state(false);
75
+ let isFocusVisible = $state(false);
76
+ let listFocusVisible = $state(false);
61
77
  let isHovered = $state(false);
78
+ let isPressed = $state(false);
79
+ let pressedKey: 'Enter' | 'Space' | null = $state(null);
80
+ let suppressNextFocusVisible = $state(false);
62
81
 
63
82
  // Focus: use override if provided, otherwise use internal state
64
83
  const isFocusedComputed = $derived(
@@ -67,12 +86,28 @@
67
86
  const isDisabledComputed = $derived(
68
87
  disabled || listboxCtx.disabledIds.has(id) || isParentDisabled
69
88
  );
89
+ const isPressedComputed = $derived(
90
+ pressedOverride !== undefined
91
+ ? Boolean(pressedOverride) && !isDisabledComputed
92
+ : isPressed && !isDisabledComputed
93
+ );
94
+ const isFocusVisibleComputed = $derived(
95
+ isFocusVisibleOverride !== undefined ? isFocusVisibleOverride : isFocusVisible
96
+ );
97
+ const isActiveFocusVisible = $derived(
98
+ isFocusVisibleOverride !== undefined
99
+ ? isFocusVisibleComputed
100
+ : isFocusedComputed && listFocusVisible
101
+ );
102
+ const showFocusVisible = $derived(isActiveFocusVisible && !isHovered);
103
+ const showHovered = $derived(isHovered && !isActiveFocusVisible);
70
104
 
71
105
  // ID: use custom if provided, otherwise generate
72
106
  const uniqueId = $derived(customId ?? `listbox-item-${id}`);
73
107
 
74
108
  let unsubscribeSelection: (() => void) | null = null;
75
109
  let unsubscribeFocus: (() => void) | null = null;
110
+ let unsubscribeFocusVisible: (() => void) | null = null;
76
111
 
77
112
  function getResolvedTextValue() {
78
113
  return textValue || elementRef?.textContent?.trim() || String(id);
@@ -94,6 +129,9 @@
94
129
  unsubscribeFocus = listboxCtx.subscribeToFocus(id, (focused) => {
95
130
  isFocused = focused;
96
131
  });
132
+ unsubscribeFocusVisible = listboxCtx.subscribeToFocusVisible((visible) => {
133
+ listFocusVisible = visible;
134
+ });
97
135
  listboxCtx.keyboardNav.updateItems();
98
136
  }
99
137
  });
@@ -102,58 +140,265 @@
102
140
  listboxCtx.unregisterItem(id);
103
141
  unsubscribeSelection?.();
104
142
  unsubscribeFocus?.();
143
+ unsubscribeFocusVisible?.();
105
144
  });
106
145
 
107
146
  // Scroll into view when focused (if enabled)
108
147
  $effect(() => {
109
- if (scrollOnFocus && isFocusedComputed && elementRef) {
148
+ if (scrollOnFocus && isFocusedComputed && isFocusVisibleComputed && elementRef) {
110
149
  requestAnimationFrame(() => {
111
150
  elementRef?.scrollIntoView({ block: 'nearest' });
112
151
  });
113
152
  }
114
153
  });
115
154
 
155
+ $effect(() => {
156
+ if (!isDisabledComputed) return;
157
+ clearPressedState();
158
+ isHovered = false;
159
+ isFocusVisible = false;
160
+ });
161
+
162
+ $effect(() => {
163
+ if (!isFocusedComputed) {
164
+ if (pressedKey !== null) {
165
+ clearPressedState();
166
+ }
167
+ return;
168
+ }
169
+
170
+ if (listFocusVisible || isFocusVisibleComputed) {
171
+ isHovered = false;
172
+ }
173
+ });
174
+
175
+ function clearPressedState() {
176
+ isPressed = false;
177
+ pressedKey = null;
178
+ }
179
+
180
+ function applyPointerFocusState() {
181
+ suppressNextFocusVisible = true;
182
+ listboxCtx.setFocusVisible(false);
183
+ listboxCtx.setFocusedId(id);
184
+ listboxCtx.keyboardNav.setCurrentId(id);
185
+ if (elementRef) {
186
+ focusWithModality(elementRef, 'pointer');
187
+ }
188
+ }
189
+
190
+ function transferHoverFocus() {
191
+ const label = getResolvedTextValue();
192
+ if (onItemHoverStart) {
193
+ onItemHoverStart(id, label);
194
+ } else if (!disableFocusHandling) {
195
+ applyPointerFocusState();
196
+ requestAnimationFrame(() => {
197
+ if (isHovered && !isDisabledComputed) {
198
+ applyPointerFocusState();
199
+ }
200
+ });
201
+ }
202
+ }
203
+
116
204
  function handleClick() {
117
205
  if (isDisabledComputed) return;
118
206
 
119
207
  const label = getResolvedTextValue();
120
208
 
209
+ if (!disableFocusHandling && elementRef) {
210
+ suppressNextFocusVisible = true;
211
+ isFocusVisible = false;
212
+ listboxCtx.setFocusVisible(false);
213
+ listboxCtx.setFocusedId(id);
214
+ listboxCtx.keyboardNav.setCurrentId(id);
215
+ focusWithModality(elementRef, 'pointer');
216
+ }
217
+
121
218
  // Use custom select handler if provided, otherwise use listbox default
122
219
  if (onItemSelect) {
123
220
  onItemSelect(id, label);
124
221
  } else {
125
222
  listboxCtx.select(id);
126
- listboxCtx.setFocusedId(id);
223
+ }
224
+
225
+ if (!disableFocusHandling) {
226
+ listboxCtx.keyboardNav.setCurrentId(id);
127
227
  }
128
228
  }
129
229
 
130
230
  function handleFocus() {
231
+ if (isDisabledComputed) return;
232
+ isFocusVisible = suppressNextFocusVisible ? false : shouldShowFocusVisible(elementRef);
233
+ suppressNextFocusVisible = false;
234
+ if (isFocusVisible) {
235
+ isHovered = false;
236
+ }
131
237
  if (!disableFocusHandling) {
238
+ listboxCtx.setFocusVisible(isFocusVisible);
132
239
  listboxCtx.setFocusedId(id);
133
240
  }
134
241
  }
135
242
 
136
- function handleBlur() {}
243
+ function handleBlur() {
244
+ isFocusVisible = false;
245
+ if (!disableFocusHandling && listboxCtx.isFocused(id)) {
246
+ listboxCtx.setFocusVisible(false);
247
+ listboxCtx.setFocusedId(null);
248
+ }
249
+ }
250
+
251
+ function handlePointerDown(event: PointerEvent) {
252
+ trackInteractionModality(event, elementRef);
253
+ isFocusVisible = false;
254
+ if (!disableFocusHandling) {
255
+ listboxCtx.setFocusVisible(false);
256
+ }
137
257
 
138
- function handleMouseEnter() {
258
+ if (isDisabledComputed) {
259
+ event.preventDefault();
260
+ clearPressedState();
261
+ return;
262
+ }
263
+
264
+ if (event.button !== 0) return;
265
+ isPressed = true;
266
+ pressedKey = null;
267
+ }
268
+
269
+ function handlePointerUp(event: PointerEvent) {
270
+ if (event.button !== 0) return;
271
+ isPressed = false;
272
+ pressedKey = null;
273
+ }
274
+
275
+ function handlePointerCancel() {
276
+ clearPressedState();
277
+ }
278
+
279
+ function handlePointerEnter(event: PointerEvent) {
280
+ if (isDisabledComputed) return;
281
+
282
+ trackInteractionModality(event, elementRef);
283
+ if (!disableFocusHandling) {
284
+ listboxCtx.setFocusVisible(false);
285
+ }
286
+ transferHoverFocus();
287
+
288
+ if ((event.buttons & 1) === 1 && pressedKey === null) {
289
+ isPressed = true;
290
+ }
291
+ }
292
+
293
+ function handlePointerLeave() {
294
+ if (pressedKey === null) {
295
+ isPressed = false;
296
+ }
297
+ }
298
+
299
+ function handleMouseEnter(event: MouseEvent) {
139
300
  if (!isDisabledComputed) {
301
+ trackInteractionModality(event, elementRef);
140
302
  isHovered = true;
303
+ isFocusVisible = false;
304
+ if (!disableFocusHandling) {
305
+ listboxCtx.setFocusVisible(false);
306
+ transferHoverFocus();
307
+ }
141
308
  }
142
309
  }
143
310
 
144
311
  function handleMouseLeave() {
145
312
  isHovered = false;
313
+ if (pressedKey === null) {
314
+ isPressed = false;
315
+ }
146
316
  }
147
317
 
148
318
  // Keyboard is handled by parent container
149
- function handleKeydown() {}
319
+ function handleKeydown(event: KeyboardEvent) {
320
+ trackInteractionModality(event, elementRef);
321
+ if (isFocusedComputed) {
322
+ isHovered = false;
323
+ isFocusVisible = true;
324
+ if (!disableFocusHandling) {
325
+ listboxCtx.setFocusVisible(true);
326
+ }
327
+ }
328
+
329
+ const key =
330
+ event.key === 'Enter'
331
+ ? 'Enter'
332
+ : event.key === ' ' || event.key === 'Spacebar'
333
+ ? 'Space'
334
+ : null;
335
+
336
+ if (!key) return;
337
+
338
+ if (isDisabledComputed) {
339
+ event.preventDefault();
340
+ clearPressedState();
341
+ return;
342
+ }
343
+
344
+ if (event.repeat && isPressed && pressedKey === key) return;
345
+
346
+ isPressed = true;
347
+ pressedKey = key;
348
+ }
349
+
350
+ function handleKeyup(event: KeyboardEvent) {
351
+ const key =
352
+ event.key === 'Enter'
353
+ ? 'Enter'
354
+ : event.key === ' ' || event.key === 'Spacebar'
355
+ ? 'Space'
356
+ : null;
357
+
358
+ if (!key) return;
359
+
360
+ if (isDisabledComputed) {
361
+ event.preventDefault();
362
+ clearPressedState();
363
+ return;
364
+ }
365
+
366
+ if (pressedKey === key) {
367
+ clearPressedState();
368
+ }
369
+ }
370
+
150
371
  function handleMouseDown(event: MouseEvent) {
372
+ trackInteractionModality(event, elementRef);
373
+ isFocusVisible = false;
374
+ if (!disableFocusHandling) {
375
+ listboxCtx.setFocusVisible(false);
376
+ }
377
+
151
378
  // Prevent focus stealing when used in ComboBox (disableFocusHandling=true)
152
379
  // This keeps the focus on the input while allowing click selection
380
+ if (isDisabledComputed) {
381
+ event.preventDefault();
382
+ clearPressedState();
383
+ return;
384
+ }
385
+
386
+ if (event.button === 0) {
387
+ isPressed = true;
388
+ pressedKey = null;
389
+ }
390
+
153
391
  if (disableFocusHandling) {
154
392
  event.preventDefault();
155
393
  }
156
394
  }
395
+
396
+ function handleMouseUp(event: MouseEvent) {
397
+ if (event.button !== 0) return;
398
+ if (pressedKey === null) {
399
+ clearPressedState();
400
+ }
401
+ }
157
402
  </script>
158
403
 
159
404
  <div
@@ -170,10 +415,19 @@
170
415
  data-selected={isSelected || undefined}
171
416
  data-disabled={isDisabledComputed || undefined}
172
417
  data-focused={isFocusedComputed || undefined}
173
- data-hovered={isHovered || undefined}
418
+ data-focus-visible={showFocusVisible || undefined}
419
+ data-hovered={showHovered || undefined}
420
+ data-pressed={isPressedComputed || undefined}
421
+ onpointerdown={handlePointerDown}
422
+ onpointerup={handlePointerUp}
423
+ onpointercancel={handlePointerCancel}
424
+ onpointerenter={handlePointerEnter}
425
+ onpointerleave={handlePointerLeave}
174
426
  onmousedown={handleMouseDown}
427
+ onmouseup={handleMouseUp}
175
428
  onclick={handleClick}
176
429
  onkeydown={handleKeydown}
430
+ onkeyup={handleKeyup}
177
431
  onfocus={handleFocus}
178
432
  onblur={handleBlur}
179
433
  onmouseenter={handleMouseEnter}
@@ -20,14 +20,20 @@ type ListBoxItemProps = Omit<HTMLAttributes<HTMLDivElement>, 'id' | 'children'>
20
20
  disableFocusHandling?: boolean;
21
21
  /** Override the focused state. When provided, this value is used instead of internal focus tracking. */
22
22
  isFocusedOverride?: boolean;
23
+ /** Override the focus-visible presentation state. */
24
+ isFocusVisibleOverride?: boolean;
23
25
  /** Override the select behavior. When provided, called instead of default listbox selection. */
24
26
  onItemSelect?: (id: string | number, label: string) => void;
25
27
  /** Callback with resolved text value when mounted (from prop or rendered content). */
26
28
  onResolvedTextValue?: (label: string) => void;
29
+ /** Callback when pointer hover should move logical focus to this item. */
30
+ onItemHoverStart?: (id: string | number, label: string) => void;
27
31
  /** Whether to scroll this item into view when focused. Useful for virtual focus patterns. */
28
32
  scrollOnFocus?: boolean;
29
33
  /** Additional disabled state from parent. */
30
34
  isParentDisabled?: boolean;
35
+ /** Override the visual pressed state. When provided, this value is used instead of internal press tracking. */
36
+ pressed?: boolean;
31
37
  };
32
38
  declare const ListboxItem: import("svelte").Component<ListBoxItemProps, {}, "">;
33
39
  type ListboxItem = ReturnType<typeof ListboxItem>;
@@ -20,6 +20,8 @@ export type ListBoxContext = {
20
20
  isDisabled: (id: string | number) => boolean;
21
21
  /** Checks if an item is focused. */
22
22
  isFocused: (id: string | number) => boolean;
23
+ /** Whether keyboard focus-visible should be shown for the currently focused item. */
24
+ getFocusVisible: () => boolean;
23
25
  /** Keyboard navigation controller from the shared primitive. */
24
26
  keyboardNav: KeyboardNavigationReturn;
25
27
  /** Map of registered items with their metadata. */
@@ -45,10 +47,14 @@ export type ListBoxContext = {
45
47
  setSelection: (selection: Set<string | number>) => void;
46
48
  /** Sets the focused item ID. */
47
49
  setFocusedId: (id: string | number | null) => void;
50
+ /** Sets whether the focused item should render keyboard focus-visible. */
51
+ setFocusVisible: (visible: boolean) => void;
48
52
  /** Subscribes to selection changes for a specific item. Returns unsubscribe function. */
49
53
  subscribeToItem: (id: string | number, callback: (selected: boolean) => void) => () => void;
50
54
  /** Subscribes to focus changes for a specific item. Returns unsubscribe function. */
51
55
  subscribeToFocus: (id: string | number, callback: (focused: boolean) => void) => () => void;
56
+ /** Subscribes to focus-visible state changes. Returns unsubscribe function. */
57
+ subscribeToFocusVisible: (callback: (visible: boolean) => void) => () => void;
52
58
  /** Returns the next item ID respecting loop setting, or null if at end. */
53
59
  getNextItemId: (currentId: string | number | null) => string | number | null;
54
60
  /** Returns the previous item ID respecting loop setting, or null if at start. */
@@ -53,30 +53,30 @@ export function createListBoxContext(options = {}) {
53
53
  }
54
54
  let focusedId = null;
55
55
  const focusCallbacks = new Map();
56
+ let focusVisible = false;
57
+ const focusVisibleCallbacks = new Set();
56
58
  function getFocusedId() {
57
59
  return focusedId;
58
60
  }
59
61
  function isFocused(id) {
60
62
  return focusedId === id || String(focusedId) === String(id);
61
63
  }
62
- function notifyFocus(id, focused) {
63
- const callbacks = focusCallbacks.get(id);
64
- if (callbacks) {
65
- callbacks.forEach((cb) => cb(focused));
66
- }
64
+ function getFocusVisible() {
65
+ return focusVisible;
67
66
  }
68
67
  function setFocusedId(newId) {
69
- if (focusedId === newId)
70
- return;
71
- const previousId = focusedId;
72
68
  focusedId = newId;
73
- if (previousId !== null) {
74
- notifyFocus(previousId, false);
75
- }
76
- if (newId !== null) {
77
- notifyFocus(newId, true);
69
+ for (const [id, callbacks] of focusCallbacks) {
70
+ const focused = newId !== null && (id === newId || String(id) === String(newId));
71
+ callbacks.forEach((callback) => callback(focused));
78
72
  }
79
73
  }
74
+ function setFocusVisible(visible) {
75
+ if (focusVisible === visible)
76
+ return;
77
+ focusVisible = visible;
78
+ focusVisibleCallbacks.forEach((callback) => callback(visible));
79
+ }
80
80
  function subscribeToFocus(id, callback) {
81
81
  if (!focusCallbacks.has(id)) {
82
82
  focusCallbacks.set(id, new Set());
@@ -93,6 +93,13 @@ export function createListBoxContext(options = {}) {
93
93
  }
94
94
  };
95
95
  }
96
+ function subscribeToFocusVisible(callback) {
97
+ focusVisibleCallbacks.add(callback);
98
+ callback(focusVisible);
99
+ return () => {
100
+ focusVisibleCallbacks.delete(callback);
101
+ };
102
+ }
96
103
  function subscribeToItem(id, callback) {
97
104
  if (!itemCallbacks.has(id)) {
98
105
  itemCallbacks.set(id, new Set());
@@ -221,6 +228,7 @@ export function createListBoxContext(options = {}) {
221
228
  isSelected,
222
229
  isDisabled,
223
230
  isFocused,
231
+ getFocusVisible,
224
232
  keyboardNav,
225
233
  items,
226
234
  registerItem,
@@ -232,8 +240,10 @@ export function createListBoxContext(options = {}) {
232
240
  selectAll,
233
241
  setSelection,
234
242
  setFocusedId,
243
+ setFocusVisible,
235
244
  subscribeToItem,
236
245
  subscribeToFocus,
246
+ subscribeToFocusVisible,
237
247
  getNextItemId,
238
248
  getPreviousItemId
239
249
  };
@@ -5,9 +5,17 @@
5
5
  selectionMode?: 'single' | 'multiple';
6
6
  selectionBehavior?: 'toggle' | 'replace';
7
7
  disabledIds?: Iterable<string | number>;
8
+ pressedIds?: Iterable<string | number>;
8
9
  };
9
10
 
10
- let { selectionMode = 'single', selectionBehavior = 'toggle', disabledIds }: Props = $props();
11
+ let {
12
+ selectionMode = 'single',
13
+ selectionBehavior = 'toggle',
14
+ disabledIds,
15
+ pressedIds
16
+ }: Props = $props();
17
+
18
+ const pressedIdSet = $derived(new Set(pressedIds ?? []));
11
19
 
12
20
  const fruits = [
13
21
  { id: 'apple', name: 'Apple' },
@@ -20,7 +28,11 @@
20
28
 
21
29
  <ListBox.Root {selectionMode} {selectionBehavior} {disabledIds} aria-label="Fruits list">
22
30
  {#each fruits as fruit (fruit.id)}
23
- <ListBox.Item id={fruit.id} textValue={fruit.name}>
31
+ <ListBox.Item
32
+ id={fruit.id}
33
+ textValue={fruit.name}
34
+ pressed={pressedIdSet.has(fruit.id) ? true : undefined}
35
+ >
24
36
  {fruit.name}
25
37
  </ListBox.Item>
26
38
  {/each}
@@ -2,6 +2,7 @@ type Props = {
2
2
  selectionMode?: 'single' | 'multiple';
3
3
  selectionBehavior?: 'toggle' | 'replace';
4
4
  disabledIds?: Iterable<string | number>;
5
+ pressedIds?: Iterable<string | number>;
5
6
  };
6
7
  declare const ListboxTest: import("svelte").Component<Props, {}, "">;
7
8
  type ListboxTest = ReturnType<typeof ListboxTest>;
@@ -1,6 +1,8 @@
1
1
  <script lang="ts" generics="T extends object = object">
2
2
  import type { Snippet } from 'svelte';
3
+ import { onMount } from 'svelte';
3
4
  import { createListBoxContext, type ListBoxContext } from './context';
5
+ import { trackInteractionModality } from '../../primitives/input-modality';
4
6
 
5
7
  /**
6
8
  * Props for the ListBox component.
@@ -31,6 +33,8 @@
31
33
  'aria-label'?: string;
32
34
  /** Callback fired when the selection changes. */
33
35
  onChange?: (value: Set<string | number>) => void;
36
+ /** Disable DOM focus handling on the root container for virtual-focus compositions. */
37
+ disableFocusHandling?: boolean;
34
38
  };
35
39
 
36
40
  let {
@@ -46,6 +50,7 @@
46
50
  id,
47
51
  'aria-label': ariaLabel,
48
52
  onChange,
53
+ disableFocusHandling = false,
49
54
  context = $bindable(),
50
55
  element = $bindable()
51
56
  }: ListBoxProps & { context?: ListBoxContext; element?: HTMLElement } = $props();
@@ -114,6 +119,43 @@
114
119
 
115
120
  const itemsArray = $derived(items ? Array.from(items) : []);
116
121
  const hasItems = $derived(itemsArray.length > 0 || itemCount > 0);
122
+ let hasMounted = $state(false);
123
+
124
+ let focusWithin = $state(false);
125
+
126
+ onMount(() => {
127
+ hasMounted = true;
128
+ });
129
+
130
+ function syncFocusWithin() {
131
+ focusWithin =
132
+ !!listboxElement &&
133
+ !!document.activeElement &&
134
+ listboxElement.contains(document.activeElement);
135
+ }
136
+
137
+ function handleFocusIn() {
138
+ focusWithin = true;
139
+ }
140
+
141
+ function handleFocusOut() {
142
+ queueMicrotask(syncFocusWithin);
143
+ }
144
+
145
+ function handleMouseDown(event: MouseEvent) {
146
+ trackInteractionModality(event, event.target as HTMLElement | null);
147
+ ctx.setFocusVisible(false);
148
+ if (disableFocusHandling) {
149
+ event.preventDefault();
150
+ }
151
+ }
152
+
153
+ function handleKeyDown(event: KeyboardEvent) {
154
+ trackInteractionModality(event, event.target as HTMLElement | null);
155
+ if (focusWithin) {
156
+ ctx.setFocusVisible(true);
157
+ }
158
+ }
117
159
  </script>
118
160
 
119
161
  <div
@@ -123,8 +165,13 @@
123
165
  aria-multiselectable={selectionMode === 'multiple'}
124
166
  aria-label={ariaLabel}
125
167
  class={className}
126
- tabindex="0"
168
+ tabindex={disableFocusHandling ? undefined : 0}
169
+ data-focus-within={focusWithin || undefined}
127
170
  use:keyboardAction
171
+ onfocusin={handleFocusIn}
172
+ onfocusout={handleFocusOut}
173
+ onmousedown={handleMouseDown}
174
+ onkeydown={handleKeyDown}
128
175
  >
129
176
  {#if items && children}
130
177
  {#each itemsArray as item (item)}
@@ -134,7 +181,7 @@
134
181
  {@render (children as Snippet)()}
135
182
  {/if}
136
183
 
137
- {#if !hasItems && itemCount === 0}
184
+ {#if hasMounted && !hasItems && itemCount === 0}
138
185
  {#if typeof emptyPlaceholder === 'string'}
139
186
  <div role="option" aria-selected="false" aria-disabled="true" data-empty-placeholder>
140
187
  {emptyPlaceholder}
@@ -26,12 +26,14 @@ declare function $$render<T extends object = object>(): {
26
26
  'aria-label'?: string;
27
27
  /** Callback fired when the selection changes. */
28
28
  onChange?: (value: Set<string | number>) => void;
29
+ /** Disable DOM focus handling on the root container for virtual-focus compositions. */
30
+ disableFocusHandling?: boolean;
29
31
  } & {
30
32
  context?: ListBoxContext;
31
33
  element?: HTMLElement;
32
34
  };
33
35
  exports: {};
34
- bindings: "value" | "context" | "element";
36
+ bindings: "value" | "element" | "context";
35
37
  slots: {};
36
38
  events: {};
37
39
  };
@@ -39,7 +41,7 @@ declare class __sveltets_Render<T extends object = object> {
39
41
  props(): ReturnType<typeof $$render<T>>['props'];
40
42
  events(): ReturnType<typeof $$render<T>>['events'];
41
43
  slots(): ReturnType<typeof $$render<T>>['slots'];
42
- bindings(): "value" | "context" | "element";
44
+ bindings(): "value" | "element" | "context";
43
45
  exports(): {};
44
46
  }
45
47
  interface $$IsomorphicComponent {
@@ -12,6 +12,16 @@
12
12
  - Use `Popover.Content` inside `Popover.Root`, or in standalone mode with `open`, `triggerRef`, and `onOpenChange`.
13
13
  - Configure `isNonModal`, `shouldCloseOnInteractOutside`, and `shouldCloseOnBlur` to match your interaction model.
14
14
 
15
+ ## onOpenChange details
16
+
17
+ `Popover.Root` and standalone `Popover.Content` use:
18
+
19
+ - `onOpenChange(open, details)`
20
+ - `details.reason`: `trigger-press | imperative-action | none | escape-key | outside-press | focus-out | close-press`
21
+ - `details.event?`: native event that triggered the change when available
22
+ - `details.cancel()`: prevents the open-state transition
23
+ - `details.isCanceled`: reflects cancellation state inside the callback
24
+
15
25
  ## Anatomy
16
26
 
17
27
  Import the component and compose its parts: