fancy-ui-svelte 0.11.0 → 0.13.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 (553) hide show
  1. package/README.md +4 -4
  2. package/dist/fancy-ui/_internals/ScrollLockHarness.test.svelte +29 -0
  3. package/dist/fancy-ui/_internals/ScrollLockHarness.test.svelte.d.ts +3 -0
  4. package/dist/fancy-ui/_internals/ScrollLockPanel.test.svelte +43 -0
  5. package/dist/fancy-ui/_internals/ScrollLockPanel.test.svelte.d.ts +8 -0
  6. package/dist/fancy-ui/_internals/anchor-position.d.ts +18 -7
  7. package/dist/fancy-ui/_internals/anchor-position.js +45 -10
  8. package/dist/fancy-ui/_internals/anchor-position.test.js +48 -1
  9. package/dist/fancy-ui/_internals/dismissable.d.ts +16 -0
  10. package/dist/fancy-ui/_internals/dismissable.js +23 -6
  11. package/dist/fancy-ui/_internals/dismissable.test.js +115 -6
  12. package/dist/fancy-ui/_internals/focus-trap.d.ts +36 -0
  13. package/dist/fancy-ui/_internals/focus-trap.js +106 -39
  14. package/dist/fancy-ui/_internals/focus-trap.test.js +356 -1
  15. package/dist/fancy-ui/_internals/motion/AnchoredHarness.test.svelte +42 -0
  16. package/dist/fancy-ui/_internals/motion/AnchoredHarness.test.svelte.d.ts +11 -0
  17. package/dist/fancy-ui/_internals/motion/TransitionsHarness.test.svelte +32 -0
  18. package/dist/fancy-ui/_internals/motion/TransitionsHarness.test.svelte.d.ts +10 -0
  19. package/dist/fancy-ui/_internals/motion/anchored.d.ts +104 -0
  20. package/dist/fancy-ui/_internals/motion/anchored.js +141 -0
  21. package/dist/fancy-ui/_internals/motion/anchored.test.d.ts +1 -0
  22. package/dist/fancy-ui/_internals/motion/anchored.test.js +250 -0
  23. package/dist/fancy-ui/_internals/motion/haptics.d.ts +38 -0
  24. package/dist/fancy-ui/_internals/motion/haptics.js +59 -0
  25. package/dist/fancy-ui/_internals/motion/haptics.test.d.ts +1 -0
  26. package/dist/fancy-ui/_internals/motion/haptics.test.js +70 -0
  27. package/dist/fancy-ui/_internals/motion/in-view.d.ts +24 -0
  28. package/dist/fancy-ui/_internals/motion/in-view.js +99 -0
  29. package/dist/fancy-ui/_internals/motion/in-view.test.d.ts +1 -0
  30. package/dist/fancy-ui/_internals/motion/in-view.test.js +149 -0
  31. package/dist/fancy-ui/_internals/motion/media-query.svelte.d.ts +26 -0
  32. package/dist/fancy-ui/_internals/motion/media-query.svelte.js +69 -0
  33. package/dist/fancy-ui/_internals/motion/media-query.test.d.ts +1 -0
  34. package/dist/fancy-ui/_internals/motion/media-query.test.js +175 -0
  35. package/dist/fancy-ui/_internals/motion/presets.d.ts +34 -0
  36. package/dist/fancy-ui/_internals/motion/presets.js +33 -0
  37. package/dist/fancy-ui/_internals/motion/presets.test.d.ts +1 -0
  38. package/dist/fancy-ui/_internals/motion/presets.test.js +48 -0
  39. package/dist/fancy-ui/_internals/motion/raf.d.ts +35 -0
  40. package/dist/fancy-ui/_internals/motion/raf.js +54 -0
  41. package/dist/fancy-ui/_internals/motion/raf.test.d.ts +1 -0
  42. package/dist/fancy-ui/_internals/motion/raf.test.js +104 -0
  43. package/dist/fancy-ui/_internals/motion/stagger.d.ts +32 -0
  44. package/dist/fancy-ui/_internals/motion/stagger.js +51 -0
  45. package/dist/fancy-ui/_internals/motion/stagger.test.d.ts +1 -0
  46. package/dist/fancy-ui/_internals/motion/stagger.test.js +58 -0
  47. package/dist/fancy-ui/_internals/motion/tokens.d.ts +97 -0
  48. package/dist/fancy-ui/_internals/motion/tokens.js +83 -0
  49. package/dist/fancy-ui/_internals/motion/tokens.test.d.ts +1 -0
  50. package/dist/fancy-ui/_internals/motion/tokens.test.js +28 -0
  51. package/dist/fancy-ui/_internals/motion/transitions.d.ts +52 -0
  52. package/dist/fancy-ui/_internals/motion/transitions.js +91 -0
  53. package/dist/fancy-ui/_internals/motion/transitions.test.d.ts +1 -0
  54. package/dist/fancy-ui/_internals/motion/transitions.test.js +143 -0
  55. package/dist/fancy-ui/_internals/motion/types.d.ts +17 -0
  56. package/dist/fancy-ui/_internals/motion/types.js +15 -0
  57. package/dist/fancy-ui/_internals/motion/types.test.d.ts +1 -0
  58. package/dist/fancy-ui/_internals/motion/types.test.js +19 -0
  59. package/dist/fancy-ui/_internals/scroll-lock.d.ts +21 -0
  60. package/dist/fancy-ui/_internals/scroll-lock.js +20 -0
  61. package/dist/fancy-ui/_internals/scroll-lock.test.js +82 -1
  62. package/dist/fancy-ui/agent-plan/AgentPlan.svelte +16 -1
  63. package/dist/fancy-ui/agent-plan/AgentPlan.svelte.d.ts +5 -0
  64. package/dist/fancy-ui/agent-plan/AgentPlan.test.js +55 -1
  65. package/dist/fancy-ui/agent-plan/README.md +11 -0
  66. package/dist/fancy-ui/alert-dialog/AlertDialog.svelte +20 -0
  67. package/dist/fancy-ui/alert-dialog/AlertDialog.svelte.d.ts +5 -0
  68. package/dist/fancy-ui/alert-dialog/AlertDialog.test.js +145 -2
  69. package/dist/fancy-ui/alert-dialog/README.md +45 -14
  70. package/dist/fancy-ui/animated-beam/AnimatedBeam.svelte +4 -0
  71. package/dist/fancy-ui/animated-beam/AnimatedBeam.test.js +16 -0
  72. package/dist/fancy-ui/animated-beam/README.md +1 -0
  73. package/dist/fancy-ui/animated-testimonials/AnimatedTestimonials.svelte +13 -3
  74. package/dist/fancy-ui/animated-testimonials/AnimatedTestimonials.svelte.d.ts +5 -0
  75. package/dist/fancy-ui/animated-testimonials/AnimatedTestimonials.test.js +70 -0
  76. package/dist/fancy-ui/animated-testimonials/README.md +17 -6
  77. package/dist/fancy-ui/animated-tooltip/AnimatedTooltip.svelte +21 -1
  78. package/dist/fancy-ui/animated-tooltip/AnimatedTooltip.test.js +25 -1
  79. package/dist/fancy-ui/animated-tooltip/README.md +1 -0
  80. package/dist/fancy-ui/apple-card-carousel/AppleCard.svelte +20 -0
  81. package/dist/fancy-ui/apple-card-carousel/AppleCard.svelte.d.ts +5 -0
  82. package/dist/fancy-ui/apple-card-carousel/AppleCardCarousel.svelte +7 -1
  83. package/dist/fancy-ui/apple-card-carousel/AppleCardCarousel.svelte.d.ts +5 -0
  84. package/dist/fancy-ui/apple-card-carousel/AppleCardCarousel.test.js +111 -1
  85. package/dist/fancy-ui/apple-card-carousel/README.md +16 -5
  86. package/dist/fancy-ui/approval-card/ApprovalCard.svelte +10 -0
  87. package/dist/fancy-ui/approval-card/ApprovalCard.svelte.d.ts +5 -0
  88. package/dist/fancy-ui/approval-card/ApprovalCard.test.js +51 -1
  89. package/dist/fancy-ui/approval-card/README.md +30 -14
  90. package/dist/fancy-ui/artifact-card/ArtifactCard.svelte +19 -1
  91. package/dist/fancy-ui/artifact-card/ArtifactCard.svelte.d.ts +5 -0
  92. package/dist/fancy-ui/artifact-card/ArtifactCard.test.js +80 -1
  93. package/dist/fancy-ui/artifact-card/README.md +24 -13
  94. package/dist/fancy-ui/autocomplete/Autocomplete.svelte +16 -0
  95. package/dist/fancy-ui/autocomplete/Autocomplete.svelte.d.ts +5 -0
  96. package/dist/fancy-ui/autocomplete/Autocomplete.test.js +245 -1
  97. package/dist/fancy-ui/autocomplete/AutocompletePanel.svelte +60 -3
  98. package/dist/fancy-ui/autocomplete/AutocompletePanel.svelte.d.ts +2 -17
  99. package/dist/fancy-ui/autocomplete/README.md +74 -17
  100. package/dist/fancy-ui/autocomplete/types.d.ts +8 -0
  101. package/dist/fancy-ui/breadcrumb/Breadcrumb.svelte +16 -0
  102. package/dist/fancy-ui/breadcrumb/Breadcrumb.svelte.d.ts +6 -0
  103. package/dist/fancy-ui/breadcrumb/Breadcrumb.test.js +43 -2
  104. package/dist/fancy-ui/breadcrumb/README.md +11 -0
  105. package/dist/fancy-ui/button/Button.svelte +174 -9
  106. package/dist/fancy-ui/button/Button.test.js +117 -3
  107. package/dist/fancy-ui/button/ButtonLeadHarness.test.svelte +32 -0
  108. package/dist/fancy-ui/button/ButtonLeadHarness.test.svelte.d.ts +3 -0
  109. package/dist/fancy-ui/button/README.md +13 -2
  110. package/dist/fancy-ui/chat-error/ChatError.svelte +19 -1
  111. package/dist/fancy-ui/chat-error/ChatError.svelte.d.ts +6 -0
  112. package/dist/fancy-ui/chat-error/ChatError.test.js +40 -0
  113. package/dist/fancy-ui/chat-error/README.md +11 -0
  114. package/dist/fancy-ui/chat-message/ChatMessage.svelte +13 -0
  115. package/dist/fancy-ui/chat-message/ChatMessage.svelte.d.ts +9 -0
  116. package/dist/fancy-ui/chat-message/ChatMessageAction.svelte +10 -0
  117. package/dist/fancy-ui/chat-message/ChatMessageBranches.svelte +14 -3
  118. package/dist/fancy-ui/chat-message/ChatMessageHarness.test.svelte +3 -1
  119. package/dist/fancy-ui/chat-message/ChatMessageHarness.test.svelte.d.ts +1 -0
  120. package/dist/fancy-ui/chat-message/ChatMessageParts.test.js +68 -0
  121. package/dist/fancy-ui/chat-message/README.md +25 -0
  122. package/dist/fancy-ui/chat-message/types.d.ts +7 -0
  123. package/dist/fancy-ui/chat-panel/ChatPanel.svelte +9 -0
  124. package/dist/fancy-ui/chat-panel/ChatPanel.svelte.d.ts +6 -0
  125. package/dist/fancy-ui/chat-panel/ChatPanel.test.js +46 -0
  126. package/dist/fancy-ui/chat-panel/README.md +15 -0
  127. package/dist/fancy-ui/checkbox/Checkbox.svelte +139 -42
  128. package/dist/fancy-ui/checkbox/Checkbox.test.js +108 -0
  129. package/dist/fancy-ui/checkbox/README.md +70 -11
  130. package/dist/fancy-ui/code-diff/CodeDiff.svelte +23 -2
  131. package/dist/fancy-ui/code-diff/CodeDiff.svelte.d.ts +5 -0
  132. package/dist/fancy-ui/code-diff/CodeDiff.test.js +61 -1
  133. package/dist/fancy-ui/code-diff/README.md +21 -10
  134. package/dist/fancy-ui/combobox/Combobox.svelte +16 -0
  135. package/dist/fancy-ui/combobox/Combobox.svelte.d.ts +5 -0
  136. package/dist/fancy-ui/combobox/Combobox.test.js +210 -0
  137. package/dist/fancy-ui/combobox/ComboboxPanel.svelte +57 -3
  138. package/dist/fancy-ui/combobox/ComboboxPanel.svelte.d.ts +2 -17
  139. package/dist/fancy-ui/combobox/README.md +52 -0
  140. package/dist/fancy-ui/combobox/types.d.ts +8 -0
  141. package/dist/fancy-ui/command-menu/CommandMenu.svelte +122 -47
  142. package/dist/fancy-ui/command-menu/CommandMenu.svelte.d.ts +5 -0
  143. package/dist/fancy-ui/command-menu/CommandMenu.test.js +242 -4
  144. package/dist/fancy-ui/command-menu/README.md +43 -2
  145. package/dist/fancy-ui/composer/Composer.svelte +14 -0
  146. package/dist/fancy-ui/composer/Composer.svelte.d.ts +5 -0
  147. package/dist/fancy-ui/composer/Composer.test.js +107 -1
  148. package/dist/fancy-ui/composer/ComposerAttachment.svelte +7 -0
  149. package/dist/fancy-ui/composer/ComposerAttachments.test.js +49 -1
  150. package/dist/fancy-ui/composer/ComposerCommandMenu.svelte +5 -0
  151. package/dist/fancy-ui/composer/ComposerCommandMenu.test.js +57 -2
  152. package/dist/fancy-ui/composer/ComposerHarness.test.svelte +3 -0
  153. package/dist/fancy-ui/composer/ComposerHarness.test.svelte.d.ts +1 -0
  154. package/dist/fancy-ui/composer/ComposerModelPicker.svelte +14 -2
  155. package/dist/fancy-ui/composer/ComposerToolbar.test.js +64 -2
  156. package/dist/fancy-ui/composer/README.md +31 -0
  157. package/dist/fancy-ui/composer/types.d.ts +6 -0
  158. package/dist/fancy-ui/confetti/Confetti.test.js +55 -11
  159. package/dist/fancy-ui/confetti/ConfettiButton.svelte +8 -1
  160. package/dist/fancy-ui/confetti/ConfettiButton.svelte.d.ts +5 -0
  161. package/dist/fancy-ui/confetti/README.md +22 -9
  162. package/dist/fancy-ui/context-menu/ContextMenu.svelte +27 -3
  163. package/dist/fancy-ui/context-menu/ContextMenu.svelte.d.ts +5 -0
  164. package/dist/fancy-ui/context-menu/ContextMenu.test.js +324 -0
  165. package/dist/fancy-ui/context-menu/ContextMenuContent.svelte +77 -22
  166. package/dist/fancy-ui/context-menu/ContextMenuHarness.test.svelte +3 -1
  167. package/dist/fancy-ui/context-menu/ContextMenuHarness.test.svelte.d.ts +1 -0
  168. package/dist/fancy-ui/context-menu/README.md +86 -2
  169. package/dist/fancy-ui/context-menu/types.d.ts +5 -3
  170. package/dist/fancy-ui/context-ring/ContextRing.svelte +24 -3
  171. package/dist/fancy-ui/context-ring/ContextRing.svelte.d.ts +5 -0
  172. package/dist/fancy-ui/context-ring/ContextRing.test.js +75 -1
  173. package/dist/fancy-ui/context-ring/README.md +11 -0
  174. package/dist/fancy-ui/copy-button/CopyButton.svelte +171 -52
  175. package/dist/fancy-ui/copy-button/CopyButton.svelte.d.ts +6 -4
  176. package/dist/fancy-ui/copy-button/CopyButton.test.js +237 -16
  177. package/dist/fancy-ui/copy-button/README.md +111 -44
  178. package/dist/fancy-ui/date-picker/DatePicker.svelte +74 -22
  179. package/dist/fancy-ui/date-picker/DatePicker.svelte.d.ts +5 -0
  180. package/dist/fancy-ui/date-picker/DatePicker.test.js +230 -0
  181. package/dist/fancy-ui/date-picker/README.md +50 -0
  182. package/dist/fancy-ui/dialog/Dialog.svelte +16 -0
  183. package/dist/fancy-ui/dialog/Dialog.svelte.d.ts +5 -0
  184. package/dist/fancy-ui/dialog/Dialog.test.js +234 -3
  185. package/dist/fancy-ui/dialog/DialogSurface.svelte +101 -48
  186. package/dist/fancy-ui/dialog/README.md +43 -16
  187. package/dist/fancy-ui/dim-siblings/DimSiblings.svelte +184 -0
  188. package/dist/fancy-ui/dim-siblings/DimSiblings.svelte.d.ts +35 -0
  189. package/dist/fancy-ui/dim-siblings/DimSiblings.test.d.ts +1 -0
  190. package/dist/fancy-ui/dim-siblings/DimSiblings.test.js +127 -0
  191. package/dist/fancy-ui/dim-siblings/DimSiblingsHarness.test.svelte +18 -0
  192. package/dist/fancy-ui/dim-siblings/DimSiblingsHarness.test.svelte.d.ts +18 -0
  193. package/dist/fancy-ui/dim-siblings/README.md +77 -0
  194. package/dist/fancy-ui/dim-siblings/index.d.ts +3 -0
  195. package/dist/fancy-ui/dim-siblings/index.js +2 -0
  196. package/dist/fancy-ui/displacement-text/DisplacementText.svelte +6 -1
  197. package/dist/fancy-ui/displacement-text/DisplacementText.test.js +5 -1
  198. package/dist/fancy-ui/displacement-text/README.md +1 -0
  199. package/dist/fancy-ui/dock/Dock.svelte +44 -4
  200. package/dist/fancy-ui/dock/Dock.test.js +133 -2
  201. package/dist/fancy-ui/dock/DockHarness.test.svelte +36 -0
  202. package/dist/fancy-ui/dock/DockHarness.test.svelte.d.ts +8 -0
  203. package/dist/fancy-ui/dock/DockIcon.svelte +6 -0
  204. package/dist/fancy-ui/dock/README.md +49 -22
  205. package/dist/fancy-ui/dock/types.d.ts +8 -0
  206. package/dist/fancy-ui/drawer/Drawer.svelte +176 -50
  207. package/dist/fancy-ui/drawer/Drawer.svelte.d.ts +12 -0
  208. package/dist/fancy-ui/drawer/Drawer.test.js +228 -10
  209. package/dist/fancy-ui/drawer/DrawerHarness.test.svelte +6 -2
  210. package/dist/fancy-ui/drawer/DrawerHarness.test.svelte.d.ts +1 -0
  211. package/dist/fancy-ui/drawer/README.md +70 -26
  212. package/dist/fancy-ui/dropdown-menu/DropdownMenu.test.js +295 -8
  213. package/dist/fancy-ui/dropdown-menu/DropdownMenuContent.svelte +67 -21
  214. package/dist/fancy-ui/dropdown-menu/DropdownMenuSub.svelte +14 -3
  215. package/dist/fancy-ui/dropdown-menu/DropdownMenuSubContent.svelte +68 -20
  216. package/dist/fancy-ui/dropdown-menu/DropdownMenuSubTrigger.svelte +1 -0
  217. package/dist/fancy-ui/dropdown-menu/README.md +80 -5
  218. package/dist/fancy-ui/dropdown-menu/types.d.ts +26 -5
  219. package/dist/fancy-ui/editorial-engine/EditorialEngine.svelte +37 -15
  220. package/dist/fancy-ui/editorial-engine/EditorialEngine.test.js +34 -2
  221. package/dist/fancy-ui/editorial-engine/README.md +9 -0
  222. package/dist/fancy-ui/file-upload/FileUpload.svelte +137 -15
  223. package/dist/fancy-ui/file-upload/FileUpload.svelte.d.ts +5 -0
  224. package/dist/fancy-ui/file-upload/FileUpload.test.js +302 -1
  225. package/dist/fancy-ui/file-upload/README.md +69 -5
  226. package/dist/fancy-ui/fireworks-hdr/FireworksHdr.svelte +12 -2
  227. package/dist/fancy-ui/fireworks-hdr/FireworksHdr.test.js +70 -0
  228. package/dist/fancy-ui/fireworks-hdr/README.md +4 -2
  229. package/dist/fancy-ui/fluid-cursor/FluidCursor.svelte +97 -11
  230. package/dist/fancy-ui/fluid-cursor/README.md +3 -1
  231. package/dist/fancy-ui/fluid-cursor/fluid-shared.d.ts +18 -0
  232. package/dist/fancy-ui/fluid-cursor/fluid-shared.js +22 -0
  233. package/dist/fancy-ui/fluid-cursor/fluid-shared.test.js +17 -1
  234. package/dist/fancy-ui/fluid-cursor/webgpu-engine.d.ts +6 -0
  235. package/dist/fancy-ui/fluid-cursor/webgpu-engine.js +32 -9
  236. package/dist/fancy-ui/form-field/FormField.svelte +38 -2
  237. package/dist/fancy-ui/form-field/FormField.test.js +118 -1
  238. package/dist/fancy-ui/form-field/README.md +26 -0
  239. package/dist/fancy-ui/gradient-button/GradientButton.svelte +14 -0
  240. package/dist/fancy-ui/gradient-button/GradientButton.svelte.d.ts +5 -0
  241. package/dist/fancy-ui/gradient-button/GradientButton.test.js +40 -2
  242. package/dist/fancy-ui/gradient-button/README.md +10 -0
  243. package/dist/fancy-ui/hover-card/HoverCard.svelte +76 -29
  244. package/dist/fancy-ui/hover-card/HoverCard.test.js +227 -8
  245. package/dist/fancy-ui/hover-card/README.md +47 -1
  246. package/dist/fancy-ui/icon-button/IconButton.svelte +7 -0
  247. package/dist/fancy-ui/icon-button/IconButton.svelte.d.ts +5 -0
  248. package/dist/fancy-ui/icon-button/IconButton.test.js +40 -1
  249. package/dist/fancy-ui/icon-button/README.md +13 -0
  250. package/dist/fancy-ui/image-generation/ImageGeneration.svelte +18 -1
  251. package/dist/fancy-ui/image-generation/ImageGeneration.svelte.d.ts +6 -0
  252. package/dist/fancy-ui/image-generation/ImageGeneration.test.js +46 -0
  253. package/dist/fancy-ui/image-generation/README.md +11 -0
  254. package/dist/fancy-ui/index.d.ts +13 -0
  255. package/dist/fancy-ui/index.js +14 -0
  256. package/dist/fancy-ui/interactive-hover-button/InteractiveHoverButton.svelte +26 -3
  257. package/dist/fancy-ui/interactive-hover-button/InteractiveHoverButton.svelte.d.ts +5 -0
  258. package/dist/fancy-ui/interactive-hover-button/InteractiveHoverButton.test.js +69 -2
  259. package/dist/fancy-ui/interactive-hover-button/README.md +30 -5
  260. package/dist/fancy-ui/line-hover-link/LineHoverLink.svelte +181 -51
  261. package/dist/fancy-ui/line-hover-link/LineHoverLink.svelte.d.ts +5 -0
  262. package/dist/fancy-ui/line-hover-link/LineHoverLink.test.js +69 -2
  263. package/dist/fancy-ui/line-hover-link/README.md +42 -8
  264. package/dist/fancy-ui/line-reveal/LineReveal.svelte +10 -6
  265. package/dist/fancy-ui/line-reveal/LineReveal.test.js +20 -16
  266. package/dist/fancy-ui/link/Link.svelte +54 -1
  267. package/dist/fancy-ui/link/Link.svelte.d.ts +5 -0
  268. package/dist/fancy-ui/link/Link.test.js +67 -1
  269. package/dist/fancy-ui/link/README.md +35 -0
  270. package/dist/fancy-ui/magnetic/Magnetic.svelte +337 -0
  271. package/dist/fancy-ui/magnetic/Magnetic.svelte.d.ts +40 -0
  272. package/dist/fancy-ui/magnetic/Magnetic.test.d.ts +1 -0
  273. package/dist/fancy-ui/magnetic/Magnetic.test.js +354 -0
  274. package/dist/fancy-ui/magnetic/README.md +175 -0
  275. package/dist/fancy-ui/magnetic/index.d.ts +2 -0
  276. package/dist/fancy-ui/magnetic/index.js +2 -0
  277. package/dist/fancy-ui/mosaic-glow/MosaicGlow.ssr.test.d.ts +1 -0
  278. package/dist/fancy-ui/mosaic-glow/MosaicGlow.ssr.test.js +22 -0
  279. package/dist/fancy-ui/mosaic-glow/MosaicGlow.svelte +528 -0
  280. package/dist/fancy-ui/mosaic-glow/MosaicGlow.svelte.d.ts +53 -0
  281. package/dist/fancy-ui/mosaic-glow/MosaicGlow.test.d.ts +1 -0
  282. package/dist/fancy-ui/mosaic-glow/MosaicGlow.test.js +319 -0
  283. package/dist/fancy-ui/mosaic-glow/README.md +60 -0
  284. package/dist/fancy-ui/mosaic-glow/index.d.ts +2 -0
  285. package/dist/fancy-ui/mosaic-glow/index.js +2 -0
  286. package/dist/fancy-ui/mosaic-glow/mosaic-glow-core.d.ts +87 -0
  287. package/dist/fancy-ui/mosaic-glow/mosaic-glow-core.js +221 -0
  288. package/dist/fancy-ui/mosaic-glow/mosaic-glow-core.test.d.ts +1 -0
  289. package/dist/fancy-ui/mosaic-glow/mosaic-glow-core.test.js +201 -0
  290. package/dist/fancy-ui/navbar/Navbar.test.js +76 -1
  291. package/dist/fancy-ui/navbar/NavbarLink.svelte +55 -1
  292. package/dist/fancy-ui/navbar/NavbarLink.svelte.d.ts +5 -0
  293. package/dist/fancy-ui/navbar/README.md +36 -0
  294. package/dist/fancy-ui/navigation-menu/NavigationMenu.test.js +151 -12
  295. package/dist/fancy-ui/navigation-menu/NavigationMenuContent.svelte +74 -26
  296. package/dist/fancy-ui/navigation-menu/README.md +58 -0
  297. package/dist/fancy-ui/number-input/NumberInput.svelte +110 -3
  298. package/dist/fancy-ui/number-input/NumberInput.svelte.d.ts +5 -0
  299. package/dist/fancy-ui/number-input/NumberInput.test.js +234 -0
  300. package/dist/fancy-ui/number-input/README.md +65 -0
  301. package/dist/fancy-ui/number-ticker/NumberTicker.svelte +18 -3
  302. package/dist/fancy-ui/number-ticker/NumberTicker.test.js +94 -0
  303. package/dist/fancy-ui/pagination/Pagination.svelte +63 -1
  304. package/dist/fancy-ui/pagination/Pagination.svelte.d.ts +5 -0
  305. package/dist/fancy-ui/pagination/Pagination.test.js +90 -2
  306. package/dist/fancy-ui/pagination/PaginationHarness.test.svelte +3 -0
  307. package/dist/fancy-ui/pagination/PaginationHarness.test.svelte.d.ts +1 -0
  308. package/dist/fancy-ui/pagination/README.md +38 -0
  309. package/dist/fancy-ui/password-input/PasswordInput.svelte +109 -9
  310. package/dist/fancy-ui/password-input/PasswordInput.svelte.d.ts +5 -0
  311. package/dist/fancy-ui/password-input/PasswordInput.test.js +187 -0
  312. package/dist/fancy-ui/password-input/README.md +52 -0
  313. package/dist/fancy-ui/popover/Popover.svelte +17 -0
  314. package/dist/fancy-ui/popover/Popover.svelte.d.ts +5 -0
  315. package/dist/fancy-ui/popover/Popover.test.js +361 -2
  316. package/dist/fancy-ui/popover/PopoverContent.svelte +86 -22
  317. package/dist/fancy-ui/popover/README.md +70 -12
  318. package/dist/fancy-ui/popover/types.d.ts +11 -0
  319. package/dist/fancy-ui/presence/Presence.svelte +162 -0
  320. package/dist/fancy-ui/presence/Presence.svelte.d.ts +29 -0
  321. package/dist/fancy-ui/presence/Presence.test.d.ts +1 -0
  322. package/dist/fancy-ui/presence/Presence.test.js +274 -0
  323. package/dist/fancy-ui/presence/PresenceHarness.test.svelte +23 -0
  324. package/dist/fancy-ui/presence/PresenceHarness.test.svelte.d.ts +7 -0
  325. package/dist/fancy-ui/presence/README.md +121 -0
  326. package/dist/fancy-ui/presence/index.d.ts +2 -0
  327. package/dist/fancy-ui/presence/index.js +1 -0
  328. package/dist/fancy-ui/pressable/Pressable.svelte +217 -0
  329. package/dist/fancy-ui/pressable/Pressable.svelte.d.ts +32 -0
  330. package/dist/fancy-ui/pressable/Pressable.test.d.ts +1 -0
  331. package/dist/fancy-ui/pressable/Pressable.test.js +285 -0
  332. package/dist/fancy-ui/pressable/README.md +80 -0
  333. package/dist/fancy-ui/pressable/index.d.ts +3 -0
  334. package/dist/fancy-ui/pressable/index.js +2 -0
  335. package/dist/fancy-ui/prompt-suggestions/PromptSuggestions.svelte +14 -1
  336. package/dist/fancy-ui/prompt-suggestions/PromptSuggestions.svelte.d.ts +5 -0
  337. package/dist/fancy-ui/prompt-suggestions/PromptSuggestions.test.js +41 -1
  338. package/dist/fancy-ui/prompt-suggestions/README.md +11 -0
  339. package/dist/fancy-ui/pulse-beam/PulseBeam.ssr.test.d.ts +1 -0
  340. package/dist/fancy-ui/pulse-beam/PulseBeam.ssr.test.js +15 -0
  341. package/dist/fancy-ui/pulse-beam/PulseBeam.svelte +373 -0
  342. package/dist/fancy-ui/pulse-beam/PulseBeam.svelte.d.ts +50 -0
  343. package/dist/fancy-ui/pulse-beam/PulseBeam.test.d.ts +1 -0
  344. package/dist/fancy-ui/pulse-beam/PulseBeam.test.js +254 -0
  345. package/dist/fancy-ui/pulse-beam/README.md +72 -0
  346. package/dist/fancy-ui/pulse-beam/index.d.ts +2 -0
  347. package/dist/fancy-ui/pulse-beam/index.js +2 -0
  348. package/dist/fancy-ui/pulse-beam/pulse-beam-data.d.ts +81 -0
  349. package/dist/fancy-ui/pulse-beam/pulse-beam-data.js +331 -0
  350. package/dist/fancy-ui/pulse-beam/pulse-beam-data.test.d.ts +1 -0
  351. package/dist/fancy-ui/pulse-beam/pulse-beam-data.test.js +155 -0
  352. package/dist/fancy-ui/pulse-beam/pulse-beam-loop.d.ts +26 -0
  353. package/dist/fancy-ui/pulse-beam/pulse-beam-loop.js +84 -0
  354. package/dist/fancy-ui/radio-group/README.md +27 -1
  355. package/dist/fancy-ui/radio-group/RadioGroup.test.js +43 -0
  356. package/dist/fancy-ui/radio-group/RadioGroupItem.svelte +31 -2
  357. package/dist/fancy-ui/rainbow-button/README.md +23 -9
  358. package/dist/fancy-ui/rainbow-button/RainbowButton.svelte +25 -1
  359. package/dist/fancy-ui/rainbow-button/RainbowButton.svelte.d.ts +5 -0
  360. package/dist/fancy-ui/rainbow-button/RainbowButton.test.js +49 -2
  361. package/dist/fancy-ui/reasoning-panel/README.md +11 -0
  362. package/dist/fancy-ui/reasoning-panel/ReasoningPanel.svelte +13 -1
  363. package/dist/fancy-ui/reasoning-panel/ReasoningPanel.svelte.d.ts +5 -0
  364. package/dist/fancy-ui/reasoning-panel/ReasoningPanel.test.js +47 -1
  365. package/dist/fancy-ui/recommendation-card/README.md +25 -14
  366. package/dist/fancy-ui/recommendation-card/RecommendationCard.svelte +10 -0
  367. package/dist/fancy-ui/recommendation-card/RecommendationCard.svelte.d.ts +5 -0
  368. package/dist/fancy-ui/recommendation-card/RecommendationCard.test.js +39 -1
  369. package/dist/fancy-ui/registry.d.ts +7 -0
  370. package/dist/fancy-ui/registry.js +1278 -99
  371. package/dist/fancy-ui/registry.test.d.ts +1 -0
  372. package/dist/fancy-ui/registry.test.js +32 -0
  373. package/dist/fancy-ui/reveal/README.md +186 -0
  374. package/dist/fancy-ui/reveal/Reveal.svelte +353 -0
  375. package/dist/fancy-ui/reveal/Reveal.svelte.d.ts +41 -0
  376. package/dist/fancy-ui/reveal/Reveal.test.d.ts +1 -0
  377. package/dist/fancy-ui/reveal/Reveal.test.js +421 -0
  378. package/dist/fancy-ui/reveal/RevealHarness.test.svelte +49 -0
  379. package/dist/fancy-ui/reveal/RevealHarness.test.svelte.d.ts +9 -0
  380. package/dist/fancy-ui/reveal/index.d.ts +2 -0
  381. package/dist/fancy-ui/reveal/index.js +1 -0
  382. package/dist/fancy-ui/ripple-button/README.md +17 -6
  383. package/dist/fancy-ui/ripple-button/RippleButton.svelte +10 -1
  384. package/dist/fancy-ui/ripple-button/RippleButton.svelte.d.ts +5 -0
  385. package/dist/fancy-ui/ripple-button/RippleButton.test.js +81 -2
  386. package/dist/fancy-ui/scroll-anchor/README.md +11 -0
  387. package/dist/fancy-ui/scroll-anchor/ScrollAnchor.svelte +9 -0
  388. package/dist/fancy-ui/scroll-anchor/ScrollAnchor.svelte.d.ts +6 -0
  389. package/dist/fancy-ui/scroll-anchor/ScrollAnchor.test.js +39 -0
  390. package/dist/fancy-ui/scroll-progress/README.md +73 -0
  391. package/dist/fancy-ui/scroll-progress/ScrollProgress.svelte +291 -0
  392. package/dist/fancy-ui/scroll-progress/ScrollProgress.svelte.d.ts +38 -0
  393. package/dist/fancy-ui/scroll-progress/ScrollProgress.test.d.ts +1 -0
  394. package/dist/fancy-ui/scroll-progress/ScrollProgress.test.js +275 -0
  395. package/dist/fancy-ui/scroll-progress/index.d.ts +3 -0
  396. package/dist/fancy-ui/scroll-progress/index.js +2 -0
  397. package/dist/fancy-ui/search-input/README.md +44 -0
  398. package/dist/fancy-ui/search-input/SearchInput.svelte +31 -0
  399. package/dist/fancy-ui/search-input/SearchInput.svelte.d.ts +5 -0
  400. package/dist/fancy-ui/search-input/SearchInput.test.js +131 -0
  401. package/dist/fancy-ui/select/README.md +32 -0
  402. package/dist/fancy-ui/select/Select.svelte +6 -0
  403. package/dist/fancy-ui/select/Select.test.js +162 -4
  404. package/dist/fancy-ui/select/SelectPanel.svelte +56 -18
  405. package/dist/fancy-ui/select/types.d.ts +14 -0
  406. package/dist/fancy-ui/sheet/README.md +63 -27
  407. package/dist/fancy-ui/sheet/Sheet.svelte +150 -85
  408. package/dist/fancy-ui/sheet/Sheet.svelte.d.ts +12 -0
  409. package/dist/fancy-ui/sheet/Sheet.test.js +192 -8
  410. package/dist/fancy-ui/sheet/SheetHarness.test.svelte +3 -2
  411. package/dist/fancy-ui/sheet/SheetHarness.test.svelte.d.ts +1 -0
  412. package/dist/fancy-ui/shimmer-button/README.md +10 -0
  413. package/dist/fancy-ui/shimmer-button/ShimmerButton.svelte +14 -0
  414. package/dist/fancy-ui/shimmer-button/ShimmerButton.svelte.d.ts +5 -0
  415. package/dist/fancy-ui/shimmer-button/ShimmerButton.test.js +39 -2
  416. package/dist/fancy-ui/sidebar/README.md +42 -0
  417. package/dist/fancy-ui/sidebar/Sidebar.svelte +14 -1
  418. package/dist/fancy-ui/sidebar/Sidebar.test.js +94 -1
  419. package/dist/fancy-ui/sidebar/SidebarItem.svelte +51 -1
  420. package/dist/fancy-ui/sidebar/SidebarItem.svelte.d.ts +5 -0
  421. package/dist/fancy-ui/skeleton/README.md +166 -0
  422. package/dist/fancy-ui/skeleton/Skeleton.svelte +390 -0
  423. package/dist/fancy-ui/skeleton/Skeleton.svelte.d.ts +38 -0
  424. package/dist/fancy-ui/skeleton/Skeleton.test.d.ts +1 -0
  425. package/dist/fancy-ui/skeleton/Skeleton.test.js +347 -0
  426. package/dist/fancy-ui/skeleton/SkeletonRevealHarness.test.svelte +48 -0
  427. package/dist/fancy-ui/skeleton/SkeletonRevealHarness.test.svelte.d.ts +11 -0
  428. package/dist/fancy-ui/skeleton/index.d.ts +3 -0
  429. package/dist/fancy-ui/skeleton/index.js +2 -0
  430. package/dist/fancy-ui/slider/README.md +19 -0
  431. package/dist/fancy-ui/slider/Slider.svelte +19 -0
  432. package/dist/fancy-ui/slider/Slider.svelte.d.ts +5 -0
  433. package/dist/fancy-ui/slider/Slider.test.js +37 -0
  434. package/dist/fancy-ui/smooth-cursor/SmoothCursor.svelte +2 -1
  435. package/dist/fancy-ui/smooth-cursor/SmoothCursor.test.js +6 -0
  436. package/dist/fancy-ui/sound/README.md +72 -13
  437. package/dist/fancy-ui/sources/README.md +12 -1
  438. package/dist/fancy-ui/sources/Sources.svelte +9 -0
  439. package/dist/fancy-ui/sources/Sources.svelte.d.ts +6 -0
  440. package/dist/fancy-ui/sources/Sources.test.js +34 -0
  441. package/dist/fancy-ui/sources/SourcesHarness.test.svelte +10 -2
  442. package/dist/fancy-ui/sources/SourcesHarness.test.svelte.d.ts +1 -0
  443. package/dist/fancy-ui/sparkles/Sparkles.svelte +6 -3
  444. package/dist/fancy-ui/sparkles/Sparkles.test.js +51 -0
  445. package/dist/fancy-ui/status-morph/README.md +175 -0
  446. package/dist/fancy-ui/status-morph/StatusMorph.svelte +449 -0
  447. package/dist/fancy-ui/status-morph/StatusMorph.svelte.d.ts +45 -0
  448. package/dist/fancy-ui/status-morph/StatusMorph.test.d.ts +1 -0
  449. package/dist/fancy-ui/status-morph/StatusMorph.test.js +243 -0
  450. package/dist/fancy-ui/status-morph/StatusMorphHarness.test.svelte +33 -0
  451. package/dist/fancy-ui/status-morph/StatusMorphHarness.test.svelte.d.ts +7 -0
  452. package/dist/fancy-ui/status-morph/index.d.ts +3 -0
  453. package/dist/fancy-ui/status-morph/index.js +2 -0
  454. package/dist/fancy-ui/stepper/README.md +40 -0
  455. package/dist/fancy-ui/stepper/Step.svelte +26 -0
  456. package/dist/fancy-ui/stepper/Stepper.svelte +9 -0
  457. package/dist/fancy-ui/stepper/Stepper.svelte.d.ts +5 -0
  458. package/dist/fancy-ui/stepper/Stepper.test.js +98 -1
  459. package/dist/fancy-ui/stepper/StepperHarness.test.svelte +11 -1
  460. package/dist/fancy-ui/stepper/StepperHarness.test.svelte.d.ts +1 -0
  461. package/dist/fancy-ui/sticky-scroll/README.md +91 -0
  462. package/dist/fancy-ui/sticky-scroll/StickyScroll.svelte +255 -0
  463. package/dist/fancy-ui/sticky-scroll/StickyScroll.svelte.d.ts +62 -0
  464. package/dist/fancy-ui/sticky-scroll/StickyScroll.test.d.ts +1 -0
  465. package/dist/fancy-ui/sticky-scroll/StickyScroll.test.js +267 -0
  466. package/dist/fancy-ui/sticky-scroll/StickyScrollHarness.test.svelte +73 -0
  467. package/dist/fancy-ui/sticky-scroll/StickyScrollHarness.test.svelte.d.ts +12 -0
  468. package/dist/fancy-ui/sticky-scroll/index.d.ts +3 -0
  469. package/dist/fancy-ui/sticky-scroll/index.js +2 -0
  470. package/dist/fancy-ui/subagent-list/README.md +11 -0
  471. package/dist/fancy-ui/subagent-list/SubagentList.svelte +15 -1
  472. package/dist/fancy-ui/subagent-list/SubagentList.svelte.d.ts +5 -0
  473. package/dist/fancy-ui/subagent-list/SubagentList.test.js +50 -1
  474. package/dist/fancy-ui/switch/README.md +27 -6
  475. package/dist/fancy-ui/switch/Switch.svelte +18 -4
  476. package/dist/fancy-ui/switch/Switch.test.js +41 -0
  477. package/dist/fancy-ui/tabs/README.md +141 -11
  478. package/dist/fancy-ui/tabs/Tabs.svelte +9 -0
  479. package/dist/fancy-ui/tabs/Tabs.svelte.d.ts +5 -0
  480. package/dist/fancy-ui/tabs/Tabs.test.js +407 -2
  481. package/dist/fancy-ui/tabs/TabsContent.svelte +34 -0
  482. package/dist/fancy-ui/tabs/TabsHarness.test.svelte +3 -1
  483. package/dist/fancy-ui/tabs/TabsHarness.test.svelte.d.ts +1 -0
  484. package/dist/fancy-ui/tabs/TabsList.svelte +330 -0
  485. package/dist/fancy-ui/tabs/TabsTrigger.svelte +46 -23
  486. package/dist/fancy-ui/terminal-text/README.md +1 -1
  487. package/dist/fancy-ui/terminal-text/TerminalText.svelte +31 -2
  488. package/dist/fancy-ui/terminal-text/TerminalText.test.js +70 -0
  489. package/dist/fancy-ui/terminal-text/TerminalTextHarness.test.svelte +36 -0
  490. package/dist/fancy-ui/terminal-text/TerminalTextHarness.test.svelte.d.ts +6 -0
  491. package/dist/fancy-ui/text-roll/README.md +152 -0
  492. package/dist/fancy-ui/text-roll/TextRoll.svelte +455 -0
  493. package/dist/fancy-ui/text-roll/TextRoll.svelte.d.ts +53 -0
  494. package/dist/fancy-ui/text-roll/TextRoll.test.d.ts +1 -0
  495. package/dist/fancy-ui/text-roll/TextRoll.test.js +574 -0
  496. package/dist/fancy-ui/text-roll/TextRollHarness.test.svelte +49 -0
  497. package/dist/fancy-ui/text-roll/TextRollHarness.test.svelte.d.ts +7 -0
  498. package/dist/fancy-ui/text-roll/index.d.ts +2 -0
  499. package/dist/fancy-ui/text-roll/index.js +2 -0
  500. package/dist/fancy-ui/text-roll/roll-transitions.d.ts +74 -0
  501. package/dist/fancy-ui/text-roll/roll-transitions.js +66 -0
  502. package/dist/fancy-ui/thread-list/README.md +11 -0
  503. package/dist/fancy-ui/thread-list/ThreadList.svelte +15 -1
  504. package/dist/fancy-ui/thread-list/ThreadList.svelte.d.ts +6 -0
  505. package/dist/fancy-ui/thread-list/ThreadList.test.js +43 -0
  506. package/dist/fancy-ui/thread-list/ThreadListHarness.test.svelte +3 -0
  507. package/dist/fancy-ui/thread-list/ThreadListHarness.test.svelte.d.ts +1 -0
  508. package/dist/fancy-ui/time-picker/README.md +51 -1
  509. package/dist/fancy-ui/time-picker/TimePicker.svelte +47 -10
  510. package/dist/fancy-ui/time-picker/TimePicker.svelte.d.ts +5 -0
  511. package/dist/fancy-ui/time-picker/TimePicker.test.js +254 -1
  512. package/dist/fancy-ui/time-picker/TimePickerPanel.svelte +55 -20
  513. package/dist/fancy-ui/time-picker/types.d.ts +8 -0
  514. package/dist/fancy-ui/toast/README.md +62 -6
  515. package/dist/fancy-ui/toast/Toast.svelte +32 -15
  516. package/dist/fancy-ui/toast/Toast.test.js +243 -4
  517. package/dist/fancy-ui/toast/Toaster.svelte +48 -0
  518. package/dist/fancy-ui/toast/Toaster.svelte.d.ts +6 -0
  519. package/dist/fancy-ui/toggle/README.md +48 -11
  520. package/dist/fancy-ui/toggle/Toggle.svelte +89 -10
  521. package/dist/fancy-ui/toggle/Toggle.svelte.d.ts +5 -0
  522. package/dist/fancy-ui/toggle/Toggle.test.js +78 -1
  523. package/dist/fancy-ui/toggle-group/README.md +50 -12
  524. package/dist/fancy-ui/toggle-group/ToggleGroup.svelte +8 -0
  525. package/dist/fancy-ui/toggle-group/ToggleGroup.svelte.d.ts +5 -0
  526. package/dist/fancy-ui/toggle-group/ToggleGroup.test.js +97 -1
  527. package/dist/fancy-ui/toggle-group/ToggleGroupHarness.test.svelte +3 -1
  528. package/dist/fancy-ui/toggle-group/ToggleGroupHarness.test.svelte.d.ts +1 -0
  529. package/dist/fancy-ui/toggle-group/ToggleGroupItem.svelte +53 -1
  530. package/dist/fancy-ui/tool-call/README.md +21 -10
  531. package/dist/fancy-ui/tool-call/ToolCall.svelte +13 -1
  532. package/dist/fancy-ui/tool-call/ToolCall.svelte.d.ts +5 -0
  533. package/dist/fancy-ui/tool-call/ToolCall.test.js +50 -1
  534. package/dist/fancy-ui/tool-timeline/README.md +11 -0
  535. package/dist/fancy-ui/tool-timeline/ToolTimeline.svelte +15 -1
  536. package/dist/fancy-ui/tool-timeline/ToolTimeline.svelte.d.ts +5 -0
  537. package/dist/fancy-ui/tool-timeline/ToolTimeline.test.js +56 -2
  538. package/dist/fancy-ui/tooltip/README.md +26 -0
  539. package/dist/fancy-ui/tooltip/Tooltip.svelte +48 -20
  540. package/dist/fancy-ui/tooltip/Tooltip.test.js +118 -0
  541. package/dist/fancy-ui/voice-input/README.md +25 -13
  542. package/dist/fancy-ui/voice-input/VoiceInput.svelte +42 -1
  543. package/dist/fancy-ui/voice-input/VoiceInput.svelte.d.ts +5 -0
  544. package/dist/fancy-ui/voice-input/VoiceInput.test.js +99 -1
  545. package/dist/fancy-ui/voice-input/VoiceInputHarness.test.svelte +3 -1
  546. package/dist/fancy-ui/voice-input/VoiceInputHarness.test.svelte.d.ts +1 -0
  547. package/dist/fancy-ui/web-search/README.md +11 -0
  548. package/dist/fancy-ui/web-search/WebSearch.svelte +22 -2
  549. package/dist/fancy-ui/web-search/WebSearch.svelte.d.ts +5 -0
  550. package/dist/fancy-ui/web-search/WebSearch.test.js +60 -1
  551. package/package.json +3 -2
  552. package/dist/fancy-ui/themes.d.ts +0 -38
  553. package/dist/fancy-ui/themes.js +0 -356
