entasis 0.11.0 → 0.12.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 (839) hide show
  1. package/README.md +1 -1
  2. package/dist/attachments/disclosurePanel.svelte.d.ts +84 -0
  3. package/dist/attachments/disclosurePanel.svelte.js +277 -0
  4. package/dist/attachments/portal.d.ts +17 -1
  5. package/dist/attachments/portal.js +39 -2
  6. package/dist/attachments/spinnerOverlay.svelte.js +12 -0
  7. package/dist/attachments/transitionSize.d.ts +6 -0
  8. package/dist/attachments/transitionSize.js +30 -0
  9. package/dist/components/AIAskUserQuestion/AIAskUserQuestion.svelte +131 -17
  10. package/dist/components/AIAskUserQuestion/AIAskUserQuestionFileStep.svelte +26 -6
  11. package/dist/components/AIAskUserQuestion/AIAskUserQuestionFileStep.svelte.d.ts +6 -0
  12. package/dist/components/AIAskUserQuestion/AIAskUserQuestionFooter.svelte +27 -53
  13. package/dist/components/AIAskUserQuestion/AIAskUserQuestionFooter.svelte.d.ts +3 -4
  14. package/dist/components/AIAskUserQuestion/AIAskUserQuestionHeader.svelte +19 -16
  15. package/dist/components/AIAskUserQuestion/AIAskUserQuestionStep.svelte +180 -21
  16. package/dist/components/AIAskUserQuestion/AIAskUserQuestionStep.svelte.d.ts +9 -1
  17. package/dist/components/AIAskUserQuestion/AIAskUserQuestionSummary.svelte +56 -0
  18. package/dist/components/AIAskUserQuestion/AIAskUserQuestionSummary.svelte.d.ts +4 -0
  19. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.mcp.d.ts +1 -1
  20. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.mcp.js +26 -8
  21. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.props.d.ts +62 -5
  22. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.theme.d.ts +42 -0
  23. package/dist/components/AIAskUserQuestion/aiAskUserQuestion.theme.js +53 -12
  24. package/dist/components/AIAskUserQuestion/aiAskUserQuestionAnswers.d.ts +17 -1
  25. package/dist/components/AIAskUserQuestion/aiAskUserQuestionAnswers.js +56 -8
  26. package/dist/components/AIAskUserQuestion/index.d.ts +3 -1
  27. package/dist/components/AIAskUserQuestion/index.js +2 -0
  28. package/dist/components/AIAskUserQuestion/schemas.d.ts +44 -0
  29. package/dist/components/AIAskUserQuestion/schemas.js +10 -3
  30. package/dist/components/AIChat/AIChat.svelte +10 -0
  31. package/dist/components/AIChat/AIChat.svelte.d.ts +2 -2
  32. package/dist/components/AIChat/AIChatComposerSurface.svelte +23 -5
  33. package/dist/components/AIChat/AIChatComposerSurface.svelte.d.ts +5 -0
  34. package/dist/components/AIChat/AIChatSkeleton.svelte +29 -37
  35. package/dist/components/AIChat/AIChatSurface.svelte +30 -2
  36. package/dist/components/AIChat/AIChatSurface.svelte.d.ts +1 -1
  37. package/dist/components/AIChat/AIChatThreadSurface.svelte +11 -1
  38. package/dist/components/AIChat/AIChatThreadSurface.svelte.d.ts +3 -1
  39. package/dist/components/AIChat/aiChat.mcp.d.ts +1 -1
  40. package/dist/components/AIChat/aiChat.mcp.js +31 -15
  41. package/dist/components/AIChat/aiChat.props.d.ts +36 -10
  42. package/dist/components/AIChat/aiChat.theme.d.ts +9 -0
  43. package/dist/components/AIChat/aiChat.theme.js +21 -4
  44. package/dist/components/AIChat/aiChatSkeleton.props.d.ts +5 -0
  45. package/dist/components/AIChat/index.d.ts +1 -1
  46. package/dist/components/AIComposer/AIComposer.svelte +102 -5
  47. package/dist/components/AIComposer/AIComposer.svelte.d.ts +1 -0
  48. package/dist/components/AIComposer/AIComposerFooter.svelte +54 -12
  49. package/dist/components/AIComposer/AIComposerFooter.svelte.d.ts +2 -0
  50. package/dist/components/AIComposer/AIComposerQueue.svelte +8 -3
  51. package/dist/components/AIComposer/aiComposer.editor.theme.js +13 -2
  52. package/dist/components/AIComposer/aiComposer.mcp.d.ts +1 -1
  53. package/dist/components/AIComposer/aiComposer.mcp.js +15 -7
  54. package/dist/components/AIComposer/aiComposer.props.d.ts +27 -7
  55. package/dist/components/AIComposer/aiComposer.theme.d.ts +42 -3
  56. package/dist/components/AIComposer/aiComposer.theme.js +37 -5
  57. package/dist/components/AIComposer/aiComposerFileController.svelte.d.ts +20 -0
  58. package/dist/components/AIComposer/aiComposerFileController.svelte.js +75 -9
  59. package/dist/components/AIComposer/aiComposerSourceAdapter.js +22 -4
  60. package/dist/components/AIComposer/aiComposerSubmitController.svelte.d.ts +12 -0
  61. package/dist/components/AIComposer/aiComposerSubmitController.svelte.js +16 -6
  62. package/dist/components/AIContext/AIContext.svelte +7 -3
  63. package/dist/components/AIContext/aiContext.mcp.d.ts +1 -1
  64. package/dist/components/AIContext/aiContext.mcp.js +1 -1
  65. package/dist/components/AIContext/aiContext.props.d.ts +4 -1
  66. package/dist/components/AIContext/aiContext.theme.d.ts +3 -0
  67. package/dist/components/AIContext/aiContext.theme.js +7 -2
  68. package/dist/components/AIConversation/AIConversation.svelte.d.ts +2 -2
  69. package/dist/components/AIFilePreview/aiFilePreview.theme.js +1 -1
  70. package/dist/components/AIMarker/AIMarker.svelte +2 -0
  71. package/dist/components/AIMarker/aiMarker.mcp.d.ts +1 -1
  72. package/dist/components/AIMarker/aiMarker.mcp.js +2 -0
  73. package/dist/components/AIMarker/aiMarker.props.d.ts +3 -0
  74. package/dist/components/AIMarker/aiMarker.theme.js +2 -2
  75. package/dist/components/AIMessage/AIMessage.svelte +38 -16
  76. package/dist/components/AIMessage/aiMessage.mcp.d.ts +1 -1
  77. package/dist/components/AIMessage/aiMessage.mcp.js +20 -6
  78. package/dist/components/AIMessage/aiMessage.props.d.ts +18 -2
  79. package/dist/components/AIMessage/aiMessage.theme.d.ts +51 -6
  80. package/dist/components/AIMessage/aiMessage.theme.js +91 -32
  81. package/dist/components/AIMessageActions/AIMessageActions.svelte +19 -9
  82. package/dist/components/AIMessageActions/aiMessageActions.mcp.d.ts +1 -1
  83. package/dist/components/AIMessageActions/aiMessageActions.mcp.js +11 -3
  84. package/dist/components/AIMessageActions/aiMessageActions.theme.js +36 -9
  85. package/dist/components/AIModelSelector/AIModelSelector.svelte +25 -10
  86. package/dist/components/AIModelSelector/aiModelSelector.mcp.d.ts +1 -1
  87. package/dist/components/AIModelSelector/aiModelSelector.mcp.js +1 -1
  88. package/dist/components/AIModelSelector/aiModelSelector.theme.d.ts +3 -0
  89. package/dist/components/AIModelSelector/aiModelSelector.theme.js +7 -3
  90. package/dist/components/AIReasoning/AIReasoning.svelte +135 -38
  91. package/dist/components/AIReasoning/aiReasoning.mcp.d.ts +1 -1
  92. package/dist/components/AIReasoning/aiReasoning.mcp.js +11 -5
  93. package/dist/components/AIReasoning/aiReasoning.props.d.ts +15 -4
  94. package/dist/components/AIReasoning/aiReasoning.theme.d.ts +45 -0
  95. package/dist/components/AIReasoning/aiReasoning.theme.js +47 -7
  96. package/dist/components/AISuggestion/AISuggestion.svelte +2 -1
  97. package/dist/components/AISuggestion/AISuggestions.svelte +2 -1
  98. package/dist/components/AISuggestion/aiSuggestion.mcp.d.ts +1 -1
  99. package/dist/components/AISuggestion/aiSuggestion.mcp.js +8 -1
  100. package/dist/components/AISuggestion/aiSuggestion.props.d.ts +4 -1
  101. package/dist/components/AISuggestion/aiSuggestion.theme.js +1 -1
  102. package/dist/components/AISuggestion/aiSuggestions.props.d.ts +7 -0
  103. package/dist/components/AIThread/AIThread.svelte +378 -95
  104. package/dist/components/AIThread/AIThreadAskUserQuestion.svelte +1 -0
  105. package/dist/components/AIThread/AIThreadItems.svelte +266 -64
  106. package/dist/components/AIThread/AIThreadItems.svelte.d.ts +7 -3
  107. package/dist/components/AIThread/AIThreadMarker.svelte +8 -1
  108. package/dist/components/AIThread/AIThreadMarker.svelte.d.ts +1 -0
  109. package/dist/components/AIThread/aiThread.mcp.d.ts +1 -1
  110. package/dist/components/AIThread/aiThread.mcp.js +34 -20
  111. package/dist/components/AIThread/aiThread.props.d.ts +73 -8
  112. package/dist/components/AIThread/aiThread.theme.d.ts +78 -0
  113. package/dist/components/AIThread/aiThread.theme.js +108 -9
  114. package/dist/components/AIThread/index.d.ts +1 -1
  115. package/dist/components/AIThread/threadAskUserQuestion.d.ts +4 -1
  116. package/dist/components/AIThread/threadAskUserQuestion.js +8 -4
  117. package/dist/components/AIThread/threadRenderItems.d.ts +74 -3
  118. package/dist/components/AIThread/threadRenderItems.js +265 -77
  119. package/dist/components/AIThread/threadScrollController.d.ts +0 -8
  120. package/dist/components/AIThread/threadScrollController.js +2 -39
  121. package/dist/components/AIThread/threadTools.d.ts +11 -0
  122. package/dist/components/AIThread/threadTools.js +79 -0
  123. package/dist/components/AIThreadToc/AIThreadToc.svelte +188 -18
  124. package/dist/components/AIThreadToc/AIThreadTocPreview.svelte +25 -2
  125. package/dist/components/AIThreadToc/AIThreadTocPreview.svelte.d.ts +3 -0
  126. package/dist/components/AIThreadToc/aiThreadToc.d.ts +4 -2
  127. package/dist/components/AIThreadToc/aiThreadToc.js +17 -5
  128. package/dist/components/AIThreadToc/aiThreadToc.mcp.d.ts +1 -1
  129. package/dist/components/AIThreadToc/aiThreadToc.mcp.js +13 -3
  130. package/dist/components/AIThreadToc/aiThreadToc.props.d.ts +11 -0
  131. package/dist/components/AIThreadToc/aiThreadToc.theme.d.ts +3 -0
  132. package/dist/components/AIThreadToc/aiThreadToc.theme.js +15 -6
  133. package/dist/components/AITool/AITool.svelte +56 -21
  134. package/dist/components/AITool/AIToolCallList.svelte +79 -29
  135. package/dist/components/AITool/AIToolCallList.svelte.d.ts +6 -2
  136. package/dist/components/AITool/AIToolStatusMark.svelte +52 -0
  137. package/dist/components/AITool/AIToolStatusMark.svelte.d.ts +14 -0
  138. package/dist/components/AITool/AIToolValueSection.svelte +126 -28
  139. package/dist/components/AITool/AIToolValueSection.svelte.d.ts +6 -2
  140. package/dist/components/AITool/AIToolValueTree.svelte +11 -16
  141. package/dist/components/AITool/AIToolValueTree.svelte.d.ts +2 -3
  142. package/dist/components/AITool/aiTool.mcp.d.ts +1 -1
  143. package/dist/components/AITool/aiTool.mcp.js +36 -8
  144. package/dist/components/AITool/aiTool.props.d.ts +52 -6
  145. package/dist/components/AITool/aiTool.theme.d.ts +117 -39
  146. package/dist/components/AITool/aiTool.theme.js +144 -140
  147. package/dist/components/AITool/aiToolClock.svelte.d.ts +18 -0
  148. package/dist/components/AITool/aiToolClock.svelte.js +62 -0
  149. package/dist/components/AITool/aiToolPrimitiveThemes.d.ts +0 -2
  150. package/dist/components/AITool/aiToolPrimitiveThemes.js +0 -10
  151. package/dist/components/AITool/index.d.ts +2 -1
  152. package/dist/components/AITool/index.js +1 -0
  153. package/dist/components/AITool/toolRendering.d.ts +33 -1
  154. package/dist/components/AITool/toolRendering.js +179 -15
  155. package/dist/components/AITool/toolValueTree.d.ts +14 -1
  156. package/dist/components/AITool/toolValueTree.js +126 -27
  157. package/dist/components/Accordion/Accordion.svelte +109 -109
  158. package/dist/components/Accordion/Accordion.svelte.d.ts +0 -1
  159. package/dist/components/Accordion/AccordionPanel.svelte +64 -0
  160. package/dist/components/Accordion/AccordionPanel.svelte.d.ts +20 -0
  161. package/dist/components/Accordion/accordion.attributes.d.ts +24 -0
  162. package/dist/components/Accordion/accordion.attributes.js +20 -0
  163. package/dist/components/Accordion/accordion.mcp.d.ts +1 -1
  164. package/dist/components/Accordion/accordion.mcp.js +78 -22
  165. package/dist/components/Accordion/accordion.props.d.ts +54 -10
  166. package/dist/components/Accordion/accordion.theme.d.ts +3 -0
  167. package/dist/components/Accordion/accordion.theme.js +4 -0
  168. package/dist/components/Accordion/index.d.ts +1 -0
  169. package/dist/components/Accordion/index.js +1 -0
  170. package/dist/components/AudioPlayer/audioPlayerVolumeControl.slider.theme.d.ts +31 -1
  171. package/dist/components/Avatar/Avatar.svelte +60 -10
  172. package/dist/components/Avatar/AvatarGroup.svelte +9 -0
  173. package/dist/components/Avatar/avatar.mcp.d.ts +1 -1
  174. package/dist/components/Avatar/avatar.mcp.js +13 -5
  175. package/dist/components/Avatar/avatar.props.d.ts +28 -1
  176. package/dist/components/Avatar/avatar.theme.js +3 -3
  177. package/dist/components/Avatar/index.d.ts +1 -1
  178. package/dist/components/Breadcrumbs/breadcrumbs.mcp.d.ts +1 -1
  179. package/dist/components/Breadcrumbs/breadcrumbs.mcp.js +1 -1
  180. package/dist/components/Button/Button.svelte +35 -15
  181. package/dist/components/Button/button.mcp.d.ts +1 -1
  182. package/dist/components/Button/button.mcp.js +8 -4
  183. package/dist/components/Button/button.props.d.ts +23 -8
  184. package/dist/components/Button/button.theme.d.ts +12 -0
  185. package/dist/components/Button/button.theme.js +17 -4
  186. package/dist/components/ButtonGroup/buttonGroup.mcp.d.ts +1 -1
  187. package/dist/components/ButtonGroup/buttonGroup.mcp.js +1 -1
  188. package/dist/components/ButtonGroup/buttonGroup.props.d.ts +4 -1
  189. package/dist/components/Collapsible/Collapsible.svelte +125 -19
  190. package/dist/components/Collapsible/collapsible.attributes.d.ts +21 -0
  191. package/dist/components/Collapsible/collapsible.attributes.js +17 -0
  192. package/dist/components/Collapsible/collapsible.mcp.d.ts +1 -1
  193. package/dist/components/Collapsible/collapsible.mcp.js +62 -12
  194. package/dist/components/Collapsible/collapsible.props.d.ts +39 -8
  195. package/dist/components/Collapsible/collapsible.theme.js +3 -1
  196. package/dist/components/Collapsible/index.d.ts +1 -0
  197. package/dist/components/Collapsible/index.js +1 -0
  198. package/dist/components/Command/Command.svelte +56 -14
  199. package/dist/components/Command/command.mcp.d.ts +1 -1
  200. package/dist/components/Command/command.mcp.js +12 -6
  201. package/dist/components/Command/command.props.d.ts +39 -6
  202. package/dist/components/Command/command.state.svelte.d.ts +40 -11
  203. package/dist/components/Command/command.state.svelte.js +75 -28
  204. package/dist/components/Command/command.theme.js +4 -3
  205. package/dist/components/Confirmation/Confirmation.svelte +72 -31
  206. package/dist/components/Confirmation/confirmation.mcp.d.ts +1 -1
  207. package/dist/components/Confirmation/confirmation.mcp.js +5 -4
  208. package/dist/components/ContextMenu/ContextMenu.svelte +126 -16
  209. package/dist/components/ContextMenu/contextMenu.mcp.d.ts +1 -1
  210. package/dist/components/ContextMenu/contextMenu.mcp.js +10 -7
  211. package/dist/components/ContextMenu/contextMenu.props.d.ts +13 -4
  212. package/dist/components/ContextMenu/contextMenu.theme.d.ts +3 -3
  213. package/dist/components/ContextMenu/contextMenu.theme.js +3 -2
  214. package/dist/components/DataTable/DataTable.svelte +4 -9
  215. package/dist/components/DataTable/DataTableEditor.svelte +5 -0
  216. package/dist/components/DataTable/DataTableFilter.svelte +1 -0
  217. package/dist/components/DataTable/DataTableToolbar.svelte +1 -0
  218. package/dist/components/DataTable/dataTable.mcp.d.ts +1 -1
  219. package/dist/components/DataTable/dataTable.mcp.js +4 -2
  220. package/dist/components/DataTable/dataTable.theme.d.ts +0 -3
  221. package/dist/components/DataTable/dataTable.theme.js +9 -6
  222. package/dist/components/Dialog/Dialog.svelte +120 -35
  223. package/dist/components/Dialog/Dialog.svelte.d.ts +1 -1
  224. package/dist/components/Dialog/DialogBackdrop.svelte +21 -1
  225. package/dist/components/Dialog/dialog.api.d.ts +65 -0
  226. package/dist/components/Dialog/dialog.api.js +1 -0
  227. package/dist/components/Dialog/dialog.attributes.d.ts +23 -0
  228. package/dist/components/Dialog/dialog.attributes.js +19 -0
  229. package/dist/components/Dialog/dialog.indent.d.ts +6 -0
  230. package/dist/components/Dialog/dialog.indent.js +16 -0
  231. package/dist/components/Dialog/dialog.mcp.d.ts +1 -1
  232. package/dist/components/Dialog/dialog.mcp.js +195 -22
  233. package/dist/components/Dialog/dialog.props.d.ts +102 -19
  234. package/dist/components/Dialog/dialog.snap.d.ts +40 -0
  235. package/dist/components/Dialog/dialog.snap.js +78 -0
  236. package/dist/components/Dialog/dialog.state.svelte.d.ts +122 -10
  237. package/dist/components/Dialog/dialog.state.svelte.js +525 -66
  238. package/dist/components/Dialog/dialog.theme.d.ts +48 -0
  239. package/dist/components/Dialog/dialog.theme.js +32 -9
  240. package/dist/components/Dialog/index.d.ts +4 -1
  241. package/dist/components/Dialog/index.js +1 -0
  242. package/dist/components/DocumentViewer/DocumentSearchControl.svelte +5 -3
  243. package/dist/components/DocumentViewer/documentOutput.js +2 -1
  244. package/dist/components/FloatingWindow/FloatingWindow.svelte +20 -32
  245. package/dist/components/FloatingWindow/FloatingWindow.svelte.d.ts +1 -1
  246. package/dist/components/FloatingWindow/floatingWindow.mcp.d.ts +1 -1
  247. package/dist/components/FloatingWindow/floatingWindow.mcp.js +3 -3
  248. package/dist/components/FloatingWindow/floatingWindow.props.d.ts +9 -4
  249. package/dist/components/FloatingWindow/floatingWindow.state.svelte.d.ts +8 -2
  250. package/dist/components/FloatingWindow/floatingWindow.state.svelte.js +18 -7
  251. package/dist/components/Form/Ask/Ask.svelte +9 -13
  252. package/dist/components/Form/Ask/ask.mcp.d.ts +1 -1
  253. package/dist/components/Form/Ask/ask.mcp.js +1 -1
  254. package/dist/components/Form/Ask/ask.props.d.ts +1 -1
  255. package/dist/components/Form/Autocomplete/Autocomplete.svelte +418 -0
  256. package/dist/components/Form/Autocomplete/Autocomplete.svelte.d.ts +4 -0
  257. package/dist/components/Form/Autocomplete/autocomplete.items.d.ts +30 -0
  258. package/dist/components/Form/Autocomplete/autocomplete.items.js +64 -0
  259. package/dist/components/Form/Autocomplete/autocomplete.mcp.d.ts +1 -0
  260. package/dist/components/Form/Autocomplete/autocomplete.mcp.js +134 -0
  261. package/dist/components/Form/Autocomplete/autocomplete.props.d.ts +146 -0
  262. package/dist/components/Form/Autocomplete/autocomplete.props.js +1 -0
  263. package/dist/components/Form/Autocomplete/autocomplete.theme.d.ts +213 -0
  264. package/dist/components/Form/Autocomplete/autocomplete.theme.js +119 -0
  265. package/dist/components/Form/Autocomplete/index.d.ts +3 -0
  266. package/dist/components/Form/Autocomplete/index.js +2 -0
  267. package/dist/components/Form/Calendar/CalendarInput.svelte +9 -0
  268. package/dist/components/Form/Calendar/CalendarMonthYearPicker.svelte +3 -0
  269. package/dist/components/Form/Calendar/CalendarPrimitive.svelte +5 -0
  270. package/dist/components/Form/Calendar/calendar.mcp.d.ts +1 -1
  271. package/dist/components/Form/Calendar/calendar.mcp.js +2 -1
  272. package/dist/components/Form/Calendar/calendarInput.props.d.ts +2 -0
  273. package/dist/components/Form/Calendar/useCalendar.svelte.d.ts +3 -0
  274. package/dist/components/Form/Calendar/useCalendar.svelte.js +3 -0
  275. package/dist/components/Form/Checkbox/Checkbox.svelte +17 -2
  276. package/dist/components/Form/Checkbox/checkbox.mcp.d.ts +1 -1
  277. package/dist/components/Form/Checkbox/checkbox.mcp.js +11 -1
  278. package/dist/components/Form/Checkbox/checkbox.props.d.ts +12 -1
  279. package/dist/components/Form/CheckboxesInput/CheckboxLine.svelte +69 -32
  280. package/dist/components/Form/CheckboxesInput/CheckboxLine.svelte.d.ts +10 -2
  281. package/dist/components/Form/CheckboxesInput/CheckboxesInput.svelte +123 -74
  282. package/dist/components/Form/CheckboxesInput/CheckboxesInput.svelte.d.ts +12 -12
  283. package/dist/components/Form/CheckboxesInput/checkboxesInput.mcp.d.ts +1 -1
  284. package/dist/components/Form/CheckboxesInput/checkboxesInput.mcp.js +11 -7
  285. package/dist/components/Form/CheckboxesInput/checkboxesInput.props.d.ts +25 -9
  286. package/dist/components/Form/CheckboxesInput/checkboxesInput.theme.d.ts +12 -0
  287. package/dist/components/Form/CheckboxesInput/checkboxesInput.theme.js +9 -4
  288. package/dist/components/Form/CheckboxesInput/choiceEnter.d.ts +11 -0
  289. package/dist/components/Form/CheckboxesInput/choiceEnter.js +27 -0
  290. package/dist/components/Form/ColorInput/ColorInput.svelte +12 -3
  291. package/dist/components/Form/ColorInput/colorInput.mcp.d.ts +1 -1
  292. package/dist/components/Form/ColorInput/colorInput.mcp.js +1 -0
  293. package/dist/components/Form/ColorPicker/ColorPicker.svelte +11 -2
  294. package/dist/components/Form/ColorPicker/ColorPickerInput.svelte +9 -0
  295. package/dist/components/Form/ColorPicker/colorPicker.mcp.d.ts +1 -1
  296. package/dist/components/Form/ColorPicker/colorPicker.mcp.js +1 -0
  297. package/dist/components/Form/ColorPicker/colorPicker.props.d.ts +2 -0
  298. package/dist/components/Form/ColorPicker/colorPicker.state.svelte.d.ts +4 -0
  299. package/dist/components/Form/ColorPicker/colorPicker.state.svelte.js +12 -8
  300. package/dist/components/Form/Combobox/Combobox.svelte +145 -185
  301. package/dist/components/Form/Combobox/Combobox.svelte.d.ts +1 -1
  302. package/dist/components/Form/Combobox/ComboboxPopup.svelte +128 -0
  303. package/dist/components/Form/Combobox/ComboboxPopup.svelte.d.ts +28 -0
  304. package/dist/components/Form/Combobox/combobox.attributes.d.ts +34 -0
  305. package/dist/components/Form/Combobox/combobox.attributes.js +25 -0
  306. package/dist/components/Form/Combobox/combobox.items.d.ts +28 -0
  307. package/dist/components/Form/Combobox/combobox.items.js +68 -0
  308. package/dist/components/Form/Combobox/combobox.mcp.d.ts +1 -1
  309. package/dist/components/Form/Combobox/combobox.mcp.js +104 -13
  310. package/dist/components/Form/Combobox/combobox.props.d.ts +113 -19
  311. package/dist/components/Form/Combobox/combobox.state.svelte.d.ts +137 -0
  312. package/dist/components/Form/Combobox/combobox.state.svelte.js +375 -0
  313. package/dist/components/Form/Combobox/combobox.theme.d.ts +63 -0
  314. package/dist/components/Form/Combobox/combobox.theme.js +37 -1
  315. package/dist/components/Form/Combobox/index.d.ts +2 -1
  316. package/dist/components/Form/Combobox/index.js +1 -0
  317. package/dist/components/Form/DateInput/DateInput.svelte +11 -3
  318. package/dist/components/Form/DateInput/dateInput.mcp.d.ts +1 -1
  319. package/dist/components/Form/DateInput/dateInput.mcp.js +5 -0
  320. package/dist/components/Form/DateSelector/DateSelector.svelte +5 -2
  321. package/dist/components/Form/DateSelector/DateSelectorInput.svelte +9 -0
  322. package/dist/components/Form/DateSelector/dateSelector.mcp.d.ts +1 -1
  323. package/dist/components/Form/DateSelector/dateSelector.mcp.js +2 -2
  324. package/dist/components/Form/DateSelector/dateSelector.props.d.ts +2 -0
  325. package/dist/components/Form/Field/Field.svelte +256 -30
  326. package/dist/components/Form/Field/Field.svelte.d.ts +9 -0
  327. package/dist/components/Form/Field/FieldGroup.svelte +29 -0
  328. package/dist/components/Form/Field/FieldGroup.svelte.d.ts +11 -0
  329. package/dist/components/Form/Field/FieldHiddenInputs.svelte +187 -0
  330. package/dist/components/Form/Field/FieldHiddenInputs.svelte.d.ts +26 -0
  331. package/dist/components/Form/Field/field.d.ts +64 -8
  332. package/dist/components/Form/Field/field.mcp.d.ts +1 -1
  333. package/dist/components/Form/Field/field.mcp.js +158 -18
  334. package/dist/components/Form/Field/field.messages.d.ts +47 -0
  335. package/dist/components/Form/Field/field.messages.js +64 -0
  336. package/dist/components/Form/Field/field.state.svelte.d.ts +109 -3
  337. package/dist/components/Form/Field/field.state.svelte.js +508 -16
  338. package/dist/components/Form/Field/field.theme.d.ts +46 -0
  339. package/dist/components/Form/Field/field.theme.js +33 -0
  340. package/dist/components/Form/Field/fieldHiddenInputs.props.d.ts +61 -0
  341. package/dist/components/Form/Field/fieldHiddenInputs.props.js +1 -0
  342. package/dist/components/Form/Field/fieldNativeForm.svelte.d.ts +14 -0
  343. package/dist/components/Form/Field/fieldNativeForm.svelte.js +113 -0
  344. package/dist/components/Form/Field/index.d.ts +5 -2
  345. package/dist/components/Form/Field/index.js +1 -0
  346. package/dist/components/Form/Field/schemas.js +7 -2
  347. package/dist/components/Form/File/FileInput.svelte +24 -3
  348. package/dist/components/Form/File/fileInput.mcp.d.ts +1 -1
  349. package/dist/components/Form/File/fileInput.mcp.js +1 -0
  350. package/dist/components/Form/Form/Form.svelte +47 -14
  351. package/dist/components/Form/Form/FormActions.svelte +3 -1
  352. package/dist/components/Form/Form/FormActions.svelte.d.ts +42 -2
  353. package/dist/components/Form/Form/FormFieldRenderer.svelte +40 -2
  354. package/dist/components/Form/Form/FormInputRenderer.svelte +7 -0
  355. package/dist/components/Form/Form/form.d.ts +35 -6
  356. package/dist/components/Form/Form/form.mcp.d.ts +1 -1
  357. package/dist/components/Form/Form/form.mcp.js +113 -13
  358. package/dist/components/Form/Form/form.props.d.ts +32 -1
  359. package/dist/components/Form/Form/form.registry.d.ts +2 -2
  360. package/dist/components/Form/Form/form.registry.js +1 -4
  361. package/dist/components/Form/Form/form.state.svelte.d.ts +1138 -413
  362. package/dist/components/Form/Form/form.state.svelte.js +319 -26
  363. package/dist/components/Form/Form/index.d.ts +3 -1
  364. package/dist/components/Form/Form/visibility.d.ts +3096 -1831
  365. package/dist/components/Form/KeyValueInput/KeyValueInput.svelte +22 -10
  366. package/dist/components/Form/KeyValueInput/keyValueInput.mcp.d.ts +1 -1
  367. package/dist/components/Form/KeyValueInput/keyValueInput.mcp.js +1 -0
  368. package/dist/components/Form/MultiStepForm/MultiStepForm.svelte +12 -5
  369. package/dist/components/Form/MultiStepForm/multiStepForm.mcp.d.ts +1 -1
  370. package/dist/components/Form/MultiStepForm/multiStepForm.mcp.js +5 -3
  371. package/dist/components/Form/MultiStepForm/multiStepForm.props.d.ts +5 -0
  372. package/dist/components/Form/MultiStepForm/multiStepForm.state.svelte.d.ts +1022 -408
  373. package/dist/components/Form/MultiStepForm/multiStepForm.state.svelte.js +48 -24
  374. package/dist/components/Form/NumberInput/NumberInput.svelte +365 -46
  375. package/dist/components/Form/NumberInput/index.d.ts +1 -1
  376. package/dist/components/Form/NumberInput/numberInput.mcp.d.ts +1 -1
  377. package/dist/components/Form/NumberInput/numberInput.mcp.js +55 -30
  378. package/dist/components/Form/NumberInput/numberInput.props.d.ts +64 -4
  379. package/dist/components/Form/PasswordInput/Password.svelte +28 -1
  380. package/dist/components/Form/PasswordInput/index.d.ts +1 -1
  381. package/dist/components/Form/PasswordInput/passwordInput.mcp.d.ts +1 -1
  382. package/dist/components/Form/PasswordInput/passwordInput.mcp.js +20 -2
  383. package/dist/components/Form/PasswordInput/passwordInput.props.d.ts +23 -0
  384. package/dist/components/Form/PhoneInput/PhoneInput.svelte +11 -4
  385. package/dist/components/Form/PhoneInput/PhoneInputCountryPicker.svelte +47 -21
  386. package/dist/components/Form/PhoneInput/phoneInput-cdn.js +2 -1
  387. package/dist/components/Form/PhoneInput/phoneInput.mcp.d.ts +1 -1
  388. package/dist/components/Form/PhoneInput/phoneInput.mcp.js +6 -2
  389. package/dist/components/Form/PhoneInput/phoneInputCountry.d.ts +9 -3
  390. package/dist/components/Form/PhoneInput/phoneInputCountry.js +34 -24
  391. package/dist/components/Form/PinInput/PinInput.svelte +44 -9
  392. package/dist/components/Form/PinInput/PinInputCells.svelte +22 -1
  393. package/dist/components/Form/PinInput/PinInputCells.svelte.d.ts +1 -0
  394. package/dist/components/Form/PinInput/index.d.ts +1 -1
  395. package/dist/components/Form/PinInput/pinInput.mcp.d.ts +1 -1
  396. package/dist/components/Form/PinInput/pinInput.mcp.js +29 -6
  397. package/dist/components/Form/PinInput/pinInput.props.d.ts +38 -4
  398. package/dist/components/Form/PinInput/pinInput.state.svelte.d.ts +41 -0
  399. package/dist/components/Form/PinInput/pinInput.state.svelte.js +227 -24
  400. package/dist/components/Form/PinInput/pinInput.theme.d.ts +39 -3
  401. package/dist/components/Form/PinInput/pinInput.theme.js +27 -1
  402. package/dist/components/Form/RadioInput/RadioInput.svelte +94 -32
  403. package/dist/components/Form/RadioInput/RadioInput.svelte.d.ts +12 -12
  404. package/dist/components/Form/RadioInput/radioInput.mcp.d.ts +1 -1
  405. package/dist/components/Form/RadioInput/radioInput.mcp.js +12 -9
  406. package/dist/components/Form/RadioInput/radioInput.props.d.ts +22 -6
  407. package/dist/components/Form/RadioInput/radioInput.theme.d.ts +12 -0
  408. package/dist/components/Form/RadioInput/radioInput.theme.js +10 -5
  409. package/dist/components/Form/RatingInput/RatingInput.svelte +13 -4
  410. package/dist/components/Form/RatingInput/ratingInput.mcp.d.ts +1 -1
  411. package/dist/components/Form/RatingInput/ratingInput.mcp.js +3 -3
  412. package/dist/components/Form/RatingInput/ratingInput.props.d.ts +1 -1
  413. package/dist/components/Form/Select/Select.svelte +186 -48
  414. package/dist/components/Form/Select/Select.svelte.d.ts +23 -2
  415. package/dist/components/Form/Select/SelectOptionRow.svelte +69 -0
  416. package/dist/components/Form/Select/SelectOptionRow.svelte.d.ts +18 -0
  417. package/dist/components/Form/Select/index.d.ts +2 -1
  418. package/dist/components/Form/Select/index.js +1 -0
  419. package/dist/components/Form/Select/select.align.d.ts +5 -0
  420. package/dist/components/Form/Select/select.align.js +19 -5
  421. package/dist/components/Form/Select/select.attributes.d.ts +36 -0
  422. package/dist/components/Form/Select/select.attributes.js +27 -0
  423. package/dist/components/Form/Select/select.mcp.d.ts +1 -1
  424. package/dist/components/Form/Select/select.mcp.js +103 -18
  425. package/dist/components/Form/Select/select.props.d.ts +87 -10
  426. package/dist/components/Form/Select/select.state.svelte.d.ts +108 -17
  427. package/dist/components/Form/Select/select.state.svelte.js +354 -59
  428. package/dist/components/Form/Select/select.theme.d.ts +21 -0
  429. package/dist/components/Form/Select/select.theme.js +22 -0
  430. package/dist/components/Form/Slider/Slider.svelte +54 -14
  431. package/dist/components/Form/Slider/SliderMarks.svelte +1 -1
  432. package/dist/components/Form/Slider/SliderThumb.svelte +49 -19
  433. package/dist/components/Form/Slider/SliderThumb.svelte.d.ts +8 -2
  434. package/dist/components/Form/Slider/SliderTrack.svelte +33 -12
  435. package/dist/components/Form/Slider/SliderTrack.svelte.d.ts +6 -2
  436. package/dist/components/Form/Slider/index.d.ts +1 -1
  437. package/dist/components/Form/Slider/slider.mcp.d.ts +1 -1
  438. package/dist/components/Form/Slider/slider.mcp.js +55 -11
  439. package/dist/components/Form/Slider/slider.props.d.ts +35 -2
  440. package/dist/components/Form/Slider/slider.state.svelte.d.ts +66 -5
  441. package/dist/components/Form/Slider/slider.state.svelte.js +273 -49
  442. package/dist/components/Form/Slider/slider.theme.d.ts +36 -0
  443. package/dist/components/Form/Slider/slider.theme.js +35 -17
  444. package/dist/components/Form/Switch/Switch.svelte +61 -38
  445. package/dist/components/Form/Switch/switch.mcp.d.ts +1 -1
  446. package/dist/components/Form/Switch/switch.mcp.js +25 -5
  447. package/dist/components/Form/Switch/switch.props.d.ts +14 -1
  448. package/dist/components/Form/Switch/switch.theme.d.ts +12 -0
  449. package/dist/components/Form/Switch/switch.theme.js +8 -3
  450. package/dist/components/Form/TagGroup/TagGroup.svelte +8 -0
  451. package/dist/components/Form/TagGroup/tagGroup.mcp.d.ts +1 -1
  452. package/dist/components/Form/TagGroup/tagGroup.mcp.js +1 -0
  453. package/dist/components/Form/TagsInput/TagsInput.svelte +277 -275
  454. package/dist/components/Form/TagsInput/TagsInput.svelte.d.ts +1 -1
  455. package/dist/components/Form/TagsInput/tagsInput.mcp.d.ts +1 -1
  456. package/dist/components/Form/TagsInput/tagsInput.mcp.js +31 -11
  457. package/dist/components/Form/TagsInput/tagsInput.props.d.ts +6 -26
  458. package/dist/components/Form/TagsInput/tagsInput.theme.d.ts +63 -0
  459. package/dist/components/Form/TagsInput/tagsInput.theme.js +37 -1
  460. package/dist/components/Form/TextArea/TextArea.svelte +8 -0
  461. package/dist/components/Form/TextArea/textArea.mcp.d.ts +1 -1
  462. package/dist/components/Form/TextArea/textArea.mcp.js +1 -0
  463. package/dist/components/Form/TextInput/TextInput.svelte +8 -1
  464. package/dist/components/Form/TextInput/textInput.mcp.d.ts +1 -1
  465. package/dist/components/Form/TextInput/textInput.mcp.js +5 -0
  466. package/dist/components/Form/TimeInput/TimeInput.svelte +9 -1
  467. package/dist/components/Form/TimeInput/timeInput.mcp.d.ts +1 -1
  468. package/dist/components/Form/TimeInput/timeInput.mcp.js +31 -0
  469. package/dist/components/Form/VoiceInput/VoiceInput.svelte +10 -2
  470. package/dist/components/Form/VoiceInput/voiceInput.mcp.d.ts +1 -1
  471. package/dist/components/Form/VoiceInput/voiceInput.mcp.js +1 -0
  472. package/dist/components/GanttChart/GanttDependencyControl.svelte +4 -4
  473. package/dist/components/HoverCard/HoverCard.svelte +100 -10
  474. package/dist/components/HoverCard/hoverCard.attributes.d.ts +33 -0
  475. package/dist/components/HoverCard/hoverCard.attributes.js +24 -0
  476. package/dist/components/HoverCard/hoverCard.mcp.d.ts +1 -1
  477. package/dist/components/HoverCard/hoverCard.mcp.js +61 -2
  478. package/dist/components/HoverCard/hoverCard.props.d.ts +19 -0
  479. package/dist/components/HoverCard/hoverCard.theme.d.ts +12 -0
  480. package/dist/components/HoverCard/hoverCard.theme.js +9 -2
  481. package/dist/components/HoverCard/index.d.ts +1 -0
  482. package/dist/components/HoverCard/index.js +1 -0
  483. package/dist/components/ImageGallery/imageGallery.state.svelte.d.ts +1 -1
  484. package/dist/components/ImageZoom/imageZoom.lightbox.js +40 -6
  485. package/dist/components/ImageZoom/imageZoom.mcp.d.ts +1 -1
  486. package/dist/components/ImageZoom/imageZoom.mcp.js +3 -3
  487. package/dist/components/ImageZoom/imageZoom.props.d.ts +10 -4
  488. package/dist/components/ImageZoom/imageZoom.state.svelte.d.ts +16 -4
  489. package/dist/components/ImageZoom/imageZoom.state.svelte.js +38 -9
  490. package/dist/components/Kanban/kanban.theme.js +7 -3
  491. package/dist/components/Layout/layoutSpacing.d.ts +2 -2
  492. package/dist/components/LinkPreview/LinkPreview.svelte +7 -1
  493. package/dist/components/LinkPreview/linkPreview.mcp.d.ts +1 -1
  494. package/dist/components/LinkPreview/linkPreview.mcp.js +4 -1
  495. package/dist/components/LinkPreview/linkPreview.props.d.ts +15 -0
  496. package/dist/components/LinkPreview/linkPreview.theme.d.ts +12 -0
  497. package/dist/components/LinkPreview/linkPreview.theme.js +9 -2
  498. package/dist/components/Map/maplibre-cdn.js +3 -2
  499. package/dist/components/Markdown/markdown.mcp.d.ts +1 -1
  500. package/dist/components/Markdown/markdown.mcp.js +2 -1
  501. package/dist/components/Markdown/markdown.theme.js +18 -9
  502. package/dist/components/MediaVolume/MediaVolumeControl.svelte +4 -3
  503. package/dist/components/Menu/Menu.svelte +3 -3
  504. package/dist/components/Menu/Menu.svelte.d.ts +1 -1
  505. package/dist/components/Menu/MenuCheckboxItem.svelte +87 -0
  506. package/dist/components/Menu/MenuCheckboxItem.svelte.d.ts +16 -0
  507. package/dist/components/Menu/MenuFloating.svelte +421 -74
  508. package/dist/components/Menu/MenuFloating.svelte.d.ts +1 -1
  509. package/dist/components/Menu/MenuMirroredIcon.svelte +9 -0
  510. package/dist/components/Menu/MenuMirroredIcon.svelte.d.ts +7 -0
  511. package/dist/components/Menu/MenuRadioGroup.svelte +102 -0
  512. package/dist/components/Menu/MenuRadioGroup.svelte.d.ts +18 -0
  513. package/dist/components/Menu/MenuSearchField.svelte +54 -0
  514. package/dist/components/Menu/MenuSearchField.svelte.d.ts +20 -0
  515. package/dist/components/Menu/MenuStacked.svelte +404 -158
  516. package/dist/components/Menu/MenuStacked.svelte.d.ts +1 -1
  517. package/dist/components/Menu/MenuStackedBackHeader.svelte +6 -1
  518. package/dist/components/Menu/index.d.ts +2 -1
  519. package/dist/components/Menu/index.js +1 -0
  520. package/dist/components/Menu/menu.attributes.d.ts +37 -0
  521. package/dist/components/Menu/menu.attributes.js +28 -0
  522. package/dist/components/Menu/menu.filter.svelte.d.ts +52 -0
  523. package/dist/components/Menu/menu.filter.svelte.js +143 -0
  524. package/dist/components/Menu/menu.mcp.d.ts +1 -1
  525. package/dist/components/Menu/menu.mcp.js +227 -17
  526. package/dist/components/Menu/menu.platform.d.ts +5 -0
  527. package/dist/components/Menu/menu.platform.js +11 -0
  528. package/dist/components/Menu/menu.props.d.ts +172 -9
  529. package/dist/components/Menu/menu.theme.d.ts +147 -0
  530. package/dist/components/Menu/menu.theme.js +101 -0
  531. package/dist/components/Menu/menuTree.d.ts +35 -1
  532. package/dist/components/Menu/menuTree.js +158 -1
  533. package/dist/components/MenuBar/menuBar.mcp.d.ts +1 -1
  534. package/dist/components/MenuBar/menuBar.mcp.js +4 -2
  535. package/dist/components/MenuBar/menuBar.state.svelte.js +28 -10
  536. package/dist/components/MenuOption/MenuOption.svelte +5 -1
  537. package/dist/components/MenuOption/menuOption.mcp.d.ts +1 -1
  538. package/dist/components/MenuOption/menuOption.mcp.js +8 -0
  539. package/dist/components/MenuOption/menuOption.props.d.ts +12 -0
  540. package/dist/components/MenuOption/menuOption.theme.d.ts +18 -0
  541. package/dist/components/MenuOption/menuOption.theme.js +24 -4
  542. package/dist/components/Mermaid/mermaid.mcp.d.ts +1 -1
  543. package/dist/components/Mermaid/mermaid.mcp.js +8 -8
  544. package/dist/components/Mermaid/mermaid.props.d.ts +3 -4
  545. package/dist/components/Mermaid/mermaid.state.svelte.d.ts +20 -19
  546. package/dist/components/Mermaid/mermaid.state.svelte.js +80 -243
  547. package/dist/components/Mermaid/mermaid.theme.js +26 -1
  548. package/dist/components/MetadataList/MetadataList.svelte.d.ts +1 -1
  549. package/dist/components/Meter/Meter.svelte +110 -24
  550. package/dist/components/Meter/Meter.svelte.d.ts +12 -12
  551. package/dist/components/Meter/meter.mcp.d.ts +1 -1
  552. package/dist/components/Meter/meter.mcp.js +23 -37
  553. package/dist/components/Meter/meter.props.d.ts +36 -44
  554. package/dist/components/NavigationMenu/NavigationMenu.svelte +181 -0
  555. package/dist/components/NavigationMenu/NavigationMenu.svelte.d.ts +25 -0
  556. package/dist/components/NavigationMenu/NavigationMenuContent.svelte +141 -0
  557. package/dist/components/NavigationMenu/NavigationMenuContent.svelte.d.ts +13 -0
  558. package/dist/components/NavigationMenu/NavigationMenuTrigger.svelte +75 -0
  559. package/dist/components/NavigationMenu/NavigationMenuTrigger.svelte.d.ts +13 -0
  560. package/dist/components/NavigationMenu/index.d.ts +4 -0
  561. package/dist/components/NavigationMenu/index.js +3 -0
  562. package/dist/components/NavigationMenu/navigationMenu.attributes.d.ts +24 -0
  563. package/dist/components/NavigationMenu/navigationMenu.attributes.js +21 -0
  564. package/dist/components/NavigationMenu/navigationMenu.mcp.d.ts +1 -0
  565. package/dist/components/NavigationMenu/navigationMenu.mcp.js +138 -0
  566. package/dist/components/NavigationMenu/navigationMenu.props.d.ts +129 -0
  567. package/dist/components/NavigationMenu/navigationMenu.props.js +1 -0
  568. package/dist/components/NavigationMenu/navigationMenu.state.svelte.d.ts +163 -0
  569. package/dist/components/NavigationMenu/navigationMenu.state.svelte.js +721 -0
  570. package/dist/components/NavigationMenu/navigationMenu.theme.d.ts +326 -0
  571. package/dist/components/NavigationMenu/navigationMenu.theme.js +239 -0
  572. package/dist/components/Overlay/Overlay.svelte +19 -30
  573. package/dist/components/Overlay/index.d.ts +1 -0
  574. package/dist/components/Overlay/index.js +1 -0
  575. package/dist/components/Overlay/overlay.attributes.d.ts +16 -0
  576. package/dist/components/Overlay/overlay.attributes.js +14 -0
  577. package/dist/components/Overlay/overlay.mcp.d.ts +1 -1
  578. package/dist/components/Overlay/overlay.mcp.js +21 -3
  579. package/dist/components/Overlay/overlay.props.d.ts +8 -4
  580. package/dist/components/Popover/Popover.svelte +163 -52
  581. package/dist/components/Popover/Popover.svelte.d.ts +23 -2
  582. package/dist/components/Popover/PopoverSession.svelte +12 -0
  583. package/dist/components/Popover/PopoverSession.svelte.d.ts +7 -0
  584. package/dist/components/Popover/index.d.ts +10 -2
  585. package/dist/components/Popover/index.js +4 -1
  586. package/dist/components/Popover/popover.api.d.ts +83 -0
  587. package/dist/components/Popover/popover.api.js +1 -0
  588. package/dist/components/Popover/popover.attributes.d.ts +32 -0
  589. package/dist/components/Popover/popover.attributes.js +28 -0
  590. package/dist/components/Popover/popover.claims.d.ts +19 -0
  591. package/dist/components/Popover/popover.claims.js +45 -0
  592. package/dist/components/Popover/popover.mcp.d.ts +1 -1
  593. package/dist/components/Popover/popover.mcp.js +163 -31
  594. package/dist/components/Popover/popover.position.d.ts +226 -0
  595. package/dist/components/Popover/popover.position.js +402 -0
  596. package/dist/components/Popover/popover.props.d.ts +179 -24
  597. package/dist/components/Popover/popover.state.svelte.d.ts +169 -37
  598. package/dist/components/Popover/popover.state.svelte.js +1034 -194
  599. package/dist/components/Popover/popover.theme.d.ts +15 -0
  600. package/dist/components/Popover/popover.theme.js +27 -2
  601. package/dist/components/PopupMenu/PopupMenu.svelte +193 -22
  602. package/dist/components/PopupMenu/PopupMenu.svelte.d.ts +2 -2
  603. package/dist/components/PopupMenu/popupMenu.context.d.ts +42 -0
  604. package/dist/components/PopupMenu/popupMenu.context.js +52 -0
  605. package/dist/components/PopupMenu/popupMenu.mcp.d.ts +1 -1
  606. package/dist/components/PopupMenu/popupMenu.mcp.js +46 -6
  607. package/dist/components/PopupMenu/popupMenu.props.d.ts +29 -2
  608. package/dist/components/Progress/Progress.svelte +160 -0
  609. package/dist/components/Progress/Progress.svelte.d.ts +4 -0
  610. package/dist/components/Progress/index.d.ts +3 -0
  611. package/dist/components/Progress/index.js +2 -0
  612. package/dist/components/Progress/progress.mcp.d.ts +1 -0
  613. package/dist/components/Progress/progress.mcp.js +101 -0
  614. package/dist/components/Progress/progress.props.d.ts +79 -0
  615. package/dist/components/Progress/progress.props.js +1 -0
  616. package/dist/components/Progress/progress.theme.d.ts +129 -0
  617. package/dist/components/Progress/progress.theme.js +83 -0
  618. package/dist/components/ProgressCircle/ProgressCircle.svelte +51 -6
  619. package/dist/components/ProgressCircle/progressCircle.mcp.d.ts +1 -1
  620. package/dist/components/ProgressCircle/progressCircle.mcp.js +18 -4
  621. package/dist/components/ProgressCircle/progressCircle.props.d.ts +32 -2
  622. package/dist/components/ProgressCircle/progressCircle.theme.d.ts +15 -3
  623. package/dist/components/ProgressCircle/progressCircle.theme.js +7 -2
  624. package/dist/components/RichTextInput/RichTextInput.svelte +19 -1
  625. package/dist/components/RichTextInput/RichTextInputChrome.svelte +5 -1
  626. package/dist/components/RichTextInput/RichTextInputChrome.svelte.d.ts +2 -0
  627. package/dist/components/RichTextInput/RichTextInputViewport.svelte +3 -1
  628. package/dist/components/RichTextInput/RichTextInputViewport.svelte.d.ts +1 -0
  629. package/dist/components/RichTextInput/richTextInput.mcp.d.ts +1 -1
  630. package/dist/components/RichTextInput/richTextInput.mcp.js +1 -0
  631. package/dist/components/RichTextInput/suggestions.js +2 -0
  632. package/dist/components/ScrollArea/ScrollArea.svelte +166 -27
  633. package/dist/components/ScrollArea/index.d.ts +2 -1
  634. package/dist/components/ScrollArea/index.js +1 -0
  635. package/dist/components/ScrollArea/scrollArea.attributes.d.ts +25 -0
  636. package/dist/components/ScrollArea/scrollArea.attributes.js +21 -0
  637. package/dist/components/ScrollArea/scrollArea.mcp.d.ts +1 -1
  638. package/dist/components/ScrollArea/scrollArea.mcp.js +47 -3
  639. package/dist/components/ScrollArea/scrollArea.props.d.ts +33 -6
  640. package/dist/components/ScrollArea/scrollArea.svelte.d.ts +56 -12
  641. package/dist/components/ScrollArea/scrollArea.svelte.js +281 -71
  642. package/dist/components/ScrollArea/scrollArea.theme.js +5 -2
  643. package/dist/components/SegmentedControl/SegmentedControl.svelte +4 -3
  644. package/dist/components/SegmentedControl/segmentedControl.mcp.d.ts +1 -1
  645. package/dist/components/SegmentedControl/segmentedControl.mcp.js +3 -2
  646. package/dist/components/SelectionMenu/SelectionMenu.svelte +4 -2
  647. package/dist/components/Sidebar/SidebarAction.svelte +13 -3
  648. package/dist/components/Sidebar/SidebarAction.svelte.d.ts +2 -1
  649. package/dist/components/Sidebar/SidebarActivityBar.svelte +14 -7
  650. package/dist/components/Sidebar/SidebarFlyout.svelte +97 -0
  651. package/dist/components/Sidebar/SidebarFlyout.svelte.d.ts +32 -0
  652. package/dist/components/Sidebar/SidebarGroup.svelte +39 -15
  653. package/dist/components/Sidebar/SidebarMenuButton.svelte +6 -3
  654. package/dist/components/Sidebar/SidebarMenuItem.svelte +134 -31
  655. package/dist/components/Sidebar/SidebarMenuSubItem.svelte +30 -14
  656. package/dist/components/Sidebar/SidebarTreeNode.svelte +41 -61
  657. package/dist/components/Sidebar/index.d.ts +1 -0
  658. package/dist/components/Sidebar/index.js +1 -0
  659. package/dist/components/Sidebar/sidebar-position.d.ts +37 -2
  660. package/dist/components/Sidebar/sidebar-position.js +31 -2
  661. package/dist/components/Sidebar/sidebar.attributes.d.ts +33 -0
  662. package/dist/components/Sidebar/sidebar.attributes.js +29 -0
  663. package/dist/components/Sidebar/sidebar.mcp.d.ts +1 -1
  664. package/dist/components/Sidebar/sidebar.mcp.js +45 -10
  665. package/dist/components/Sidebar/sidebar.props.d.ts +28 -7
  666. package/dist/components/Sidebar/sidebar.theme.d.ts +51 -21
  667. package/dist/components/Sidebar/sidebar.theme.js +113 -62
  668. package/dist/components/Sidebar/sidebar.views.svelte.js +11 -18
  669. package/dist/components/Stepper/Stepper.svelte +2 -0
  670. package/dist/components/Stepper/stepper.mcp.d.ts +1 -1
  671. package/dist/components/Stepper/stepper.mcp.js +1 -0
  672. package/dist/components/Stepper/stepper.props.d.ts +5 -0
  673. package/dist/components/Stepper/stepper.state.svelte.d.ts +2 -0
  674. package/dist/components/Stepper/stepper.state.svelte.js +31 -12
  675. package/dist/components/Tabbar/Tabbar.svelte +55 -16
  676. package/dist/components/Tabbar/index.d.ts +1 -1
  677. package/dist/components/Tabbar/tabbar.mcp.d.ts +1 -1
  678. package/dist/components/Tabbar/tabbar.mcp.js +26 -9
  679. package/dist/components/Tabbar/tabbar.props.d.ts +34 -5
  680. package/dist/components/Tabbar/tabbar.selection.svelte.d.ts +79 -0
  681. package/dist/components/Tabbar/tabbar.selection.svelte.js +99 -0
  682. package/dist/components/TableOfContents/tableOfContents.state.svelte.js +9 -7
  683. package/dist/components/Tabs/Tabs.svelte +73 -16
  684. package/dist/components/Tabs/index.d.ts +2 -1
  685. package/dist/components/Tabs/tabs.direction.svelte.d.ts +25 -0
  686. package/dist/components/Tabs/tabs.direction.svelte.js +40 -0
  687. package/dist/components/Tabs/tabs.mcp.d.ts +1 -1
  688. package/dist/components/Tabs/tabs.mcp.js +22 -4
  689. package/dist/components/Tabs/tabs.props.d.ts +39 -12
  690. package/dist/components/Tabs/tabs.theme.js +3 -1
  691. package/dist/components/Theme/Theme.svelte +44 -27
  692. package/dist/components/Theme/helper.d.ts +16 -2
  693. package/dist/components/Theme/helper.js +46 -4
  694. package/dist/components/Theme/theme.mcp.d.ts +1 -1
  695. package/dist/components/Theme/theme.mcp.js +103 -0
  696. package/dist/components/Theme/theme.props.d.ts +16 -0
  697. package/dist/components/Theme/theme.state.svelte.d.ts +14 -1
  698. package/dist/components/Theme/theme.state.svelte.js +18 -1
  699. package/dist/components/Toast/Toast.svelte +184 -39
  700. package/dist/components/Toast/Toaster.svelte +14 -10
  701. package/dist/components/Toast/index.d.ts +1 -0
  702. package/dist/components/Toast/toast.mcp.d.ts +1 -1
  703. package/dist/components/Toast/toast.mcp.js +47 -6
  704. package/dist/components/Toast/toast.state.svelte.d.ts +172 -6
  705. package/dist/components/Toast/toast.state.svelte.js +513 -68
  706. package/dist/components/Toast/toast.theme.js +1 -1
  707. package/dist/components/ToggleButton/ToggleButton.svelte +23 -1
  708. package/dist/components/ToggleButton/toggleButton.mcp.d.ts +1 -1
  709. package/dist/components/ToggleButton/toggleButton.mcp.js +3 -1
  710. package/dist/components/ToggleButton/toggleButton.props.d.ts +13 -1
  711. package/dist/components/ToggleButton/toggleButton.theme.d.ts +12 -0
  712. package/dist/components/ToggleButton/toggleButton.theme.js +15 -3
  713. package/dist/components/ToggleButtonGroup/ToggleButtonGroup.svelte +29 -9
  714. package/dist/components/ToggleButtonGroup/index.d.ts +1 -1
  715. package/dist/components/ToggleButtonGroup/toggleButtonGroup.mcp.d.ts +1 -1
  716. package/dist/components/ToggleButtonGroup/toggleButtonGroup.mcp.js +5 -2
  717. package/dist/components/ToggleButtonGroup/toggleButtonGroup.props.d.ts +19 -1
  718. package/dist/components/ToggleButtonGroup/toggleButtonGroup.theme.d.ts +12 -0
  719. package/dist/components/ToggleButtonGroup/toggleButtonGroup.theme.js +21 -2
  720. package/dist/components/ToggleMenu/ToggleMenu.svelte +57 -43
  721. package/dist/components/ToggleMenu/ToggleMenuGroup.svelte +1 -0
  722. package/dist/components/ToggleMenu/ToggleMenuMenu.svelte +9 -3
  723. package/dist/components/ToggleMenu/ToggleMenuRadioGroup.svelte +7 -2
  724. package/dist/components/ToggleMenu/toggleMenu.mcp.d.ts +1 -1
  725. package/dist/components/ToggleMenu/toggleMenu.mcp.js +3 -2
  726. package/dist/components/ToggleMenu/toggleMenu.props.d.ts +4 -1
  727. package/dist/components/Tooltip/Tooltip.svelte +4 -12
  728. package/dist/components/Tooltip/TooltipHost.svelte +136 -15
  729. package/dist/components/Tooltip/index.d.ts +1 -0
  730. package/dist/components/Tooltip/index.js +1 -0
  731. package/dist/components/Tooltip/tooltip.attachment.svelte.d.ts +5 -0
  732. package/dist/components/Tooltip/tooltip.attachment.svelte.js +215 -33
  733. package/dist/components/Tooltip/tooltip.attributes.d.ts +32 -0
  734. package/dist/components/Tooltip/tooltip.attributes.js +28 -0
  735. package/dist/components/Tooltip/tooltip.mcp.d.ts +1 -1
  736. package/dist/components/Tooltip/tooltip.mcp.js +111 -10
  737. package/dist/components/Tooltip/tooltip.props.d.ts +33 -2
  738. package/dist/components/Tooltip/tooltip.surface.d.ts +24 -0
  739. package/dist/components/Tooltip/tooltip.surface.js +42 -0
  740. package/dist/components/Tree/TreeContextMenuSurface.svelte +16 -3
  741. package/dist/components/Utils/BeforeHydratation.svelte +14 -3
  742. package/dist/components/Utils/BeforeHydratation.svelte.d.ts +2 -0
  743. package/dist/components/VideoPlayer/VideoPlayer.svelte.d.ts +1 -1
  744. package/dist/components/VideoPlayer/VideoPlayerSettings.svelte +2 -0
  745. package/dist/generated/componentAliases.d.ts +3 -0
  746. package/dist/generated/componentAliases.js +3 -0
  747. package/dist/generated/componentContract.d.ts +79 -34
  748. package/dist/generated/componentContract.js +225 -6
  749. package/dist/generated/componentMcpRegistry.js +6 -0
  750. package/dist/i18n/ar.js +107 -3
  751. package/dist/i18n/context.svelte.d.ts +6 -0
  752. package/dist/i18n/context.svelte.js +12 -0
  753. package/dist/i18n/de.js +101 -3
  754. package/dist/i18n/en.d.ts +91 -2
  755. package/dist/i18n/en.js +101 -3
  756. package/dist/i18n/es.js +101 -3
  757. package/dist/i18n/fr.js +101 -3
  758. package/dist/i18n/ja.js +101 -3
  759. package/dist/i18n/pt.js +101 -3
  760. package/dist/i18n/zh.js +101 -3
  761. package/dist/tailwind/geometry.js +7 -0
  762. package/dist/tailwind/global.js +31 -0
  763. package/dist/types/index.d.ts +1 -0
  764. package/dist/types/types.mcp.d.ts +1 -1
  765. package/dist/types/types.mcp.js +23 -0
  766. package/dist/utils/cspNonce.d.ts +16 -0
  767. package/dist/utils/cspNonce.js +39 -0
  768. package/dist/utils/cva/merge.d.ts +5 -1
  769. package/dist/utils/cva/merge.js +6 -4
  770. package/dist/utils/focus.d.ts +34 -0
  771. package/dist/utils/focus.js +93 -0
  772. package/dist/utils/focusHistory.d.ts +21 -0
  773. package/dist/utils/focusHistory.js +99 -0
  774. package/dist/utils/handlers.d.ts +7 -0
  775. package/dist/utils/handlers.js +14 -0
  776. package/dist/utils/hoverIntent.d.ts +42 -0
  777. package/dist/utils/hoverIntent.js +57 -0
  778. package/dist/utils/id.d.ts +7 -0
  779. package/dist/utils/id.js +15 -0
  780. package/dist/utils/layers.svelte.d.ts +32 -4
  781. package/dist/utils/layers.svelte.js +214 -21
  782. package/dist/utils/listFilter.d.ts +44 -0
  783. package/dist/utils/listFilter.js +130 -0
  784. package/dist/utils/match.d.ts +35 -0
  785. package/dist/utils/match.js +36 -0
  786. package/dist/utils/number.d.ts +126 -0
  787. package/dist/utils/number.js +401 -0
  788. package/dist/utils/openChange.d.ts +88 -0
  789. package/dist/utils/openChange.js +71 -0
  790. package/dist/utils/openLifecycle.svelte.d.ts +41 -0
  791. package/dist/utils/openLifecycle.svelte.js +134 -0
  792. package/dist/utils/pointerDrag.d.ts +10 -0
  793. package/dist/utils/pointerDrag.js +37 -2
  794. package/dist/utils/pragmaticDragAndDrop.d.ts +2 -1
  795. package/dist/utils/pragmaticDragAndDrop.js +8 -3
  796. package/dist/utils/range.d.ts +62 -0
  797. package/dist/utils/range.js +70 -0
  798. package/dist/utils/requestNativeSubmit.d.ts +17 -0
  799. package/dist/utils/requestNativeSubmit.js +47 -0
  800. package/dist/utils/safeArea.svelte.d.ts +10 -1
  801. package/dist/utils/safeArea.svelte.js +19 -11
  802. package/dist/utils/stateAttributes.d.ts +108 -0
  803. package/dist/utils/stateAttributes.js +78 -0
  804. package/dist/utils/swipeVelocity.d.ts +32 -0
  805. package/dist/utils/swipeVelocity.js +59 -0
  806. package/dist/utils/timer.svelte.d.ts +65 -2
  807. package/dist/utils/timer.svelte.js +159 -25
  808. package/dist/utils/trigger.d.ts +41 -0
  809. package/dist/utils/trigger.js +103 -0
  810. package/dist/utils/typeahead.d.ts +9 -0
  811. package/dist/utils/typeahead.js +21 -9
  812. package/dist/utils/useDndList.svelte.d.ts +1 -1
  813. package/dist/utils/useDndList.svelte.js +6 -23
  814. package/dist/utils/useFocusScope.svelte.d.ts +29 -0
  815. package/dist/utils/useFocusScope.svelte.js +189 -27
  816. package/dist/utils/useHoverAction.svelte.d.ts +44 -4
  817. package/dist/utils/useHoverAction.svelte.js +161 -51
  818. package/dist/utils/useKeyDown.svelte.d.ts +19 -2
  819. package/dist/utils/useKeyDown.svelte.js +19 -12
  820. package/dist/utils/useListNavigation.svelte.d.ts +94 -13
  821. package/dist/utils/useListNavigation.svelte.js +261 -35
  822. package/dist/utils/useLiveAnnouncer.svelte.d.ts +77 -2
  823. package/dist/utils/useLiveAnnouncer.svelte.js +119 -2
  824. package/dist/utils/useNavigation.svelte.d.ts +36 -3
  825. package/dist/utils/useNavigation.svelte.js +699 -332
  826. package/dist/utils/usePressAndHold.svelte.d.ts +38 -0
  827. package/dist/utils/usePressAndHold.svelte.js +191 -0
  828. package/dist/utils/useScrollLock.svelte.d.ts +20 -1
  829. package/dist/utils/useScrollLock.svelte.js +54 -13
  830. package/dist/utils/useSlidingIndicator.svelte.d.ts +2 -0
  831. package/dist/utils/useSlidingIndicator.svelte.js +27 -5
  832. package/dist/utils/useTabBridge.svelte.d.ts +20 -0
  833. package/dist/utils/useTabBridge.svelte.js +109 -0
  834. package/dist/utils/values.d.ts +15 -0
  835. package/dist/utils/values.js +49 -0
  836. package/package.json +31 -2
  837. package/dist/generated/componentMcpRegistry.d.ts +0 -142
  838. package/dist/utils/useDrag.svelte.d.ts +0 -11
  839. package/dist/utils/useDrag.svelte.js +0 -55