@@ -7,6 +7,14 @@
7
7
  // (the default) — see `fallbackFocus` below for what happens when that
8
8
  // element is gone by the time destroy runs.
9
9
  //
10
+ // An overlay that animates its exit does not wait for destroy: `onActivate`
11
+ // hands it a function that runs the same return chain at the dismiss instant,
12
+ // and destroy then stands down. It hands over a second function that re-arms
13
+ // the trap when the surface comes back, because a reopen during the exit
14
+ // reverses the outro instead of remounting and this action is therefore never
15
+ // re-created. See `onActivate` below for why an animated close cannot use the
16
+ // destroy path, and why the eager return needs an undo.
17
+ //
10
18
  // Ordering requirement for callers combining this with `portal`: put
11
19
  // `use:portal` and `use:focusTrap` on the exact same element, with
12
20
  // `use:portal` written first. A child node's `use:` action can run before
@@ -45,7 +53,14 @@ export const focusTrap = (node, opts = {}) => {
45
53
  }
46
54
  let returnFocus = opts.returnFocus ?? true;
47
55
  let fallbackFocus = opts.fallbackFocus;
48
- const previouslyFocused = document.activeElement;
56
+ // Tracked like the other two rather than read off the original `opts`:
57
+ // a caller that retargets the initial focus between form steps updates
58
+ // the action, and `rearm()` below has to honour the CURRENT target, not
59
+ // the one this instance happened to mount with.
60
+ let initialFocus = opts.initialFocus;
61
+ // Not `const`: this is the element the trap displaced, and a surface
62
+ // reopened mid-exit is displacing a different one. `rearm()` recaptures.
63
+ let previouslyFocused = document.activeElement;
49
64
  function focusContainerFallback() {
50
65
  // No focusable descendants (empty/loading dialog): contain focus on the
51
66
  // node itself so it does not leak to the page behind the trap.
@@ -60,6 +75,85 @@ export const focusTrap = (node, opts = {}) => {
60
75
  else
61
76
  focusContainerFallback();
62
77
  }
78
+ // The three-step return chain, extracted so it can be run EAGERLY at the
79
+ // dismiss instant (via `onActivate`'s handle) as well as at destroy. The
80
+ // latch makes it run exactly once whichever path gets there first.
81
+ let returned = false;
82
+ function returnFocus_() {
83
+ // The latch guards as well as records: the handle may be called more
84
+ // than once (a reopen mid-exit, a caller being careful), and destroy()
85
+ // may still follow it. Focus moves exactly once either way.
86
+ if (returned)
87
+ return;
88
+ returned = true;
89
+ // `previouslyFocused` is a raw reference, captured at mount and
90
+ // recaptured by `rearm()` on a reopen —
91
+ // `.focus()` on it is the same silent no-op a detached node always
92
+ // is if whatever it pointed at has since left the document, so it
93
+ // is checked rather than trusted. Three-step chain, each step only
94
+ // reached if the one before it failed:
95
+ // 1. The original element, if it is still connected — the
96
+ // common case, unchanged from before this fallback existed.
97
+ // 2. `fallbackFocus()`, if the caller supplied one and it points
98
+ // at a still-connected element — typically the overlay's own
99
+ // trigger: a real, findable place for focus to land even
100
+ // though it is not literally "back where it was."
101
+ // 3. `document.body` — always connected, so unlike the previous
102
+ // two steps this one cannot fail by being disconnected. It
103
+ // still needs a `tabindex` to be programmatically focusable
104
+ // at all (the same reason `focusContainerFallback` above
105
+ // gives the trap node one) — real browsers implicitly treat
106
+ // `<body>` as tabindex="-1" for this purpose, but that
107
+ // default is not universal across environments, so it is
108
+ // set explicitly rather than assumed. This is a last
109
+ // resort, not a good outcome: it clears focus rather than
110
+ // pretending some unrelated element is where the user was,
111
+ // but it is never nothing — a user's focus should not
112
+ // silently vanish.
113
+ if (previouslyFocused?.isConnected) {
114
+ previouslyFocused.focus();
115
+ return;
116
+ }
117
+ const fallback = fallbackFocus?.();
118
+ if (fallback?.isConnected) {
119
+ fallback.focus();
120
+ return;
121
+ }
122
+ if (!document.body.hasAttribute("tabindex")) {
123
+ document.body.setAttribute("tabindex", "-1");
124
+ }
125
+ document.body.focus();
126
+ }
127
+ // The counterpart to the handle, run when the surface comes BACK — a
128
+ // reopen mid-exit reverses the outro rather than remounting, so this
129
+ // action, and the latch above, survive the aborted close (see
130
+ // `onActivate`). Clearing the latch re-arms both the handle and
131
+ // `destroy()` for the next dismiss; focus is pulled back only when it has
132
+ // left the node, which makes the ordinary first intro a no-op (focus is
133
+ // already where `focusInitial` just put it) and never yanks focus away
134
+ // from a user who has moved it inside the panel themselves.
135
+ function rearm() {
136
+ returned = false;
137
+ const active = document.activeElement;
138
+ if (node.contains(active))
139
+ return;
140
+ // A reopen mid-exit is a NEW opening, and it can come from a different
141
+ // control than the one that opened the surface the first time. Without
142
+ // recapturing, the next dismissal would return focus to the original
143
+ // opener — or fall through to the fallback, if that opener has since
144
+ // been removed. `document.body` is excluded because it is exactly what
145
+ // `activeElement` reports while the exiting panel is still `inert`:
146
+ // adopting it would throw away a perfectly good return target in
147
+ // favour of one that clears focus.
148
+ if (active && active !== document.body && active.isConnected) {
149
+ previouslyFocused = active;
150
+ }
151
+ focusInitial(initialFocus);
152
+ }
153
+ // No `active` gate on the Tab handler, deliberately. Once the exit starts
154
+ // the panel is `inert`, `.focus()` on its descendants is a browser no-op,
155
+ // and focus has already been returned by `returnFocusNow()` — so the trap
156
+ // has nothing left to trap and needs no flag nobody reads.
63
157
  function handleKeydown(event) {
64
158
  if (event.key !== "Tab")
65
159
  return;
@@ -83,53 +177,26 @@ export const focusTrap = (node, opts = {}) => {
83
177
  first.focus();
84
178
  }
85
179
  }
86
- focusInitial(opts.initialFocus);
180
+ focusInitial(initialFocus);
181
+ // Handed over AFTER the initial focus move, so a caller that calls the
182
+ // handle synchronously inside `onActivate` still restores the element the
183
+ // trap displaced rather than racing it.
184
+ opts.onActivate?.(returnFocus_, rearm);
87
185
  node.addEventListener("keydown", handleKeydown);
88
186
  return {
89
187
  update(newOpts = {}) {
90
188
  returnFocus = newOpts.returnFocus ?? true;
91
189
  fallbackFocus = newOpts.fallbackFocus;
190
+ initialFocus = newOpts.initialFocus;
92
191
  },
93
192
  destroy() {
94
193
  node.removeEventListener("keydown", handleKeydown);
95
- if (!returnFocus)
96
- return;
97
- // `previouslyFocused` is a raw reference captured once at mount —
98
- // `.focus()` on it is the same silent no-op a detached node always
99
- // is if whatever it pointed at has since left the document, so it
100
- // is checked rather than trusted. Three-step chain, each step only
101
- // reached if the one before it failed:
102
- // 1. The original element, if it is still connected — the
103
- // common case, unchanged from before this fallback existed.
104
- // 2. `fallbackFocus()`, if the caller supplied one and it points
105
- // at a still-connected element — typically the overlay's own
106
- // trigger: a real, findable place for focus to land even
107
- // though it is not literally "back where it was."
108
- // 3. `document.body` — always connected, so unlike the previous
109
- // two steps this one cannot fail by being disconnected. It
110
- // still needs a `tabindex` to be programmatically focusable
111
- // at all (the same reason `focusContainerFallback` above
112
- // gives the trap node one) — real browsers implicitly treat
113
- // `<body>` as tabindex="-1" for this purpose, but that
114
- // default is not universal across environments, so it is
115
- // set explicitly rather than assumed. This is a last
116
- // resort, not a good outcome: it clears focus rather than
117
- // pretending some unrelated element is where the user was,
118
- // but it is never nothing — a user's focus should not
119
- // silently vanish.
120
- if (previouslyFocused?.isConnected) {
121
- previouslyFocused.focus();
194
+ // `returned` disarms this path once the eager handle has already run
195
+ // it — an animated exit calls the handle at `outrostart` and only
196
+ // gets here when the fade finishes, and focus must move exactly once.
197
+ if (!returnFocus || returned)
122
198
  return;
123
- }
124
- const fallback = fallbackFocus?.();
125
- if (fallback?.isConnected) {
126
- fallback.focus();
127
- return;
128
- }
129
- if (!document.body.hasAttribute("tabindex")) {
130
- document.body.setAttribute("tabindex", "-1");
131
- }
132
- document.body.focus();
199
+ returnFocus_();
133
200
  },
134
201
  };
135
202
  };
@@ -1,4 +1,4 @@
1
- import { afterEach, describe, it, expect } from "vitest";
1
+ import { afterEach, describe, it, expect, vi } from "vitest";
2
2
  import { focusTrap } from "./focus-trap";
3
3
  function pressTab(options = {}) {
4
4
  const event = new KeyboardEvent("keydown", {
@@ -227,3 +227,358 @@ describe("focusTrap — visibility and empty containers", () => {
227
227
  action?.destroy?.();
228
228
  });
229
229
  });
230
+ // `onActivate` is the answer to a close that ANIMATES. An action's
231
+ // `destroy()` is delayed by the exit transition, so a trap that only returns
232
+ // focus there would leave a keyboard user on `<body>` for the whole fade —
233
+ // Svelte sets `inert` on the panel the instant the exit starts, which drops
234
+ // focus out of it. The handle runs the same chain at the dismiss instant.
235
+ describe("focusTrap — the eager return handle", () => {
236
+ let container;
237
+ afterEach(() => {
238
+ container?.remove();
239
+ document.body.innerHTML = "";
240
+ vi.restoreAllMocks();
241
+ });
242
+ function setup(innerHtml) {
243
+ container = document.createElement("div");
244
+ container.innerHTML = innerHtml;
245
+ document.body.appendChild(container);
246
+ return container.querySelector("#trap");
247
+ }
248
+ function withOutsideTrigger() {
249
+ const outside = document.createElement("button");
250
+ outside.id = "outside";
251
+ document.body.appendChild(outside);
252
+ outside.focus();
253
+ return outside;
254
+ }
255
+ it("hands the caller a function exactly once, synchronously, during action creation", () => {
256
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
257
+ const handles = [];
258
+ const trap = focusTrap(trapNode, { onActivate: (r) => handles.push(r) });
259
+ expect(handles).toHaveLength(1);
260
+ expect(typeof handles[0]).toBe("function");
261
+ trap?.destroy?.();
262
+ });
263
+ it("hands it over AFTER the initial focus move, so the handle restores what the trap displaced", () => {
264
+ const outside = withOutsideTrigger();
265
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
266
+ let activeAtHandover = null;
267
+ const trap = focusTrap(trapNode, {
268
+ onActivate: () => (activeAtHandover = document.activeElement),
269
+ });
270
+ expect(activeAtHandover).toBe(trapNode.querySelector("#a"));
271
+ trap?.destroy?.();
272
+ outside.remove();
273
+ });
274
+ it("returns focus immediately when called, long before destroy()", () => {
275
+ const outside = withOutsideTrigger();
276
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
277
+ let returnNow = null;
278
+ const trap = focusTrap(trapNode, { onActivate: (r) => (returnNow = r) });
279
+ expect(document.activeElement?.id).toBe("a");
280
+ returnNow();
281
+ // The node is still mounted and destroy() has not run — this is the
282
+ // window an animated exit lives in.
283
+ expect(trapNode.isConnected).toBe(true);
284
+ expect(document.activeElement).toBe(outside);
285
+ trap?.destroy?.();
286
+ outside.remove();
287
+ });
288
+ it("is idempotent: calling the handle twice moves focus exactly once", () => {
289
+ const outside = withOutsideTrigger();
290
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
291
+ let returnNow = null;
292
+ const trap = focusTrap(trapNode, { onActivate: (r) => (returnNow = r) });
293
+ const focusSpy = vi.spyOn(outside, "focus");
294
+ returnNow();
295
+ returnNow();
296
+ expect(focusSpy).toHaveBeenCalledTimes(1);
297
+ trap?.destroy?.();
298
+ outside.remove();
299
+ });
300
+ it("disarms destroy(): the handle then the unmount still moves focus exactly once", () => {
301
+ const outside = withOutsideTrigger();
302
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
303
+ let returnNow = null;
304
+ const trap = focusTrap(trapNode, { onActivate: (r) => (returnNow = r) });
305
+ const focusSpy = vi.spyOn(outside, "focus");
306
+ returnNow();
307
+ trap?.destroy?.();
308
+ expect(focusSpy).toHaveBeenCalledTimes(1);
309
+ expect(document.activeElement).toBe(outside);
310
+ outside.remove();
311
+ });
312
+ // The owner-frozen answer to a caller that contradicts itself: asking for
313
+ // the handle IS asking for the return, so the handle wins. `returnFocus`
314
+ // governs the unmount path only.
315
+ it("returnFocus: false does not disable the handle — it only disables the unmount path", () => {
316
+ const outside = withOutsideTrigger();
317
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
318
+ let returnNow = null;
319
+ const trap = focusTrap(trapNode, {
320
+ returnFocus: false,
321
+ onActivate: (r) => (returnNow = r),
322
+ });
323
+ expect(document.activeElement?.id).toBe("a");
324
+ returnNow();
325
+ expect(document.activeElement).toBe(outside);
326
+ trap?.destroy?.();
327
+ outside.remove();
328
+ });
329
+ it("returnFocus: false with no handle still returns nothing on destroy, as before", () => {
330
+ const outside = withOutsideTrigger();
331
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
332
+ const trap = focusTrap(trapNode, { returnFocus: false });
333
+ trap?.destroy?.();
334
+ expect(document.activeElement?.id).toBe("a");
335
+ outside.remove();
336
+ });
337
+ it("runs the same three-step chain as destroy(), falling back when the original is gone", () => {
338
+ const outside = withOutsideTrigger();
339
+ const fallback = document.createElement("button");
340
+ fallback.id = "fallback";
341
+ document.body.appendChild(fallback);
342
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
343
+ let returnNow = null;
344
+ const trap = focusTrap(trapNode, {
345
+ fallbackFocus: () => fallback,
346
+ onActivate: (r) => (returnNow = r),
347
+ });
348
+ outside.remove();
349
+ returnNow();
350
+ expect(document.activeElement).toBe(fallback);
351
+ trap?.destroy?.();
352
+ fallback.remove();
353
+ });
354
+ it("omitting onActivate leaves the destroy-time return exactly as it was", () => {
355
+ const outside = withOutsideTrigger();
356
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
357
+ const trap = focusTrap(trapNode, {});
358
+ expect(document.activeElement?.id).toBe("a");
359
+ trap?.destroy?.();
360
+ expect(document.activeElement).toBe(outside);
361
+ outside.remove();
362
+ });
363
+ });
364
+ // A reopen DURING the exit is not a new mount: Svelte reverses the outro and
365
+ // resumes the same branch, so the action is never re-created and neither the
366
+ // initial focus move nor `onActivate` runs again. `rearm` — the second
367
+ // function handed to `onActivate` — is what puts focus back inside the panel
368
+ // and un-spends the eager return, so the NEXT dismiss still returns focus.
369
+ // Without it a reopened `aria-modal` panel sits open with focus on the
370
+ // trigger behind it, and every later close of that instance returns focus
371
+ // nowhere at all.
372
+ describe("focusTrap — re-arming after a reopen mid-exit", () => {
373
+ let container;
374
+ afterEach(() => {
375
+ container?.remove();
376
+ document.body.innerHTML = "";
377
+ vi.restoreAllMocks();
378
+ });
379
+ function setup(innerHtml) {
380
+ container = document.createElement("div");
381
+ container.innerHTML = innerHtml;
382
+ document.body.appendChild(container);
383
+ return container.querySelector("#trap");
384
+ }
385
+ function withOutsideTrigger() {
386
+ const outside = document.createElement("button");
387
+ outside.id = "outside";
388
+ document.body.appendChild(outside);
389
+ outside.focus();
390
+ return outside;
391
+ }
392
+ it("hands over a re-arm function alongside the return handle, at the same moment", () => {
393
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
394
+ const args = [];
395
+ const trap = focusTrap(trapNode, { onActivate: (...rest) => args.push(rest) });
396
+ expect(args).toHaveLength(1);
397
+ expect(args[0]).toHaveLength(2);
398
+ expect(typeof args[0][0]).toBe("function");
399
+ expect(typeof args[0][1]).toBe("function");
400
+ trap?.destroy?.();
401
+ });
402
+ it("puts focus back inside the trap after the eager return moved it out", () => {
403
+ const outside = withOutsideTrigger();
404
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
405
+ let returnNow = null;
406
+ let rearm = null;
407
+ const trap = focusTrap(trapNode, {
408
+ onActivate: (r, again) => {
409
+ returnNow = r;
410
+ rearm = again;
411
+ },
412
+ });
413
+ // Dismiss: the eager return puts focus on the trigger while the panel
414
+ // is still mounted and fading.
415
+ returnNow();
416
+ expect(document.activeElement).toBe(outside);
417
+ // Reopen mid-fade: the same action instance is still mounted.
418
+ rearm();
419
+ expect(trapNode.contains(document.activeElement)).toBe(true);
420
+ expect(document.activeElement?.id).toBe("a");
421
+ trap?.destroy?.();
422
+ outside.remove();
423
+ });
424
+ it("re-arms destroy(): the dismiss after a reopen still returns focus", () => {
425
+ const outside = withOutsideTrigger();
426
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
427
+ let returnNow = null;
428
+ let rearm = null;
429
+ const trap = focusTrap(trapNode, {
430
+ onActivate: (r, again) => {
431
+ returnNow = r;
432
+ rearm = again;
433
+ },
434
+ });
435
+ returnNow();
436
+ rearm();
437
+ trap?.destroy?.();
438
+ expect(document.activeElement).toBe(outside);
439
+ outside.remove();
440
+ });
441
+ it("re-arms the handle itself: the next outrostart returns focus again", () => {
442
+ const outside = withOutsideTrigger();
443
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
444
+ let returnNow = null;
445
+ let rearm = null;
446
+ const trap = focusTrap(trapNode, {
447
+ onActivate: (r, again) => {
448
+ returnNow = r;
449
+ rearm = again;
450
+ },
451
+ });
452
+ const focusSpy = vi.spyOn(outside, "focus");
453
+ returnNow(); // first dismiss
454
+ rearm(); // reopened mid-fade
455
+ returnNow(); // second, genuine dismiss
456
+ expect(focusSpy).toHaveBeenCalledTimes(2);
457
+ expect(document.activeElement).toBe(outside);
458
+ // And it is still idempotent within that second activation.
459
+ returnNow();
460
+ expect(focusSpy).toHaveBeenCalledTimes(2);
461
+ trap?.destroy?.();
462
+ outside.remove();
463
+ });
464
+ it("does not move focus when it is already inside the trap", () => {
465
+ const outside = withOutsideTrigger();
466
+ const trapNode = setup(`<div id="trap"><button id="a">A</button><button id="b">B</button></div>`);
467
+ let rearm = null;
468
+ const trap = focusTrap(trapNode, { onActivate: (_r, again) => (rearm = again) });
469
+ // The very first `introstart` fires with focus already where
470
+ // `focusInitial` just put it, and a user may since have tabbed on.
471
+ const second = trapNode.querySelector("#b");
472
+ second.focus();
473
+ rearm();
474
+ expect(document.activeElement).toBe(second);
475
+ trap?.destroy?.();
476
+ outside.remove();
477
+ });
478
+ it("honours initialFocus when it re-arms, not just the first focusable", () => {
479
+ const outside = withOutsideTrigger();
480
+ const trapNode = setup(`<div id="trap"><button id="a">A</button><button id="b">B</button></div>`);
481
+ const initial = trapNode.querySelector("#b");
482
+ let returnNow = null;
483
+ let rearm = null;
484
+ const trap = focusTrap(trapNode, {
485
+ initialFocus: initial,
486
+ onActivate: (r, again) => {
487
+ returnNow = r;
488
+ rearm = again;
489
+ },
490
+ });
491
+ expect(document.activeElement).toBe(initial);
492
+ returnNow();
493
+ rearm();
494
+ expect(document.activeElement).toBe(initial);
495
+ trap?.destroy?.();
496
+ outside.remove();
497
+ });
498
+ // `update()` used to store `returnFocus` and `fallbackFocus` but drop
499
+ // `initialFocus`, so `rearm()` kept honouring whatever target the action
500
+ // mounted with. A dialog that retargets between form steps would then
501
+ // reopen onto the previous step's field — or onto nothing, if that field
502
+ // had been removed with its step.
503
+ it("re-arms onto the CURRENT initialFocus, not the one it mounted with", () => {
504
+ const outside = withOutsideTrigger();
505
+ const trapNode = setup(`<div id="trap"><button id="a">A</button><button id="b">B</button></div>`);
506
+ const a = trapNode.querySelector("#a");
507
+ const b = trapNode.querySelector("#b");
508
+ let returnNow = null;
509
+ let rearm = null;
510
+ const trap = focusTrap(trapNode, {
511
+ initialFocus: a,
512
+ onActivate: (r, again) => {
513
+ returnNow = r;
514
+ rearm = again;
515
+ },
516
+ });
517
+ expect(document.activeElement).toBe(a);
518
+ // The caller retargets while the surface is still mounted.
519
+ trap?.update?.({ initialFocus: b });
520
+ returnNow();
521
+ rearm();
522
+ expect(document.activeElement).toBe(b);
523
+ trap?.destroy?.();
524
+ outside.remove();
525
+ });
526
+ // `previouslyFocused` was captured once at mount, so a surface reopened
527
+ // from a DIFFERENT control returned focus to the first opener on its next
528
+ // dismissal — or fell through to the fallback, if that opener was gone.
529
+ it("returns focus to the control that reopened it, not the original opener", () => {
530
+ const first = withOutsideTrigger();
531
+ const second = document.createElement("button");
532
+ second.id = "second";
533
+ document.body.appendChild(second);
534
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
535
+ let returnNow = null;
536
+ let rearm = null;
537
+ const trap = focusTrap(trapNode, {
538
+ onActivate: (r, again) => {
539
+ returnNow = r;
540
+ rearm = again;
541
+ },
542
+ });
543
+ returnNow();
544
+ expect(document.activeElement).toBe(first);
545
+ // A different control reopens the surface mid-exit.
546
+ second.focus();
547
+ rearm();
548
+ expect(trapNode.contains(document.activeElement)).toBe(true);
549
+ trap?.destroy?.();
550
+ expect(document.activeElement).toBe(second);
551
+ first.remove();
552
+ second.remove();
553
+ });
554
+ // Svelte marks the exiting panel `inert`, which drops focus to <body>.
555
+ // Adopting that as the new return target would trade a real opener for
556
+ // one that clears focus, so the recapture skips it.
557
+ it("does not adopt document.body as the return target when re-arming", () => {
558
+ const outside = withOutsideTrigger();
559
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
560
+ let returnNow = null;
561
+ let rearm = null;
562
+ const trap = focusTrap(trapNode, {
563
+ onActivate: (r, again) => {
564
+ returnNow = r;
565
+ rearm = again;
566
+ },
567
+ });
568
+ returnNow();
569
+ document.body.focus();
570
+ rearm();
571
+ trap?.destroy?.();
572
+ expect(document.activeElement).toBe(outside);
573
+ outside.remove();
574
+ });
575
+ it("leaves a trap that never took the handle untouched", () => {
576
+ const outside = withOutsideTrigger();
577
+ const trapNode = setup(`<div id="trap"><button id="a">A</button></div>`);
578
+ const trap = focusTrap(trapNode, {});
579
+ expect(document.activeElement?.id).toBe("a");
580
+ trap?.destroy?.();
581
+ expect(document.activeElement).toBe(outside);
582
+ outside.remove();
583
+ });
584
+ });
@@ -0,0 +1,42 @@
1
+ <!--
2
+ Test-only rig: mounts a `{#if open}` block whose element carries the
3
+ `anchored` transition and the matching static `style:transform-origin`,
4
+ i.e. the exact call-site shape the twelve floating panels use. A test can
5
+ toggle `open` via rerender() and prove the transition drives the node
6
+ through a real mount/unmount cycle — either through the
7
+ `Element.prototype.animate` stub in `src/test-setup.ts` (non-zero
8
+ duration), or through Svelte's own duration-falsy short-circuit (the
9
+ reduced-motion path: duration 0, synchronous, animate() never called).
10
+
11
+ It uses one bidirectional `transition:` directive so a single toggle
12
+ exercises both directions; the shipping panels use `in:` only, which is a
13
+ call-site decision (an entrance-only panel must never delay its own
14
+ unmount), not a limitation of the transition itself.
15
+
16
+ Not exported from index.ts, and not collected by Vitest directly (the run
17
+ includes `*.test.ts` only) — imported and rendered from anchored.test.ts.
18
+ -->
19
+ <script lang="ts">
20
+ import { anchored, originFor, type AnchoredParams } from "./anchored.js";
21
+ import type { Side, Align } from "../anchor-position.js";
22
+
23
+ interface Props {
24
+ open: boolean;
25
+ side?: Side;
26
+ align?: Align;
27
+ params?: AnchoredParams;
28
+ }
29
+
30
+ let { open, side = "bottom", align = "center", params }: Props = $props();
31
+ </script>
32
+
33
+ {#if open}
34
+ <div
35
+ data-testid="node"
36
+ transition:anchored={params}
37
+ data-side={side}
38
+ style:transform-origin={originFor(side, align)}
39
+ >
40
+ content
41
+ </div>
42
+ {/if}
@@ -0,0 +1,11 @@
1
+ import { type AnchoredParams } from "./anchored.js";
2
+ import type { Side, Align } from "../anchor-position.js";
3
+ interface Props {
4
+ open: boolean;
5
+ side?: Side;
6
+ align?: Align;
7
+ params?: AnchoredParams;
8
+ }
9
+ declare const AnchoredHarness: import("svelte").Component<Props, {}, "">;
10
+ type AnchoredHarness = ReturnType<typeof AnchoredHarness>;
11
+ export default AnchoredHarness;
@@ -0,0 +1,32 @@
1
+ <!--
2
+ Test-only rig: mounts a `{#if open}` block whose element carries a
3
+ `preset()` transition, so a test can toggle `open` via rerender() and
4
+ prove the transition actually drives the node through a real mount/unmount
5
+ cycle — either through the `Element.prototype.animate` stub in
6
+ `src/test-setup.ts` (non-zero duration), or through Svelte's own
7
+ duration-falsy short-circuit (duration: 0, synchronous, animate() never
8
+ called). Not exported from index.ts, and not collected by Vitest directly
9
+ (the run includes `*.test.ts` only) — imported and rendered from
10
+ transitions.test.ts.
11
+ -->
12
+ <script lang="ts">
13
+ import { preset, type PresetParams } from "./transitions.js";
14
+ import type { PresetName } from "./presets.js";
15
+
16
+ interface Props {
17
+ open: boolean;
18
+ name: PresetName;
19
+ params?: PresetParams;
20
+ }
21
+
22
+ let { open, name, params }: Props = $props();
23
+ // $derived.by, not a plain `const`, because `name` is a reactive prop —
24
+ // no test currently changes it mid-lifetime, but a bare
25
+ // `const fn = preset(name)` would silently freeze on whatever `name` was
26
+ // at first render if one ever did.
27
+ const fn = $derived.by(() => preset(name));
28
+ </script>
29
+
30
+ {#if open}
31
+ <div data-testid="node" transition:fn={params}>content</div>
32
+ {/if}
@@ -0,0 +1,10 @@
1
+ import { type PresetParams } from "./transitions.js";
2
+ import type { PresetName } from "./presets.js";
3
+ interface Props {
4
+ open: boolean;
5
+ name: PresetName;
6
+ params?: PresetParams;
7
+ }
8
+ declare const TransitionsHarness: import("svelte").Component<Props, {}, "">;
9
+ type TransitionsHarness = ReturnType<typeof TransitionsHarness>;
10
+ export default TransitionsHarness;