@@ -1,38 +1,104 @@
1
1
  import { bind } from '../../utils/state.svelte.js';
2
2
  import { Registry } from '../../utils/registry.svelte.js';
3
- import { getContext, hasContext, onMount, setContext, untrack } from 'svelte';
3
+ import { getContext, hasContext, onDestroy, onMount, setContext, untrack } from 'svelte';
4
+ import { on } from 'svelte/events';
4
5
  import { useTheme } from '../Theme/theme.state.svelte.js';
5
- import { computePosition, autoUpdate, hide, offset, shift, flip } from '@floating-ui/dom';
6
6
  import { useScrollLock } from '../../utils/useScrollLock.svelte.js';
7
7
  import { useFocusScope } from '../../utils/useFocusScope.svelte.js';
8
+ import { useTabBridge } from '../../utils/useTabBridge.svelte.js';
9
+ import { composedContains, getDeepActiveElement, isTextField } from '../../utils/focus.js';
10
+ import { provideLayer, useParentLayer } from '../../utils/layers.svelte.js';
8
11
  import { useSafeArea } from '../../utils/safeArea.svelte.js';
9
12
  import { useHoverAction } from '../../utils/useHoverAction.svelte.js';
13
+ import { useOpenLifecycle } from '../../utils/openLifecycle.svelte.js';
14
+ import { getInteractionType, isOpenChangeDetails, requestOpenChange, resolveOpenChangeDetails } from '../../utils/openChange.js';
15
+ import { focusedElement, triggerActivation, triggerFocusTarget, writePopupAria } from '../../utils/trigger.js';
16
+ import { useDirection } from '../../utils/useDirection.svelte.js';
17
+ import { applyStateAttributes, openStateAttributes, placementAttributes, popupSideAttributes, transitionStatusAttributes } from '../../utils/stateAttributes.js';
10
18
  import { usePopoverMotion } from './popover.theme.js';
19
+ import { applyDirectedOffset, claimPopupOpen, claimPopupSide, createPanelPositioner, directedMotion, releasePanelPosition } from './popover.position.js';
11
20
  // `bind(this, options)` installs the option properties on the instance; this type-only base
12
21
  // class is what declares them to TypeScript. (Merging an empty `interface` into the class
13
22
  // would be unsafe declaration merging: the interface promises members the class never defines.)
14
23
  const PopoverOptionsBase = class {
15
24
  };
16
- // The one place the trigger's semantic state becomes ARIA, for triggers the library cannot
17
- // pass props to (a snippet trigger carrying `{@attach popover.reference}`).
18
- /** Elements that may carry popup ARIA state. */
19
- const POPUP_CONTROL = 'button, a[href], input, select, textarea, summary, [role="button"], [role="link"], [role="combobox"], [role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"], [role="tab"], [role="option"], [role="treeitem"], [role="gridcell"], [role="switch"], [role="checkbox"]';
20
- /** Elements the browser already focuses and activates from the keyboard. */
21
- const NATIVE_CONTROL = 'button, a[href], input, select, textarea, summary';
22
- const TRIGGER_ARIA = {
23
- haspopup: 'aria-haspopup',
24
- expanded: 'aria-expanded',
25
- controls: 'aria-controls'
25
+ /** The role a non-dialog popup's content element carries, by `haspopup`. */
26
+ const POPUP_ROLE = {
27
+ menu: 'menu',
28
+ listbox: 'listbox',
29
+ tree: 'tree',
30
+ grid: 'grid'
31
+ };
32
+ /** How the open state was reached, from the change that opened it. */
33
+ const openReasonOf = (details) => {
34
+ if (details.reason === 'trigger-hover')
35
+ return 'hover';
36
+ const fromTrigger = ['trigger-press', 'trigger-focus', 'list-navigation'];
37
+ if (fromTrigger.includes(details.reason)) {
38
+ return details.interaction === 'keyboard' ? 'keyboard' : 'press';
39
+ }
40
+ return 'programmatic';
41
+ };
42
+ /** How close to the viewport's width a touch-opened panel must be to lock page scroll, in px. */
43
+ const TOUCH_LOCK_MARGIN = 20;
44
+ /** A closed popover's safe area: it has none, so no point is inside it. */
45
+ const CLOSED_SAFE_AREA = {
46
+ containsPoint: () => false,
47
+ updateAreas: () => { }
26
48
  };
27
49
  export class PopoverState extends PopoverOptionsBase {
28
- triggerReference = $state(null);
50
+ /** The trigger that opened the popover, while it is open; `null` for a programmatic open. */
51
+ activeTrigger = $state(null);
52
+ /** The most recently attached `reference` / `trigger` element. */
53
+ #latestTrigger = $state(null);
54
+ /** The id of the role owner inside a non-dialog popup (the `role="menu"` element). */
55
+ #popupOwnerId = $state(null);
56
+ /**
57
+ * The trigger the panel anchors to: the one that opened it, else the most recently attached
58
+ * `reference` / `trigger` element.
59
+ */
60
+ triggerReference = $derived(this.activeTrigger ?? this.#latestTrigger);
29
61
  referenceElement = $derived(this.triggerReference || this.externalRef || null);
30
62
  dialogElement = $state(null);
63
+ /** The arrow inside the panel (`arrow`); `null` while there is none. */
64
+ arrowElement = $state(null);
65
+ /** The panel element focus moves into (inside `dialogElement`); `null` while it is not mounted. */
66
+ panelElement = $state(null);
31
67
  // Applied to the animated panel (not the portaled positioning wrapper) so the scale/fly
32
68
  // transition originates from the edge nearest the trigger.
33
69
  transformOrigin = $state('center center');
34
70
  // Trigger-matched width (fitTrigger), applied to the panel.
35
71
  triggerWidth = $state(null);
72
+ /**
73
+ * How the popover was opened: `hover`, `press` (pointer), `keyboard`, or `programmatic`
74
+ * (`open()` from code, the `open` prop, `defaultOpen`). `null` once closed.
75
+ */
76
+ openReason = $state(null);
77
+ /** The details of the last change that was applied, kept until the next one. */
78
+ lastOpenChange = $state.raw(null);
79
+ /** The open state `setOpen` last applied, to tell a change made from outside. */
80
+ #appliedOpen;
81
+ /** Whether a finger opened the popover (a programmatic open leaves the last change stale). */
82
+ get #openedByTouch() {
83
+ return this.openReason === 'press' && this.lastOpenChange?.interaction === 'touch';
84
+ }
85
+ /**
86
+ * Where the floating panel was last placed: the side it sits on (logical when a logical side
87
+ * was requested, `none` when `positionPanel` placed it), its alignment, and whether its anchor
88
+ * is scrolled out of view. `null` until the first placement lands and once the panel unmounts.
89
+ */
90
+ placement = $state(null);
91
+ /**
92
+ * The panel's styling hooks: `data-open` / `data-closed`, `data-entering` / `data-exiting`,
93
+ * `data-side`, `data-align` and `data-anchor-hidden` (see `popoverDataAttributes`).
94
+ */
95
+ panelAttributes = $derived({
96
+ ...openStateAttributes(this.isOpen),
97
+ ...transitionStatusAttributes(this.status),
98
+ ...placementAttributes(this.placement
99
+ ? { side: this.placement.side, align: this.placement.align ?? undefined }
100
+ : undefined, { anchorHidden: this.placement?.anchorHidden })
101
+ });
36
102
  parent = getContext('popover');
37
103
  // Nested popovers join while they mount and leave when torn down; see `Registry`.
38
104
  #children = new Registry();
@@ -40,24 +106,65 @@ export class PopoverState extends PopoverOptionsBase {
40
106
  return this.#children.items;
41
107
  }
42
108
  hasChildOpen = $derived(this.children.some((d) => d.isOpen));
43
- hasTransitioned = $state(false);
44
109
  theme = useTheme();
45
- // The mobile sheet delegates to a Dialog, which registers its own layer.
46
- // An inline panel sits in the flow and is not dismissed by an outside press; Escape still
47
- // reaches it while it is the top layer.
48
- layer = this.theme.layers.register({
49
- kind: 'popover',
50
- isOpen: () => this.isOpen && !this.isMobileSheet,
51
- isModal: () => false,
52
- dismissOnEscape: () => this.closeOnEscape,
53
- dismissOnOutside: () => !this.inline && this.closeOnClickOutside && this.hasTransitioned,
54
- onDismiss: () => this.close(),
55
- state: this
56
- });
110
+ /**
111
+ * Open → entering → open → exiting → closed; completes even when no transition plays.
112
+ * Created in the constructor: it reads the options as it starts, after `bind` installs them.
113
+ */
114
+ lifecycle;
115
+ /** Where the panel is in its open/close lifecycle; see `PopoverApi.status`. */
116
+ get status() {
117
+ return this.lifecycle.status;
118
+ }
119
+ /** @deprecated Read `status === 'open'`; kept for one minor. */
120
+ get hasTransitioned() {
121
+ return this.lifecycle.status === 'open';
122
+ }
123
+ /**
124
+ * What only an open popover needs, while it is open or closing; see `openSession`. A closed
125
+ * popover (every Select, date input and row menu on a page) builds none of it.
126
+ */
127
+ #session = $state.raw(null);
128
+ /** `#session` as last written, for teardowns, which must not read `$state`. */
129
+ #currentSession = null;
130
+ /** The layer this popover renders inside (a Dialog, a parent menu), read when it opens. */
131
+ #parentLayer = useParentLayer();
132
+ /** The popover's layer while it is open or closing, else `null`. */
133
+ get layer() {
134
+ return this.#session?.layer ?? null;
135
+ }
136
+ /**
137
+ * Whether no open layer sits above this popover, except a tooltip: a tooltip never takes focus
138
+ * or holds a control, so one showing over a button in the panel (or over the trigger) must not
139
+ * count as something that took over from it. `false` while closed.
140
+ */
141
+ get isTopLayer() {
142
+ return this.#session?.isTopLayer ?? false;
143
+ }
144
+ /**
145
+ * The safe area around the trigger and the panel (menus ask it whether the pointer is on its way
146
+ * to an open submenu). A closed popover has none: no point is inside it.
147
+ */
148
+ get safeArea() {
149
+ return this.#session?.safeArea ?? CLOSED_SAFE_AREA;
150
+ }
57
151
  computedSize = $derived(this.theme.resolveResponsiveProps(this.size, 'normal'));
58
152
  // `inline` wins over `mobileSheet`: an in-flow panel never becomes a sheet.
59
153
  isMobileSheet = $derived(!this.inline && !!this.mobileSheet && this.theme.isMobile);
60
154
  computedMode = $derived(this.inline ? 'inline' : this.isMobileSheet ? 'mobileSheet' : 'floating');
155
+ /**
156
+ * Whether the panel is modal right now: a floating panel with `modal` contains Tab and makes the
157
+ * page behind it `inert`. An inline panel sits in the page and never is; the mobile sheet is a
158
+ * modal Dialog of its own.
159
+ */
160
+ isModal = $derived(!!this.modal && this.computedMode === 'floating');
161
+ /**
162
+ * Whether the panel holds dialog content. Menus, listboxes, trees and grids render a plain
163
+ * wrapper instead of an unnamed `<dialog>`, and their trigger controls the role owner inside.
164
+ */
165
+ isDialogPopup = $derived((this.haspopup ?? 'dialog') === 'dialog');
166
+ /** The id of the element `aria-controls` points at while open. */
167
+ controlsId = $derived(this.isDialogPopup ? this.id : (this.#popupOwnerId ?? this.id));
61
168
  /**
62
169
  * Trigger state in the library's semantic vocabulary: spread on the built-in Button, and
63
170
  * written as the matching ARIA attributes by `reference` for a snippet trigger.
@@ -65,257 +172,990 @@ export class PopoverState extends PopoverOptionsBase {
65
172
  triggerProps = $derived({
66
173
  haspopup: this.haspopup ?? 'dialog',
67
174
  expanded: this.isOpen,
68
- controls: this.isOpen && !this.isMobileSheet ? this.id : undefined
69
- });
70
- // Non-modal: no Tab containment or `inert`; optional initial focus, always restores.
71
- focusScope = useFocusScope({
72
- isActive: () => this.isOpen && !this.isMobileSheet && this.layer.isTop,
73
- trap: () => false,
74
- initialFocus: () => this.focusOnOpen ?? false,
75
- returnTo: () => this.triggerReference
175
+ controls: this.isOpen && !this.isMobileSheet ? this.controlsId : undefined
76
176
  });
177
+ /**
178
+ * Whether Tab is bridged between the trigger and the portaled panel: a floating dialog popup
179
+ * opened from a trigger, unless `tabBridge` is off. Menus, listboxes and the like manage focus
180
+ * themselves, a modal panel contains Tab on its own, and a panel the pointer merely hovered
181
+ * open is not a Tab destination.
182
+ */
183
+ get tabBridgeActive() {
184
+ return (this.isOpen &&
185
+ this.tabBridge &&
186
+ !this.isModal &&
187
+ this.computedMode === 'floating' &&
188
+ this.isDialogPopup &&
189
+ this.openReason !== 'hover' &&
190
+ this.isTopLayer &&
191
+ this.placement !== null &&
192
+ this.panelElement !== null &&
193
+ this.#bridgeAnchor() !== null);
194
+ }
195
+ /**
196
+ * Whether focus moving away closes the popover: a floating dialog popup that is not modal (a
197
+ * modal one keeps focus), not opened by the pointer hovering, and `closeOnFocusOut` (by
198
+ * default, `closeOnClickOutside`). Menus and lists steer focus themselves.
199
+ */
200
+ get closesOnFocusOut() {
201
+ return ((this.closeOnFocusOut ?? this.closeOnClickOutside) &&
202
+ !this.isModal &&
203
+ this.computedMode === 'floating' &&
204
+ this.isDialogPopup &&
205
+ this.openReason !== 'hover');
206
+ }
77
207
  // Mode preset from `popoverTheme.motion`, through the override ladder
78
208
  // (registry → `setPopoverTheme` → instance `theme.motion` → `transition` prop).
79
209
  resolveMotion = usePopoverMotion();
80
210
  computedTransition = $derived(this.resolveMotion({ mode: this.computedMode }, { motion: this.motion, transition: this.transition }));
81
211
  computedPosition = $derived(this.theme.resolveResponsiveProps(this.position, 'top'));
82
- // Hook instances
83
- safeArea = useSafeArea({
84
- isActive: () => this.isOpen && this.closeOnMouseLeave && this.children.filter((d) => d.isOpen).length === 0,
85
- callback: () => this.close(),
86
- offset: 15,
87
- debug: () => this.debugSafeArea
88
- });
89
212
  hoverAction = useHoverAction({
90
- isActive: () => this.openOnHover && !this.isOpen,
91
- onMouseEnter: () => {
92
- this.open();
213
+ isActive: () => this.openOnHover && !this.modal && !this.isOpen,
214
+ onMouseEnter: (event) => {
215
+ this.setOpen(true, {
216
+ reason: 'trigger-hover',
217
+ event,
218
+ trigger: this.#hoveredTrigger ?? undefined,
219
+ interaction: 'mouse'
220
+ });
93
221
  },
94
- delay: this.delay
222
+ // A function, read on each enter: field initialisers run before `bind(this, options)`
223
+ // installs the options, so a plain `this.delay` here would be `undefined` (no delay).
224
+ delay: () => this.delay,
225
+ // Root hover popovers share the warm-up with tooltips and hover cards. Submenus keep their
226
+ // delay: it is what lets the pointer cross sibling rows on the way to an open submenu.
227
+ group: () => (this.openOnHover && !this.parent ? this.theme.hoverIntent : null),
228
+ isOpen: () => this.isOpen,
229
+ contains: (node) => !!this.dialogElement?.contains(node)
95
230
  });
96
231
  addChild = (child) => () => this.#children.add(child);
232
+ /** The element the panel is anchored to, for its writing direction. */
233
+ #anchorElement = () => {
234
+ const reference = this.referenceElement;
235
+ if (reference instanceof HTMLElement)
236
+ return reference;
237
+ const context = reference?.contextElement;
238
+ return context instanceof HTMLElement ? context : null;
239
+ };
240
+ /** The reading direction logical sides and start/end alignment resolve with. */
241
+ #direction = useDirection(this.#anchorElement);
97
242
  constructor(options) {
98
243
  super();
99
244
  bind(this, options);
245
+ this.lifecycle = useOpenLifecycle({
246
+ isOpen: () => this.isOpen,
247
+ external: () => this.isMobileSheet,
248
+ onAfterOpen: () => this.onAfterOpen?.(this),
249
+ onAfterClose: () => {
250
+ this.#currentSession?.focusScope.restore();
251
+ this.onAfterClose?.(this);
252
+ this.openReason = null;
253
+ this.#setActiveTrigger(null);
254
+ this.#opener = null;
255
+ }
256
+ });
100
257
  setContext('popover', this);
258
+ // Layers registered inside the panel (a nested popover, a dialog it opens) sit above this
259
+ // popover's layer, which exists only while it is open.
260
+ provideLayer(() => this.#currentSession?.layer ?? null);
261
+ // The parent registers its children whatever their payload type.
101
262
  if (this.parent)
102
263
  onMount(this.parent.addChild(this));
103
- useScrollLock({
104
- isActive: () => this.lockScroll && !this.inline && !this.isMobileSheet && !this.parent && this.isOpen
264
+ // Details describe the change `setOpen` made: an open state moved from outside (the bound
265
+ // `open` prop) leaves none, so a later close does not read the one that opened it.
266
+ $effect.pre(() => {
267
+ const open = this.isOpen;
268
+ untrack(() => {
269
+ if (this.#appliedOpen !== open)
270
+ this.lastOpenChange = null;
271
+ this.#appliedOpen = open;
272
+ });
273
+ });
274
+ onDestroy(() => {
275
+ this.#destroyed = true;
105
276
  });
277
+ // An open state that did not come through `setOpen` (the `open` prop, `defaultOpen`) is a
278
+ // programmatic open: focus returns to whatever had it when it opened.
279
+ $effect.pre(() => {
280
+ const open = this.isOpen;
281
+ untrack(() => {
282
+ const committed = this.#committed;
283
+ this.#committed = null;
284
+ if (committed === open || !open)
285
+ return;
286
+ this.openReason = 'programmatic';
287
+ this.#opener = focusedElement();
288
+ });
289
+ });
290
+ }
291
+ /**
292
+ * Whether the open-only machinery is needed: while the popover is open, and until its closing
293
+ * transition has finished. `PopoverSession` is rendered while this holds.
294
+ */
295
+ get sessionActive() {
296
+ return this.isOpen || this.lifecycle.status !== 'closed';
106
297
  }
107
- toggle = () => {
108
- this.setOpen(!this.isOpen);
298
+ /**
299
+ * Builds what only an open popover needs: its layer, focus scope, safe area, Tab bridge, scroll
300
+ * lock and focus-out watch, and registers the attached triggers with them. `PopoverSession`
301
+ * calls it during its initialisation while `sessionActive` holds; everything it creates goes
302
+ * with that component.
303
+ */
304
+ openSession = () => {
305
+ // The mobile sheet delegates to a Dialog, which registers its own layer.
306
+ // An inline panel sits in the flow and is not dismissed by an outside press; Escape still
307
+ // reaches it while it is the top layer.
308
+ const layer = this.theme.layers.register({
309
+ kind: 'popover',
310
+ isOpen: () => this.isOpen && !this.isMobileSheet,
311
+ isModal: () => this.isModal,
312
+ dismissOnEscape: () => this.closeOnEscape,
313
+ dismissOnOutside: () => !this.inline && this.closeOnClickOutside,
314
+ onDismiss: (request) => this.setOpen(false, request),
315
+ state: this,
316
+ // Read here, not from the session component's context, which is this popover's own.
317
+ parent: untrack(this.#parentLayer)
318
+ });
319
+ const isTopLayer = $derived.by(() => {
320
+ const open = this.theme.layers.open;
321
+ const index = open.indexOf(layer);
322
+ if (index < 0)
323
+ return false;
324
+ return open.slice(index + 1).every(({ state }) => {
325
+ // The shared tooltip surface is known by id, so it counts before its panel has
326
+ // mounted: the scope would otherwise release and re-apply `inert` around the tooltip.
327
+ return (state instanceof PopoverState &&
328
+ (`${state.id}-tooltip` === this.theme.tooltipId ||
329
+ !!state.panelElement?.querySelector('[role="tooltip"]')));
330
+ });
331
+ });
332
+ // Non-modal: no Tab containment or `inert`; optional initial focus. Focus goes back when it
333
+ // was inside the panel, or when a trigger opened the popover (Safari does not focus a button
334
+ // on click, so a press and Escape leave focus on <body>). A popover with neither, such as a
335
+ // combobox list, leaves focus alone, even when the control that kept it blurred on purpose.
336
+ // A floating panel is hidden until its first placement lands, and nothing in it can take
337
+ // focus before then, so initial focus waits for that placement.
338
+ const focusScope = useFocusScope({
339
+ isActive: () => this.isOpen &&
340
+ !this.isMobileSheet &&
341
+ isTopLayer &&
342
+ (this.computedMode !== 'floating' || this.placement !== null),
343
+ trap: () => this.isModal,
344
+ inertSiblings: () => this.isModal,
345
+ initialFocus: () => this.focusOnOpen ?? (this.isModal ? 'first' : false),
346
+ restoreFocus: () => this.#focusEntered || this.activeTrigger !== null,
347
+ returnTo: () => this.#returnTarget(),
348
+ // Focus that moved on by itself (Tab past the end of the panel) is not taken back.
349
+ focusOnClose: () => (this.lastOpenChange?.reason === 'focus-out' ? false : this.focusOnClose),
350
+ closeDetails: () => this.lastOpenChange
351
+ });
352
+ // The safe area tracks every open popover (menus ask it whether the pointer is on its way to
353
+ // an open submenu), but leaving it closes only a popover the pointer opened by hovering: one
354
+ // opened by a press, the keyboard or code stays until it is dismissed.
355
+ const safeArea = useSafeArea({
356
+ isActive: () => this.isOpen && this.closeOnMouseLeave && this.children.every((child) => !child.isOpen),
357
+ callback: (event) => {
358
+ if (this.openReason !== 'hover')
359
+ return;
360
+ this.setOpen(false, { reason: 'trigger-hover', event, interaction: 'mouse' });
361
+ },
362
+ offset: 15,
363
+ debug: () => this.debugSafeArea,
364
+ closeDelay: () => this.closeDelay
365
+ });
366
+ // Every attached trigger counts as inside the layer and anchors the safe area.
367
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping, never rendered
368
+ const triggers = new Map();
369
+ const session = {
370
+ layer,
371
+ focusScope,
372
+ safeArea,
373
+ get isTopLayer() {
374
+ return isTopLayer;
375
+ },
376
+ addTrigger: (node) => {
377
+ if (triggers.has(node))
378
+ return;
379
+ triggers.set(node, [layer.node(node), safeArea.anchorReference(node)]);
380
+ },
381
+ removeTrigger: (node) => {
382
+ triggers.get(node)?.forEach((off) => off?.());
383
+ triggers.delete(node);
384
+ }
385
+ };
386
+ untrack(() => {
387
+ for (const node of this.#triggers.keys())
388
+ session.addTrigger(node);
389
+ this.#currentSession = session;
390
+ this.#session = session;
391
+ });
392
+ onDestroy(() => {
393
+ for (const node of [...triggers.keys()])
394
+ session.removeTrigger(node);
395
+ if (this.#currentSession !== session)
396
+ return;
397
+ this.#currentSession = null;
398
+ this.#session = null;
399
+ });
400
+ useTabBridge({
401
+ isActive: () => this.tabBridgeActive,
402
+ anchor: this.#bridgeAnchor,
403
+ panel: () => this.panelElement,
404
+ // A trigger inside another popover's panel tabs on within that panel.
405
+ boundary: () => {
406
+ const anchor = this.#bridgeAnchor();
407
+ const parentPanel = this.parent?.panelElement;
408
+ return anchor && parentPanel && parentPanel.contains(anchor) ? parentPanel : undefined;
409
+ },
410
+ // The bridge has already moved focus on; whether that closes the panel is the same
411
+ // `closeOnFocusOut` decision the focus listener below makes.
412
+ onLeave: (event) => {
413
+ if (!this.closesOnFocusOut)
414
+ return;
415
+ void this.setOpen(false, { reason: 'focus-out', event, interaction: 'keyboard' });
416
+ }
417
+ });
418
+ // Focus that was inside the popover (or on its trigger) moving on closes it. A popover whose
419
+ // panel focus never entered is left to outside presses: Tab, a click or a screen reader's
420
+ // virtual cursor elsewhere on the page only counts once focus has been in the tree. Judged
421
+ // in a microtask, where focus has settled and reactive state is safe to read: `focus()`
422
+ // calls made by a closing popup's teardown dispatch this event in the middle of a flush.
423
+ $effect(() => {
424
+ if (!this.isOpen || !this.closesOnFocusOut)
425
+ return;
426
+ const doc = this.dialogElement?.ownerDocument;
427
+ if (!doc)
428
+ return;
429
+ let within = untrack(() => this.#focusInTree(getDeepActiveElement(doc)));
430
+ let scheduled = false;
431
+ return on(doc, 'focusin', (event) => {
432
+ if (scheduled)
433
+ return;
434
+ scheduled = true;
435
+ queueMicrotask(() => {
436
+ scheduled = false;
437
+ if (!this.isOpen || this.#appliedOpen === false || !this.closesOnFocusOut)
438
+ return;
439
+ const active = getDeepActiveElement(doc);
440
+ if (!active || active === doc.body)
441
+ return;
442
+ if (this.#focusInTree(active)) {
443
+ within = true;
444
+ return;
445
+ }
446
+ if (!within)
447
+ return;
448
+ within = false;
449
+ this.setOpen(false, { reason: 'focus-out', event, interaction: 'keyboard' });
450
+ });
451
+ });
452
+ });
453
+ // A touch-opened popover is non-modal and a finger scrolls the page under it, so it locks
454
+ // scroll only when its panel spans the viewport, where there is nothing left to scroll to.
455
+ let panelSpansViewport = $state(false);
456
+ $effect(() => {
457
+ const panel = this.dialogElement;
458
+ if (!panel || !this.#openedByTouch) {
459
+ panelSpansViewport = false;
460
+ return;
461
+ }
462
+ const measure = () => {
463
+ const view = panel.ownerDocument.defaultView;
464
+ panelSpansViewport =
465
+ !!view && panel.getBoundingClientRect().width >= view.innerWidth - TOUCH_LOCK_MARGIN;
466
+ };
467
+ measure();
468
+ const observer = new ResizeObserver(measure);
469
+ observer.observe(panel);
470
+ return () => observer.disconnect();
471
+ });
472
+ // A hover-opened popover is a preview the pointer can leave: the page keeps scrolling.
473
+ useScrollLock({
474
+ isActive: () => this.lockScroll &&
475
+ !this.inline &&
476
+ !this.isMobileSheet &&
477
+ !this.parent &&
478
+ this.isOpen &&
479
+ this.openReason !== 'hover' &&
480
+ (!this.#openedByTouch || panelSpansViewport)
481
+ });
482
+ // The point the pointer was at belongs to one opening: a later keyboard open must not reuse it.
483
+ $effect(() => {
484
+ if (!this.isOpen)
485
+ return;
486
+ return () => {
487
+ this.#anchorOffset = null;
488
+ };
489
+ });
490
+ // The trigger (or `ref` element) reports the side its placed panel sits on, so a theme can
491
+ // flatten the corner the panel attaches to.
492
+ $effect(() => {
493
+ const anchor = this.referenceElement;
494
+ if (!(anchor instanceof HTMLElement))
495
+ return;
496
+ const { 'data-popup-side': side } = popupSideAttributes(this.placement?.side);
497
+ claimPopupSide(anchor, this, side ?? null);
498
+ return () => claimPopupSide(anchor, this, null);
499
+ });
500
+ // The element the panel is anchored to (the trigger that opened it, or the `ref` element)
501
+ // carries `data-popup-open` while it is open. Claimed like the side: a menu and its tooltip
502
+ // share a trigger, and the tooltip closing leaves the menu's hook in place.
503
+ $effect(() => {
504
+ const anchor = this.referenceElement;
505
+ if (!(anchor instanceof HTMLElement))
506
+ return;
507
+ claimPopupOpen(anchor, this, this.isOpen);
508
+ return () => claimPopupOpen(anchor, this, false);
509
+ });
510
+ // The panel's open state and transition phase, written from here rather than only by the
511
+ // template: Svelte pauses the effects of a block while its out-transition plays, so the
512
+ // panel's own attributes would stay `data-open` until it is gone. The session lives until
513
+ // the exit ends, so `data-closed` and `data-exiting` reach the closing panel.
514
+ $effect(() => {
515
+ const panel = this.panelElement;
516
+ if (!panel)
517
+ return;
518
+ applyStateAttributes(panel, {
519
+ ...openStateAttributes(this.isOpen),
520
+ ...transitionStatusAttributes(this.lifecycle.status)
521
+ });
522
+ });
109
523
  };
110
- open = () => {
111
- this.setOpen(true);
524
+ /** Toggles the popover. A press on the trigger of a popover the pointer opened by hovering pins it open instead. */
525
+ toggle = (input) => {
526
+ const details = this.#details(input);
527
+ if (this.isOpen && details.reason === 'trigger-press') {
528
+ const anchor = this.triggerReference;
529
+ if (this.openReason === 'hover') {
530
+ // Hovered open, then pressed: the press keeps it open and makes it stay.
531
+ this.#openRequests += 1;
532
+ this.openReason = openReasonOf(details);
533
+ return;
534
+ }
535
+ if (details.trigger &&
536
+ anchor &&
537
+ details.trigger !== anchor &&
538
+ this.#triggers.has(details.trigger)) {
539
+ // Another trigger of the same popover: the panel moves to it and stays open.
540
+ this.#openRequests += 1;
541
+ this.#setActiveTrigger(details.trigger);
542
+ this.#opener = triggerFocusTarget(details.trigger, details.event);
543
+ return;
544
+ }
545
+ }
546
+ this.setOpen(!this.isOpen, details);
112
547
  };
113
- close = () => {
114
- this.setOpen(false);
548
+ open = (input) => {
549
+ this.setOpen(true, input);
115
550
  };
551
+ /** Closes the popover. Returns `false` when `onOpenChange` cancelled the change. */
552
+ close = (input) => this.setOpen(false, input);
116
553
  /** Calls to `setOpen`, direct or through `open`, `close` and `toggle`, unchanged state included. */
117
554
  #openRequests = 0;
118
- setOpen = (nextOpen) => {
119
- this.#openRequests += 1;
120
- if (this.isOpen === nextOpen)
555
+ #destroyed = false;
556
+ /** The open state `setOpen` last wrote, until the effect that sees it has run. */
557
+ #committed = null;
558
+ /** Where focus returns when the popover closes; see `#returnTarget`. */
559
+ #opener = null;
560
+ /** Whether focus has been inside the mounted panel. */
561
+ #focusEntered = false;
562
+ // Triggers: every element attached through `reference` (or `trigger`), with the order they
563
+ // attached in. Plain fields, not `$state`: detach teardowns compare against them, and a
564
+ // `$state` read in teardown can return the value from before the change that triggered it.
565
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping, never rendered
566
+ #triggers = new Map();
567
+ #triggerSequence = 0;
568
+ /** Triggers attached during the current flush: a re-rendered trigger's replacement. */
569
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping, never rendered
570
+ #recentTriggers = new Set();
571
+ #latestTriggerNode = null;
572
+ #activeTriggerNode = null;
573
+ #hoveredTrigger = null;
574
+ /** The press dispatching right now on a trigger, so `toggle()` from its handler knows it. */
575
+ #press = null;
576
+ /** The pointer type of the last press on a trigger, for clicks that do not carry one. */
577
+ #pointerType = null;
578
+ #setActiveTrigger(node) {
579
+ this.#activeTriggerNode = node;
580
+ this.activeTrigger = node;
581
+ }
582
+ #setLatestTrigger(node) {
583
+ this.#latestTriggerNode = node;
584
+ this.#latestTrigger = node;
585
+ }
586
+ /** Whether the panel still has an anchor in the document: a trigger, else the `ref` prop. */
587
+ #hasAnchor = () => {
588
+ const anchor = this.#activeTriggerNode ?? this.#latestTriggerNode ?? this.externalRef;
589
+ if (!anchor)
590
+ return false;
591
+ // A floating-ui virtual element (a cursor point) has no DOM presence to lose.
592
+ return !(anchor instanceof Element) || anchor.isConnected;
593
+ };
594
+ /**
595
+ * Closes an open popover whose anchor left the document, so `onOpenChange` reports it with
596
+ * `reason: 'trigger-unmount'`. Skipped while the component itself is being destroyed.
597
+ */
598
+ #closeIfAnchorLost = () => {
599
+ if (this.#destroyed || !this.isOpen || this.#hasAnchor())
121
600
  return;
122
- this.isOpen = nextOpen;
123
- this.onOpenChange?.(nextOpen);
601
+ this.setOpen(false, { reason: 'trigger-unmount' });
124
602
  };
125
- applyDirectedTransition = (node, placement) => {
126
- const side = placement.split('-')[0];
127
- const alignment = placement.split('-')[1];
128
- const axis = side === 'top' || side === 'bottom' ? 'y' : 'x';
129
- const value = side === 'top' || side === 'left' ? 10 : -10;
130
- const transformOriginY = side === 'top' ? 'bottom' : side === 'bottom' ? 'top' : 'center';
131
- const transformOriginX = alignment === 'start' ? 'left' : alignment === 'end' ? 'right' : 'center';
132
- this.transformOrigin = `${transformOriginX} ${transformOriginY}`;
133
- Object.assign(this.computedTransition.in, {
134
- [axis]: value
135
- });
136
- Object.assign(this.computedTransition.out, {
137
- [axis]: value
603
+ /**
604
+ * Focus goes back to the trigger that opened the popover (or the control pressed inside it),
605
+ * and after a programmatic open to the element that had focus when it opened. `null` lets the
606
+ * focus scope use the element focused when the panel mounted.
607
+ */
608
+ #returnTarget = () => {
609
+ if (this.#opener?.isConnected)
610
+ return this.#opener;
611
+ if (this.openReason === 'programmatic' || this.openReason === null)
612
+ return null;
613
+ const trigger = this.activeTrigger ?? this.triggerReference;
614
+ return trigger ? triggerFocusTarget(trigger) : null;
615
+ };
616
+ /**
617
+ * The control Tab starts from and returns to: the one that opened the popover, else the focusable
618
+ * part of the trigger. `null` without a registered trigger (a popover anchored to a `ref`), and
619
+ * for a text field (a date or color input): Tab there moves on to the next field of a form.
620
+ */
621
+ #bridgeAnchor = () => {
622
+ const trigger = this.triggerReference;
623
+ if (!trigger || !this.#triggers.has(trigger))
624
+ return null;
625
+ const anchor = this.openReason !== 'programmatic' && this.#opener?.isConnected
626
+ ? this.#opener
627
+ : triggerFocusTarget(trigger);
628
+ return anchor && !isTextField(anchor) ? anchor : null;
629
+ };
630
+ /**
631
+ * Whether `target` belongs to this popover: its panel, a trigger, the `ref` element, or a popup
632
+ * opened from any of them (a nested popover, a dialog the panel opened).
633
+ */
634
+ #focusInTree = (target) => {
635
+ if (!target)
636
+ return false;
637
+ const external = this.externalRef;
638
+ if (external instanceof Node && composedContains(external, target))
639
+ return true;
640
+ // Without a layer (closed) nothing opened from the popover is showing.
641
+ const own = this.layer;
642
+ if (!own)
643
+ return false;
644
+ const open = this.theme.layers.open;
645
+ // A modal layer opened above this popover (a Dialog or confirmation the panel's content
646
+ // opened, rendered elsewhere) holds focus while the popover waits underneath it.
647
+ const above = open.indexOf(own);
648
+ if (above >= 0 &&
649
+ open
650
+ .slice(above + 1)
651
+ .some((layer) => layer.isModal && [...layer.nodes].some((node) => composedContains(node, target))))
652
+ return true;
653
+ return open.some((layer) => {
654
+ for (let current = layer; current; current = current.parent) {
655
+ if (current !== own)
656
+ continue;
657
+ return [...layer.nodes].some((node) => composedContains(node, target));
658
+ }
659
+ return false;
138
660
  });
139
661
  };
140
- place = async (node, mount = false) => {
141
- // Inline panels are laid out by the document, never by floating-ui.
142
- if (this.inline || this.isMobileSheet || !this.referenceElement) {
143
- this.triggerWidth = null;
144
- return;
145
- }
146
- if (!mount && !this.hasTransitioned) {
147
- return;
662
+ /** The details for a request, filled in from the trigger press it happens during. */
663
+ #details = (input) => {
664
+ if (isOpenChangeDetails(input))
665
+ return input;
666
+ const event = input instanceof Event ? input : input?.event;
667
+ const press = this.#press && (!event || event === this.#press.event) ? this.#press : null;
668
+ const fallback = press
669
+ ? {
670
+ reason: press.reason,
671
+ event: press.event,
672
+ trigger: press.node,
673
+ interaction: getInteractionType(press.event, this.#pointerType)
674
+ }
675
+ : { interaction: getInteractionType(event, this.#pointerType) };
676
+ return resolveOpenChangeDetails(input, fallback);
677
+ };
678
+ /**
679
+ * Requests an open-state change. `onOpenChange(nextOpen, details)` runs first; when it calls
680
+ * `details.cancel()` nothing changes. Returns `false` when the change was cancelled.
681
+ */
682
+ setOpen = (nextOpen, input) => {
683
+ this.#openRequests += 1;
684
+ if (this.isOpen === nextOpen) {
685
+ // A press on the trigger of a popover the pointer opened by hovering pins it open, the
686
+ // same as `toggle()` does: a menu's submenu trigger opens its submenu with `open()`.
687
+ if (nextOpen && this.openReason === 'hover') {
688
+ const pressed = this.#details(input);
689
+ if (pressed.reason === 'trigger-press')
690
+ this.openReason = openReasonOf(pressed);
691
+ }
692
+ return true;
148
693
  }
149
- if (this.fitTrigger) {
150
- this.triggerWidth = this.referenceElement.getBoundingClientRect().width;
694
+ const details = this.#details(input);
695
+ if (!requestOpenChange(this.onOpenChange, nextOpen, details))
696
+ return false;
697
+ // A hover open still waiting on its delay belongs to the state before this change: left
698
+ // pending, it would reopen a popover the user just closed by click or Escape.
699
+ this.hoverAction.cancel();
700
+ if (nextOpen) {
701
+ const trigger = details.trigger && this.#triggers.has(details.trigger) ? details.trigger : null;
702
+ this.#setActiveTrigger(trigger);
703
+ this.openReason = openReasonOf(details);
704
+ this.#opener =
705
+ this.openReason === 'programmatic'
706
+ ? focusedElement()
707
+ : trigger
708
+ ? triggerFocusTarget(trigger, details.event)
709
+ : null;
151
710
  }
152
- const custom = this.positionPanel?.({ panel: node, reference: this.referenceElement });
153
- if (custom) {
154
- if (custom.minWidth != null)
155
- this.triggerWidth = custom.minWidth;
156
- Object.assign(node.style, {
157
- position: 'fixed',
158
- left: `${custom.x}px`,
159
- top: `${custom.y}px`,
160
- visibility: ''
161
- });
162
- this.safeArea.updateAreas();
711
+ this.lastOpenChange = details;
712
+ this.#appliedOpen = nextOpen;
713
+ this.#committed = nextOpen;
714
+ this.isOpen = nextOpen;
715
+ return true;
716
+ };
717
+ /**
718
+ * Points the panel's motion at the side facing the reference, for the resolved placement: the
719
+ * scale origin and the exit follow every placement (a flip included), the entrance only the
720
+ * placement made before it plays.
721
+ */
722
+ applyDirectedTransition = (placement, { direction = 'ltr', intro = true } = {}) => {
723
+ const motion = directedMotion(placement, direction);
724
+ this.transformOrigin = motion.transformOrigin;
725
+ if (intro)
726
+ applyDirectedOffset(this.computedTransition.in, motion);
727
+ applyDirectedOffset(this.computedTransition.out, motion);
728
+ };
729
+ /** Records a placement, reassigning only what changed so styling hooks don't churn on scroll. */
730
+ #setPlacement = ({ side, align, anchorHidden }) => {
731
+ const current = this.placement;
732
+ if (current?.side === side && current.align === align && current.anchorHidden === anchorHidden)
163
733
  return;
164
- }
165
- const { x, y, strategy, placement } = await computePosition(this.referenceElement, node, {
166
- strategy: 'fixed',
167
- placement: this.computedPosition,
168
- middleware: [
169
- offset(this.offset ?? 4),
170
- flip({
171
- mainAxis: true,
172
- crossAxis: true,
173
- padding: 20
174
- }),
175
- shift({
176
- mainAxis: true,
177
- crossAxis: true,
178
- padding: 20
179
- }),
180
- hide()
181
- ]
182
- });
183
- Object.assign(node.style, {
184
- position: strategy,
185
- left: `${x}px`,
186
- top: `${y}px`,
187
- // computePosition is async: unhide only once the first placement lands, so the
188
- // panel never flashes at top-left (0,0) before floating-ui resolves.
189
- visibility: ''
190
- });
191
- this.safeArea.updateAreas();
192
- if (mount && !this.hasTransitioned && this.directedTransition) {
193
- this.applyDirectedTransition(node, placement);
194
- }
734
+ this.placement = { side, align, anchorHidden };
195
735
  };
736
+ /**
737
+ * Where the pointer last was over the trigger while the popover was closed, in viewport
738
+ * coordinates. Frozen while open: `anchorTo: 'line'` anchors to the line under it.
739
+ */
740
+ #anchorOffset = null;
741
+ /**
742
+ * The captured point resolved against where its reference is now: held as an offset from the
743
+ * reference's box, it stays on the same line when the page or a scroll ancestor scrolls.
744
+ */
745
+ #anchorPoint = () => {
746
+ const offset = this.#anchorOffset;
747
+ if (!offset)
748
+ return null;
749
+ const rect = offset.reference.getBoundingClientRect();
750
+ return { x: rect.left + offset.dx, y: rect.top + offset.dy };
751
+ };
752
+ // floating-ui placement lives in `popover.position.ts`. Its inputs are read when a placement
753
+ // runs: the mount placement runs inside the `dialog` attachment, so a change to any of them
754
+ // re-places an open panel.
755
+ #positioner = createPanelPositioner({
756
+ reference: () => this.referenceElement,
757
+ // Inline panels and mobile sheets are laid out by the document, never by floating-ui.
758
+ floating: () => !this.inline && !this.isMobileSheet,
759
+ // Untracked: floating-ui runs its first observed update synchronously inside the panel
760
+ // attachment, which would otherwise re-run (and re-mount the placement) when the opening
761
+ // transition ends. The catch-up placement in `dialog` covers that moment instead.
762
+ settled: () => untrack(() => this.lifecycle.status === 'open'),
763
+ placement: () => this.computedPosition,
764
+ offset: () => this.offset,
765
+ fitTrigger: () => this.fitTrigger,
766
+ positionPanel: () => this.positionPanel,
767
+ direction: this.#direction,
768
+ collisionBoundary: () => this.collisionBoundary,
769
+ fallbackAxisSide: () => this.fallbackAxisSide,
770
+ anchorTo: () => this.anchorTo,
771
+ anchorPoint: this.#anchorPoint,
772
+ arrow: () => (this.arrow && this.computedMode === 'floating' ? this.arrowElement : null),
773
+ setMinWidth: (width) => {
774
+ this.triggerWidth = width;
775
+ },
776
+ // `positionPanel` places synchronously, inside the panel attachment: nothing read here may
777
+ // become one of its dependencies.
778
+ onPlace: ({ placement, side, align, anchorHidden, direction, mount }) => untrack(() => {
779
+ this.#setPlacement({ side, align, anchorHidden });
780
+ this.safeArea.updateAreas();
781
+ if (placement && this.directedTransition) {
782
+ this.applyDirectedTransition(placement, {
783
+ direction,
784
+ intro: mount && this.lifecycle.status !== 'open'
785
+ });
786
+ }
787
+ })
788
+ });
789
+ /** Places the floating panel against its reference once; see `PanelPositioner.place`. */
790
+ place = (node, mount = false) => this.#positioner.place(node, mount);
791
+ /** Attachment for the positioning wrapper (`<dialog>`, or a `<div>` for a non-dialog popup). */
196
792
  dialog = (node) => {
197
793
  this.dialogElement = node;
198
794
  if (this.inline) {
199
795
  // No portal, no fixed placement: the wrapper stays where the component is rendered.
200
796
  this.triggerWidth = null;
201
- Object.assign(node.style, {
202
- position: '',
203
- left: '',
204
- top: '',
205
- visibility: ''
206
- });
797
+ releasePanelPosition(node, true);
207
798
  return () => {
208
799
  this.dialogElement = null;
209
800
  };
210
801
  }
211
802
  if (this.isMobileSheet) {
212
803
  this.triggerWidth = null;
213
- Object.assign(node.style, {
214
- position: '',
215
- left: '',
216
- top: ''
217
- });
804
+ releasePanelPosition(node, false);
218
805
  return () => {
219
806
  this.dialogElement = null;
220
807
  };
221
808
  }
222
- // Hide until place() resolves (async computePosition), preventing the top-left flash.
223
- node.style.visibility = 'hidden';
224
- void this.place(node, true);
225
- const cleanup = autoUpdate(this.referenceElement, node, () => this.place(node));
809
+ const reference = this.referenceElement;
810
+ // The anchor can go while the panel's outro still runs (its trigger unmounted): the panel
811
+ // keeps its last place, since floating-ui cannot observe a missing reference.
812
+ if (!reference) {
813
+ return () => {
814
+ this.dialogElement = null;
815
+ queueMicrotask(this.#closeIfAnchorLost);
816
+ };
817
+ }
818
+ // A reference that leaves the document closes the popover instead of being placed.
819
+ const cleanup = this.#positioner.track(node, reference, this.#closeIfAnchorLost);
820
+ // Changes observed during the opening transition are not placed; catch up once it ends,
821
+ // so content that resized while opening doesn't leave the panel misplaced.
822
+ $effect(() => {
823
+ if (this.lifecycle.status === 'open')
824
+ untrack(() => void this.place(node));
825
+ });
226
826
  return () => {
227
827
  cleanup();
228
828
  this.dialogElement = null;
829
+ // Forget the placement once the panel is gone, not when it is only placed again (a new
830
+ // `position`), so the styling hooks and the focus gate don't flicker in between.
831
+ queueMicrotask(() => {
832
+ if (!this.dialogElement)
833
+ this.placement = null;
834
+ });
835
+ // The panel also leaves when its `ref` anchor does (`bind:this` resets it to null),
836
+ // and without an outro that happens before the positioner's observers can report the
837
+ // detached node: judge the anchor once the flush settles, so the popover closes
838
+ // instead of staying open and reappearing when the anchor returns. A no-op when the
839
+ // popover closed or was destroyed, or when another anchor took over.
840
+ queueMicrotask(this.#closeIfAnchorLost);
229
841
  };
230
842
  };
231
843
  panel = (node) => {
232
844
  return untrack(() => {
233
845
  const cleanups = [];
234
- cleanups.push(this.layer.node(node));
235
- cleanups.push(this.focusScope.attachment(node));
236
- cleanups.push(this.safeArea.floatingReference?.(node));
846
+ this.panelElement = node;
847
+ cleanups.push(() => {
848
+ if (this.panelElement === node)
849
+ this.panelElement = null;
850
+ });
851
+ this.#focusEntered = node.contains(node.ownerDocument.activeElement);
852
+ cleanups.push(on(node, 'focusin', () => {
853
+ this.#focusEntered = true;
854
+ }));
855
+ // The session exists whenever the panel does: it is rendered first, while open or closing.
856
+ const session = this.#currentSession;
857
+ if (session) {
858
+ cleanups.push(session.layer.node(node));
859
+ cleanups.push(session.focusScope.attachment(node));
860
+ cleanups.push(session.safeArea.floatingReference(node));
861
+ }
862
+ if (!this.isDialogPopup)
863
+ cleanups.push(this.#labelPopupOwner(node));
237
864
  return () => {
238
865
  cleanups.forEach((cleanup) => cleanup?.());
239
866
  };
240
867
  });
241
868
  };
242
- reference = (node) => {
243
- // Keep the trigger's ARIA in sync whichever way it was rendered (snippet or Button).
244
- // Only real controls carry aria-haspopup/aria-expanded; a wrapper div or a
245
- // presentational span used as the anchor must not (axe: aria-allowed-attr).
246
- const canCarryPopupState = node.matches(POPUP_CONTROL);
247
- $effect(() => {
248
- if (!canCarryPopupState)
869
+ /**
870
+ * A menu, listbox, tree or grid popup: its trigger's `aria-controls` points at the element
871
+ * carrying that role (not the wrapper), and that element is labelled by the trigger unless it
872
+ * has a name of its own. Ids it has to create are removed again when the panel goes.
873
+ */
874
+ #labelPopupOwner = (panel) => {
875
+ const haspopup = this.haspopup ?? 'dialog';
876
+ const role = haspopup === true ? 'menu' : POPUP_ROLE[haspopup];
877
+ const added = [];
878
+ const created = (element, name) => added.some(([e, n]) => e === element && n === name);
879
+ // Never replaces an attribute the consumer wrote; one this code wrote may be rewritten.
880
+ const set = (element, name, value) => {
881
+ if (element.hasAttribute(name) && !created(element, name))
882
+ return;
883
+ if (!created(element, name))
884
+ added.push([element, name]);
885
+ element.setAttribute(name, value);
886
+ };
887
+ const unset = (element, name) => {
888
+ if (!created(element, name))
249
889
  return;
250
- for (const [prop, value] of Object.entries(this.triggerProps)) {
251
- const name = TRIGGER_ARIA[prop];
252
- if (value === undefined)
253
- node.removeAttribute(name);
254
- else
255
- node.setAttribute(name, String(value));
890
+ element.removeAttribute(name);
891
+ added.splice(added.findIndex(([e, n]) => e === element && n === name), 1);
892
+ };
893
+ let owner = null;
894
+ // Named by the consumer: `label` / `labelledBy` win over the trigger. Read reactively, so a
895
+ // name that changes while the popover is open reaches the role owner.
896
+ const name = () => {
897
+ // Read before the owner check, so the effect tracks them while no owner exists yet.
898
+ const { label, labelledBy } = this;
899
+ if (!owner)
900
+ return;
901
+ unset(owner, 'aria-label');
902
+ unset(owner, 'aria-labelledby');
903
+ if (labelledBy)
904
+ set(owner, 'aria-labelledby', labelledBy);
905
+ if (label)
906
+ set(owner, 'aria-label', label);
907
+ const trigger = this.triggerReference;
908
+ if (trigger && !owner.hasAttribute('aria-label') && !owner.hasAttribute('aria-labelledby')) {
909
+ set(trigger, 'id', `${this.id}-trigger`);
910
+ set(owner, 'aria-labelledby', trigger.id);
256
911
  }
912
+ };
913
+ const resolve = () => {
914
+ const next = panel.querySelector(`[role="${role}"]`);
915
+ if (next === owner)
916
+ return;
917
+ if (owner)
918
+ for (const attribute of ['aria-label', 'aria-labelledby'])
919
+ unset(owner, attribute);
920
+ owner = next;
921
+ if (!owner) {
922
+ this.#popupOwnerId = null;
923
+ return;
924
+ }
925
+ set(owner, 'id', `${this.id}-${role}`);
926
+ this.#popupOwnerId = owner.id;
927
+ name();
928
+ };
929
+ $effect(name);
930
+ queueMicrotask(resolve);
931
+ const observer = typeof MutationObserver === 'undefined' ? null : new MutationObserver(resolve);
932
+ observer?.observe(panel, { childList: true, subtree: true });
933
+ return () => {
934
+ observer?.disconnect();
935
+ for (const [element, name] of added.splice(0))
936
+ element.removeAttribute(name);
937
+ this.#popupOwnerId = null;
938
+ };
939
+ };
940
+ /** Remembers a press on a trigger until its event has dispatched. */
941
+ #notePress = (node, event, reason) => {
942
+ const press = { node, event, reason };
943
+ this.#press = press;
944
+ setTimeout(() => {
945
+ if (this.#press === press)
946
+ this.#press = null;
947
+ });
948
+ };
949
+ reference = (node) => {
950
+ // Keep the trigger's ARIA in sync whichever way it was rendered (snippet or Button). With
951
+ // several triggers, only the one the panel is anchored to reads as expanded. Closed, they all
952
+ // read the same: the anchor is not read then, so attaching a trigger (a row of a long list
953
+ // sharing one popover) does not rewrite every other trigger's attributes.
954
+ $effect(() => {
955
+ const props = this.triggerProps;
956
+ const anchored = !props.expanded || this.triggerReference === node || this.triggerReference === null;
957
+ writePopupAria(node, {
958
+ ...props,
959
+ expanded: props.expanded && anchored,
960
+ controls: anchored ? props.controls : undefined
961
+ });
257
962
  });
258
963
  return untrack(() => {
259
- this.triggerReference = node;
964
+ this.#triggers.set(node, ++this.#triggerSequence);
965
+ this.#recentTriggers.add(node);
966
+ queueMicrotask(() => this.#recentTriggers.delete(node));
967
+ this.#setLatestTrigger(node);
260
968
  // Gather all cleanup callbacks
261
969
  const cleanups = [];
262
- cleanups.push(this.layer.node(node));
263
- cleanups.push(this.safeArea.anchorReference?.(node));
970
+ // Inside the layer and anchoring the safe area while open; see `openSession`.
971
+ this.#currentSession?.addTrigger(node);
972
+ cleanups.push(() => this.#currentSession?.removeTrigger(node));
973
+ // Before the hover action's own listener, which may open at once (no delay).
974
+ cleanups.push(on(node, 'mouseenter', () => {
975
+ this.#hoveredTrigger = node;
976
+ }));
264
977
  cleanups.push(this.hoverAction.reference?.(node));
978
+ // Capture phase: these run before the element's own (delegated) handlers, so a
979
+ // `popover.toggle()` called from `onclick` knows the press it belongs to.
980
+ cleanups.push(on(node, 'pointerdown', (event) => {
981
+ this.#pointerType = event.pointerType;
982
+ }, { capture: true }));
983
+ const notePress = (event) => this.#notePress(node, event, 'trigger-press');
984
+ const noteKey = (event) => {
985
+ if (event.key === 'Enter' || event.key === ' ')
986
+ this.#notePress(node, event, 'trigger-press');
987
+ else if (event.key === 'ArrowDown' || event.key === 'ArrowUp')
988
+ this.#notePress(node, event, 'list-navigation');
989
+ };
990
+ node.addEventListener('click', notePress, true);
991
+ node.addEventListener('keydown', noteKey, true);
992
+ cleanups.push(() => {
993
+ node.removeEventListener('click', notePress, true);
994
+ node.removeEventListener('keydown', noteKey, true);
995
+ });
996
+ cleanups.push(this.#trackAnchorPoint(node));
265
997
  // Return combined cleanup function
266
998
  return () => {
267
999
  cleanups.forEach((cleanup) => cleanup?.());
1000
+ this.#triggers.delete(node);
1001
+ this.#recentTriggers.delete(node);
1002
+ if (this.#hoveredTrigger === node)
1003
+ this.#hoveredTrigger = null;
1004
+ const wasActive = this.#activeTriggerNode === node;
1005
+ const wasAnchor = wasActive || (!this.#activeTriggerNode && this.#latestTriggerNode === node);
1006
+ if (wasActive)
1007
+ this.#setActiveTrigger(null);
1008
+ if (this.#latestTriggerNode === node)
1009
+ this.#setLatestTrigger(this.#newestTrigger());
1010
+ if (!wasAnchor)
1011
+ return;
1012
+ // A trigger re-rendered as a new element (a re-rendered snippet, a responsive
1013
+ // branch) attaches in the same flush: the panel moves to it. Only a trigger that
1014
+ // is gone for good closes the popover instead of leaving it on a detached node.
1015
+ const sequence = this.#triggerSequence;
1016
+ const replacements = [...this.#recentTriggers];
1017
+ queueMicrotask(() => {
1018
+ if (this.#destroyed || !this.isOpen)
1019
+ return;
1020
+ const successor = [...replacements, ...this.#triggersAfter(sequence)].find((candidate) => this.#triggers.has(candidate) && candidate.isConnected);
1021
+ if (successor) {
1022
+ if (wasActive)
1023
+ this.#setActiveTrigger(successor);
1024
+ return;
1025
+ }
1026
+ // The trigger that opened it is gone: another trigger does not inherit it.
1027
+ if (wasActive && !this.externalRef) {
1028
+ this.setOpen(false, { reason: 'trigger-unmount' });
1029
+ return;
1030
+ }
1031
+ this.#closeIfAnchorLost();
1032
+ });
268
1033
  };
269
1034
  });
270
1035
  };
1036
+ #newestTrigger() {
1037
+ let newest = null;
1038
+ let newestSequence = -1;
1039
+ for (const [node, sequence] of this.#triggers) {
1040
+ if (sequence > newestSequence)
1041
+ [newest, newestSequence] = [node, sequence];
1042
+ }
1043
+ return newest;
1044
+ }
1045
+ #triggersAfter(sequence) {
1046
+ return [...this.#triggers].filter(([, at]) => at > sequence).map(([node]) => node);
1047
+ }
271
1048
  /**
272
- * Makes any element a complete trigger: it anchors the panel (as \`reference\` does), toggles
273
- * it on click when \`openOnClick\` allows, and keeps \`aria-expanded\` and friends in sync.
274
- * An element that is not already a control also gets \`role="button"\`, \`tabindex="0"\` and
275
- * Enter/Space activation, so a card or an avatar opens the panel from the keyboard too.
1049
+ * Follows the pointer over the trigger while the popover is closed, so an open anchored to a
1050
+ * line (`anchorTo: 'line'`) uses the line the pointer was on; the point stays put while open.
276
1051
  */
277
- trigger = (node) => {
278
- const nativeControl = node.matches(NATIVE_CONTROL);
279
- if (!node.matches(POPUP_CONTROL) && !node.hasAttribute('role')) {
280
- node.setAttribute('role', 'button');
281
- }
282
- if (!nativeControl && !node.hasAttribute('tabindex'))
283
- node.tabIndex = 0;
284
- // The element's own handler wins. One that still opens, closes or toggles the popover
285
- // (`onclick={popover.toggle}` kept from before this attachment existed) has acted by the
286
- // time the event finishes dispatching, so the default toggle waits until then and runs only
287
- // if nothing asked for an open state meanwhile; toggling regardless would undo that call.
288
- let pending;
289
- const activate = () => {
290
- if (!this.openOnClick)
1052
+ #trackAnchorPoint = (node) => {
1053
+ const follow = (event) => {
1054
+ const reference = this.referenceElement;
1055
+ if (this.isOpen || !reference)
291
1056
  return;
292
- const requests = this.#openRequests;
293
- clearTimeout(pending);
294
- pending = setTimeout(() => {
295
- if (this.#openRequests === requests)
296
- this.toggle();
297
- });
1057
+ const rect = reference.getBoundingClientRect();
1058
+ this.#anchorOffset = {
1059
+ reference,
1060
+ dx: event.clientX - rect.left,
1061
+ dy: event.clientY - rect.top
1062
+ };
298
1063
  };
299
- const onKeydown = (event) => {
300
- if (nativeControl || event.target !== node)
301
- return;
302
- if (event.key !== 'Enter' && event.key !== ' ')
303
- return;
304
- event.preventDefault();
305
- activate();
1064
+ // A finger lifts (pointerleave) before the click that opens the popover: keep its point.
1065
+ const forget = (event) => {
1066
+ if (!this.isOpen && event.pointerType !== 'touch')
1067
+ this.#anchorOffset = null;
1068
+ };
1069
+ // A keyboard open has no pointer: it takes the first or last line, not a stale hover point.
1070
+ const forgetOnKey = () => {
1071
+ if (!this.isOpen)
1072
+ this.#anchorOffset = null;
1073
+ };
1074
+ node.addEventListener('pointerenter', follow);
1075
+ node.addEventListener('pointermove', follow);
1076
+ node.addEventListener('pointerdown', follow);
1077
+ node.addEventListener('pointerleave', forget);
1078
+ node.addEventListener('keydown', forgetOnKey);
1079
+ return () => {
1080
+ node.removeEventListener('pointerenter', follow);
1081
+ node.removeEventListener('pointermove', follow);
1082
+ node.removeEventListener('pointerdown', follow);
1083
+ node.removeEventListener('pointerleave', forget);
1084
+ node.removeEventListener('keydown', forgetOnKey);
1085
+ };
1086
+ };
1087
+ /** Attachment for the arrow element inside the panel; see the `arrow` prop. */
1088
+ arrowRef = (node) => {
1089
+ this.arrowElement = node;
1090
+ return () => {
1091
+ if (this.arrowElement === node)
1092
+ this.arrowElement = null;
1093
+ };
1094
+ };
1095
+ /** Payload getters of the triggers made with `triggerFor`. */
1096
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity -- teardown bookkeeping; `#payloadVersion` carries the reactivity
1097
+ #payloads = new Map();
1098
+ #payloadVersion = $state(0);
1099
+ /**
1100
+ * The payload of the trigger the panel is anchored to: the one that opened it, else the most
1101
+ * recently attached. `undefined` for a trigger made without one. Several triggers share this one
1102
+ * popup, so a list of rows needs a single popover, not one per row.
1103
+ */
1104
+ payload = $derived.by(() => {
1105
+ void this.#payloadVersion;
1106
+ const trigger = this.triggerReference;
1107
+ return trigger ? this.#payloads.get(trigger)?.() : undefined;
1108
+ });
1109
+ /**
1110
+ * A complete trigger (see `trigger`) that carries data for the panel: read it back as
1111
+ * `popover.payload` while this trigger is the one the panel is anchored to. Pass a getter, so
1112
+ * the payload follows its source without re-attaching the trigger:
1113
+ * `{@attach popover.triggerFor(() => row)}`.
1114
+ */
1115
+ triggerFor(payload) {
1116
+ return (node) => {
1117
+ const attached = this.trigger(node);
1118
+ untrack(() => {
1119
+ this.#payloads.set(node, payload);
1120
+ this.#payloadVersion += 1;
1121
+ });
1122
+ return () => {
1123
+ attached?.();
1124
+ untrack(() => {
1125
+ if (this.#payloads.get(node) !== payload)
1126
+ return;
1127
+ this.#payloads.delete(node);
1128
+ this.#payloadVersion += 1;
1129
+ });
1130
+ };
306
1131
  };
307
- node.addEventListener('click', activate);
308
- node.addEventListener('keydown', onKeydown);
1132
+ }
1133
+ /**
1134
+ * Makes any element a complete trigger: it anchors the panel (as `reference` does), toggles
1135
+ * it on click when `openOnClick` allows, and keeps `aria-expanded` and friends in sync.
1136
+ * An element that is not already a control also gets `role="button"`, `tabindex="0"` and
1137
+ * Enter/Space activation, so a card or an avatar opens the panel from the keyboard too.
1138
+ * The element's own handler runs first: calling `event.preventDefault()` there, or opening,
1139
+ * closing or toggling the popover itself, stops the default toggle.
1140
+ */
1141
+ trigger = (node) => {
1142
+ const offActivation = triggerActivation(node, {
1143
+ enabled: () => this.openOnClick,
1144
+ requests: () => this.#openRequests,
1145
+ activate: (event) => this.toggle({ reason: 'trigger-press', event, trigger: node })
1146
+ });
309
1147
  const offReference = this.reference(node);
310
1148
  return () => {
311
- clearTimeout(pending);
312
- node.removeEventListener('click', activate);
313
- node.removeEventListener('keydown', onKeydown);
1149
+ offActivation();
314
1150
  offReference?.();
315
1151
  };
316
1152
  };
317
1153
  }
318
- // Use interface merging to add the properties
1154
+ /**
1155
+ * The state behind the `PopoverApi` a Popover hands its snippets and callbacks. For library
1156
+ * components that drive a popover's internals (menus, hover cards); consumers get the narrow API.
1157
+ */
1158
+ export const popoverInternals = (popover) => popover;
319
1159
  export const usePopoverContext = () => {
320
1160
  const hasPopover = hasContext('popover');
321
1161
  if (!hasPopover) {