@adobe/spectrum-wc-core 0.0.0-snapshot.20260922095923

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 (335) hide show
  1. package/README.md +39 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.124.0/helpers/decorate.js +9 -0
  3. package/dist/components/accordion/Accordion.base.d.ts +59 -0
  4. package/dist/components/accordion/Accordion.base.js +69 -0
  5. package/dist/components/accordion/Accordion.base.js.map +1 -0
  6. package/dist/components/accordion/Accordion.types.d.ts +22 -0
  7. package/dist/components/accordion/Accordion.types.js +21 -0
  8. package/dist/components/accordion/Accordion.types.js.map +1 -0
  9. package/dist/components/accordion/AccordionItem.base.d.ts +96 -0
  10. package/dist/components/accordion/AccordionItem.base.js +93 -0
  11. package/dist/components/accordion/AccordionItem.base.js.map +1 -0
  12. package/dist/components/accordion/index.d.ts +14 -0
  13. package/dist/components/accordion/index.js +4 -0
  14. package/dist/components/action-button/ActionButton.types.d.ts +15 -0
  15. package/dist/components/action-button/ActionButton.types.js +12 -0
  16. package/dist/components/action-button/ActionButton.types.js.map +1 -0
  17. package/dist/components/action-button/index.d.ts +12 -0
  18. package/dist/components/action-button/index.js +2 -0
  19. package/dist/components/action-group/ActionGroup.base.d.ts +108 -0
  20. package/dist/components/action-group/ActionGroup.base.js +53 -0
  21. package/dist/components/action-group/ActionGroup.base.js.map +1 -0
  22. package/dist/components/action-group/ActionGroup.types.d.ts +17 -0
  23. package/dist/components/action-group/ActionGroup.types.js +12 -0
  24. package/dist/components/action-group/ActionGroup.types.js.map +1 -0
  25. package/dist/components/action-group/index.d.ts +13 -0
  26. package/dist/components/action-group/index.js +3 -0
  27. package/dist/components/alert-banner/AlertBanner.base.d.ts +36 -0
  28. package/dist/components/alert-banner/AlertBanner.base.js +57 -0
  29. package/dist/components/alert-banner/AlertBanner.base.js.map +1 -0
  30. package/dist/components/alert-banner/AlertBanner.types.d.ts +13 -0
  31. package/dist/components/alert-banner/AlertBanner.types.js +10 -0
  32. package/dist/components/alert-banner/AlertBanner.types.js.map +1 -0
  33. package/dist/components/alert-banner/index.d.ts +13 -0
  34. package/dist/components/alert-banner/index.js +3 -0
  35. package/dist/components/asset/Asset.base.d.ts +101 -0
  36. package/dist/components/asset/Asset.base.js +130 -0
  37. package/dist/components/asset/Asset.base.js.map +1 -0
  38. package/dist/components/asset/Asset.types.d.ts +31 -0
  39. package/dist/components/asset/Asset.types.js +14 -0
  40. package/dist/components/asset/Asset.types.js.map +1 -0
  41. package/dist/components/asset/index.d.ts +13 -0
  42. package/dist/components/asset/index.js +3 -0
  43. package/dist/components/avatar/Avatar.base.d.ts +53 -0
  44. package/dist/components/avatar/Avatar.base.js +52 -0
  45. package/dist/components/avatar/Avatar.base.js.map +1 -0
  46. package/dist/components/avatar/Avatar.types.d.ts +19 -0
  47. package/dist/components/avatar/Avatar.types.js +24 -0
  48. package/dist/components/avatar/Avatar.types.js.map +1 -0
  49. package/dist/components/avatar/index.d.ts +13 -0
  50. package/dist/components/avatar/index.js +3 -0
  51. package/dist/components/badge/Badge.base.d.ts +114 -0
  52. package/dist/components/badge/Badge.base.js +49 -0
  53. package/dist/components/badge/Badge.base.js.map +1 -0
  54. package/dist/components/badge/Badge.types.d.ts +21 -0
  55. package/dist/components/badge/Badge.types.js +43 -0
  56. package/dist/components/badge/Badge.types.js.map +1 -0
  57. package/dist/components/badge/index.d.ts +13 -0
  58. package/dist/components/badge/index.js +3 -0
  59. package/dist/components/button/Button.base.d.ts +78 -0
  60. package/dist/components/button/Button.base.js +51 -0
  61. package/dist/components/button/Button.base.js.map +1 -0
  62. package/dist/components/button/Button.types.d.ts +19 -0
  63. package/dist/components/button/Button.types.js +16 -0
  64. package/dist/components/button/Button.types.js.map +1 -0
  65. package/dist/components/button/index.d.ts +13 -0
  66. package/dist/components/button/index.js +3 -0
  67. package/dist/components/button-group/ButtonGroup.base.d.ts +89 -0
  68. package/dist/components/button-group/ButtonGroup.base.js +60 -0
  69. package/dist/components/button-group/ButtonGroup.base.js.map +1 -0
  70. package/dist/components/button-group/ButtonGroup.types.d.ts +17 -0
  71. package/dist/components/button-group/ButtonGroup.types.js +15 -0
  72. package/dist/components/button-group/ButtonGroup.types.js.map +1 -0
  73. package/dist/components/button-group/index.d.ts +13 -0
  74. package/dist/components/button-group/index.js +3 -0
  75. package/dist/components/card/Card.base.d.ts +172 -0
  76. package/dist/components/card/Card.base.js +123 -0
  77. package/dist/components/card/Card.base.js.map +1 -0
  78. package/dist/components/card/Card.types.d.ts +18 -0
  79. package/dist/components/card/Card.types.js +21 -0
  80. package/dist/components/card/Card.types.js.map +1 -0
  81. package/dist/components/card/index.d.ts +13 -0
  82. package/dist/components/card/index.js +3 -0
  83. package/dist/components/color-handle/ColorHandle.base.d.ts +51 -0
  84. package/dist/components/color-handle/ColorHandle.base.js +39 -0
  85. package/dist/components/color-handle/ColorHandle.base.js.map +1 -0
  86. package/dist/components/color-handle/ColorHandle.types.d.ts +30 -0
  87. package/dist/components/color-handle/color-contrast.d.ts +55 -0
  88. package/dist/components/color-handle/color-contrast.js +49 -0
  89. package/dist/components/color-handle/color-contrast.js.map +1 -0
  90. package/dist/components/color-handle/index.d.ts +14 -0
  91. package/dist/components/color-handle/index.js +3 -0
  92. package/dist/components/color-loupe/ColorLoupe.base.d.ts +41 -0
  93. package/dist/components/color-loupe/ColorLoupe.base.js +21 -0
  94. package/dist/components/color-loupe/ColorLoupe.base.js.map +1 -0
  95. package/dist/components/color-loupe/index.d.ts +12 -0
  96. package/dist/components/color-loupe/index.js +2 -0
  97. package/dist/components/divider/Divider.base.d.ts +43 -0
  98. package/dist/components/divider/Divider.base.js +42 -0
  99. package/dist/components/divider/Divider.base.js.map +1 -0
  100. package/dist/components/divider/Divider.types.d.ts +15 -0
  101. package/dist/components/divider/Divider.types.js +10 -0
  102. package/dist/components/divider/Divider.types.js.map +1 -0
  103. package/dist/components/divider/index.d.ts +13 -0
  104. package/dist/components/divider/index.js +3 -0
  105. package/dist/components/dropzone/Dropzone.base.d.ts +74 -0
  106. package/dist/components/dropzone/Dropzone.base.js +82 -0
  107. package/dist/components/dropzone/Dropzone.base.js.map +1 -0
  108. package/dist/components/dropzone/Dropzone.types.d.ts +43 -0
  109. package/dist/components/dropzone/Dropzone.types.js +15 -0
  110. package/dist/components/dropzone/Dropzone.types.js.map +1 -0
  111. package/dist/components/dropzone/index.d.ts +13 -0
  112. package/dist/components/dropzone/index.js +3 -0
  113. package/dist/components/icon/Icon.base.d.ts +36 -0
  114. package/dist/components/icon/Icon.base.js +28 -0
  115. package/dist/components/icon/Icon.base.js.map +1 -0
  116. package/dist/components/icon/Icon.types.d.ts +13 -0
  117. package/dist/components/icon/Icon.types.js +12 -0
  118. package/dist/components/icon/Icon.types.js.map +1 -0
  119. package/dist/components/icon/index.d.ts +13 -0
  120. package/dist/components/icon/index.js +3 -0
  121. package/dist/components/illustrated-message/IllustratedMessage.base.d.ts +60 -0
  122. package/dist/components/illustrated-message/IllustratedMessage.base.js +59 -0
  123. package/dist/components/illustrated-message/IllustratedMessage.base.js.map +1 -0
  124. package/dist/components/illustrated-message/IllustratedMessage.types.d.ts +15 -0
  125. package/dist/components/illustrated-message/IllustratedMessage.types.js +10 -0
  126. package/dist/components/illustrated-message/IllustratedMessage.types.js.map +1 -0
  127. package/dist/components/illustrated-message/index.d.ts +13 -0
  128. package/dist/components/illustrated-message/index.js +3 -0
  129. package/dist/components/infield-button/InfieldButton.base.d.ts +28 -0
  130. package/dist/components/infield-button/InfieldButton.base.js +22 -0
  131. package/dist/components/infield-button/InfieldButton.base.js.map +1 -0
  132. package/dist/components/infield-button/InfieldButton.types.d.ts +13 -0
  133. package/dist/components/infield-button/InfieldButton.types.js +11 -0
  134. package/dist/components/infield-button/InfieldButton.types.js.map +1 -0
  135. package/dist/components/infield-button/index.d.ts +13 -0
  136. package/dist/components/infield-button/index.js +3 -0
  137. package/dist/components/meter/Meter.base.d.ts +40 -0
  138. package/dist/components/meter/Meter.base.js +32 -0
  139. package/dist/components/meter/Meter.base.js.map +1 -0
  140. package/dist/components/meter/Meter.types.d.ts +13 -0
  141. package/dist/components/meter/Meter.types.js +11 -0
  142. package/dist/components/meter/Meter.types.js.map +1 -0
  143. package/dist/components/meter/index.d.ts +13 -0
  144. package/dist/components/meter/index.js +3 -0
  145. package/dist/components/popover/Popover.base.d.ts +226 -0
  146. package/dist/components/popover/Popover.base.js +287 -0
  147. package/dist/components/popover/Popover.base.js.map +1 -0
  148. package/dist/components/popover/Popover.types.d.ts +39 -0
  149. package/dist/components/popover/Popover.types.js +24 -0
  150. package/dist/components/popover/Popover.types.js.map +1 -0
  151. package/dist/components/popover/index.d.ts +13 -0
  152. package/dist/components/popover/index.js +3 -0
  153. package/dist/components/progress-bar/ProgressBar.base.d.ts +34 -0
  154. package/dist/components/progress-bar/ProgressBar.base.js +21 -0
  155. package/dist/components/progress-bar/ProgressBar.base.js.map +1 -0
  156. package/dist/components/progress-bar/ProgressBar.types.d.ts +12 -0
  157. package/dist/components/progress-bar/index.d.ts +13 -0
  158. package/dist/components/progress-bar/index.js +2 -0
  159. package/dist/components/progress-circle/ProgressCircle.base.d.ts +83 -0
  160. package/dist/components/progress-circle/ProgressCircle.base.js +77 -0
  161. package/dist/components/progress-circle/ProgressCircle.base.js.map +1 -0
  162. package/dist/components/progress-circle/ProgressCircle.types.d.ts +15 -0
  163. package/dist/components/progress-circle/ProgressCircle.types.js +10 -0
  164. package/dist/components/progress-circle/ProgressCircle.types.js.map +1 -0
  165. package/dist/components/progress-circle/index.d.ts +13 -0
  166. package/dist/components/progress-circle/index.js +3 -0
  167. package/dist/components/status-light/StatusLight.base.d.ts +69 -0
  168. package/dist/components/status-light/StatusLight.base.js +32 -0
  169. package/dist/components/status-light/StatusLight.base.js.map +1 -0
  170. package/dist/components/status-light/StatusLight.types.d.ts +19 -0
  171. package/dist/components/status-light/StatusLight.types.js +32 -0
  172. package/dist/components/status-light/StatusLight.types.js.map +1 -0
  173. package/dist/components/status-light/index.d.ts +13 -0
  174. package/dist/components/status-light/index.js +3 -0
  175. package/dist/components/tabs/Tab.base.d.ts +49 -0
  176. package/dist/components/tabs/Tab.base.js +39 -0
  177. package/dist/components/tabs/Tab.base.js.map +1 -0
  178. package/dist/components/tabs/Tab.types.d.ts +17 -0
  179. package/dist/components/tabs/TabPanel.base.d.ts +49 -0
  180. package/dist/components/tabs/TabPanel.base.js +36 -0
  181. package/dist/components/tabs/TabPanel.base.js.map +1 -0
  182. package/dist/components/tabs/TabPanel.types.d.ts +17 -0
  183. package/dist/components/tabs/Tabs.base.d.ts +221 -0
  184. package/dist/components/tabs/Tabs.base.js +213 -0
  185. package/dist/components/tabs/Tabs.base.js.map +1 -0
  186. package/dist/components/tabs/Tabs.types.d.ts +55 -0
  187. package/dist/components/tabs/Tabs.types.js +6 -0
  188. package/dist/components/tabs/Tabs.types.js.map +1 -0
  189. package/dist/components/tabs/index.d.ts +17 -0
  190. package/dist/components/tabs/index.js +5 -0
  191. package/dist/components/tooltip/Tooltip.base.d.ts +159 -0
  192. package/dist/components/tooltip/Tooltip.base.js +198 -0
  193. package/dist/components/tooltip/Tooltip.base.js.map +1 -0
  194. package/dist/components/tooltip/Tooltip.types.d.ts +18 -0
  195. package/dist/components/tooltip/Tooltip.types.js +15 -0
  196. package/dist/components/tooltip/Tooltip.types.js.map +1 -0
  197. package/dist/components/tooltip/index.d.ts +13 -0
  198. package/dist/components/tooltip/index.js +3 -0
  199. package/dist/controllers/color-controller/index.d.ts +12 -0
  200. package/dist/controllers/color-controller/index.js +2 -0
  201. package/dist/controllers/color-controller/src/color-controller.d.ts +226 -0
  202. package/dist/controllers/color-controller/src/color-controller.js +253 -0
  203. package/dist/controllers/color-controller/src/color-controller.js.map +1 -0
  204. package/dist/controllers/drag-and-drop-controller/index.d.ts +12 -0
  205. package/dist/controllers/drag-and-drop-controller/index.js +2 -0
  206. package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.d.ts +68 -0
  207. package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.js +56 -0
  208. package/dist/controllers/drag-and-drop-controller/src/drag-and-drop-controller.js.map +1 -0
  209. package/dist/controllers/focusgroup-navigation-controller/index.d.ts +12 -0
  210. package/dist/controllers/focusgroup-navigation-controller/index.js +2 -0
  211. package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.d.ts +496 -0
  212. package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.js +345 -0
  213. package/dist/controllers/focusgroup-navigation-controller/src/focusgroup-navigation-controller.js.map +1 -0
  214. package/dist/controllers/hover-controller/index.d.ts +12 -0
  215. package/dist/controllers/hover-controller/index.js +2 -0
  216. package/dist/controllers/hover-controller/src/hover-controller.d.ts +118 -0
  217. package/dist/controllers/hover-controller/src/hover-controller.js +90 -0
  218. package/dist/controllers/hover-controller/src/hover-controller.js.map +1 -0
  219. package/dist/controllers/index.d.ts +26 -0
  220. package/dist/controllers/index.js +18 -0
  221. package/dist/controllers/language-resolution.d.ts +87 -0
  222. package/dist/controllers/language-resolution.js +56 -0
  223. package/dist/controllers/language-resolution.js.map +1 -0
  224. package/dist/controllers/live-selection-controller/index.d.ts +12 -0
  225. package/dist/controllers/live-selection-controller/index.js +2 -0
  226. package/dist/controllers/live-selection-controller/src/live-selection-controller.d.ts +144 -0
  227. package/dist/controllers/live-selection-controller/src/live-selection-controller.js +36 -0
  228. package/dist/controllers/live-selection-controller/src/live-selection-controller.js.map +1 -0
  229. package/dist/controllers/page-scroll-lock-controller/index.d.ts +12 -0
  230. package/dist/controllers/page-scroll-lock-controller/index.js +2 -0
  231. package/dist/controllers/page-scroll-lock-controller/src/page-scroll-lock.d.ts +20 -0
  232. package/dist/controllers/page-scroll-lock-controller/src/page-scroll-lock.js +30 -0
  233. package/dist/controllers/page-scroll-lock-controller/src/page-scroll-lock.js.map +1 -0
  234. package/dist/controllers/pending-controller/index.d.ts +12 -0
  235. package/dist/controllers/pending-controller/index.js +2 -0
  236. package/dist/controllers/pending-controller/src/pending-controller.d.ts +95 -0
  237. package/dist/controllers/pending-controller/src/pending-controller.js +55 -0
  238. package/dist/controllers/pending-controller/src/pending-controller.js.map +1 -0
  239. package/dist/controllers/placement-controller/index.d.ts +12 -0
  240. package/dist/controllers/placement-controller/index.js +4 -0
  241. package/dist/controllers/placement-controller/src/fallback-placements.d.ts +9 -0
  242. package/dist/controllers/placement-controller/src/fallback-placements.js +71 -0
  243. package/dist/controllers/placement-controller/src/fallback-placements.js.map +1 -0
  244. package/dist/controllers/placement-controller/src/placement-controller.d.ts +152 -0
  245. package/dist/controllers/placement-controller/src/placement-controller.js +129 -0
  246. package/dist/controllers/placement-controller/src/placement-controller.js.map +1 -0
  247. package/dist/controllers/placement-controller/src/placement-conversion.d.ts +35 -0
  248. package/dist/controllers/placement-controller/src/placement-conversion.js +54 -0
  249. package/dist/controllers/placement-controller/src/placement-conversion.js.map +1 -0
  250. package/dist/controllers/placement-controller/src/types.d.ts +128 -0
  251. package/dist/controllers/placement-controller/src/types.js +29 -0
  252. package/dist/controllers/placement-controller/src/types.js.map +1 -0
  253. package/dist/controllers/slot-attribute-propagation-controller/index.d.ts +12 -0
  254. package/dist/controllers/slot-attribute-propagation-controller/index.js +2 -0
  255. package/dist/controllers/slot-attribute-propagation-controller/src/slot-attribute-propagation-controller.d.ts +65 -0
  256. package/dist/controllers/slot-attribute-propagation-controller/src/slot-attribute-propagation-controller.js +33 -0
  257. package/dist/controllers/slot-attribute-propagation-controller/src/slot-attribute-propagation-controller.js.map +1 -0
  258. package/dist/controllers/slot-presence-controller/index.d.ts +12 -0
  259. package/dist/controllers/slot-presence-controller/index.js +2 -0
  260. package/dist/controllers/slot-presence-controller/src/slot-presence-controller.d.ts +57 -0
  261. package/dist/controllers/slot-presence-controller/src/slot-presence-controller.js +44 -0
  262. package/dist/controllers/slot-presence-controller/src/slot-presence-controller.js.map +1 -0
  263. package/dist/controllers/slot-text-controller/index.d.ts +12 -0
  264. package/dist/controllers/slot-text-controller/index.js +2 -0
  265. package/dist/controllers/slot-text-controller/src/slot-text-controller.d.ts +92 -0
  266. package/dist/controllers/slot-text-controller/src/slot-text-controller.js +53 -0
  267. package/dist/controllers/slot-text-controller/src/slot-text-controller.js.map +1 -0
  268. package/dist/directives/index.d.ts +15 -0
  269. package/dist/directives/index.js +3 -0
  270. package/dist/directives/pending-spinner/index.d.ts +12 -0
  271. package/dist/directives/pending-spinner/index.js +1 -0
  272. package/dist/directives/pending-spinner/src/pending-spinner.d.ts +22 -0
  273. package/dist/directives/pending-spinner/src/pending-spinner.js +39 -0
  274. package/dist/directives/pending-spinner/src/pending-spinner.js.map +1 -0
  275. package/dist/element/define-element.d.ts +16 -0
  276. package/dist/element/define-element.js +8 -0
  277. package/dist/element/define-element.js.map +1 -0
  278. package/dist/element/index.d.ts +14 -0
  279. package/dist/element/index.js +4 -0
  280. package/dist/element/spectrum-element.d.ts +69 -0
  281. package/dist/element/spectrum-element.js +85 -0
  282. package/dist/element/spectrum-element.js.map +1 -0
  283. package/dist/element/version.d.ts +19 -0
  284. package/dist/element/version.js +6 -0
  285. package/dist/element/version.js.map +1 -0
  286. package/dist/mixins/disabled-mixin.d.ts +30 -0
  287. package/dist/mixins/disabled-mixin.js +27 -0
  288. package/dist/mixins/disabled-mixin.js.map +1 -0
  289. package/dist/mixins/index.d.ts +16 -0
  290. package/dist/mixins/index.js +5 -0
  291. package/dist/mixins/linear-progress-mixin.d.ts +41 -0
  292. package/dist/mixins/linear-progress-mixin.js +115 -0
  293. package/dist/mixins/linear-progress-mixin.js.map +1 -0
  294. package/dist/mixins/pending-mixin.d.ts +45 -0
  295. package/dist/mixins/pending-mixin.js +50 -0
  296. package/dist/mixins/pending-mixin.js.map +1 -0
  297. package/dist/mixins/sized-mixin.d.ts +49 -0
  298. package/dist/mixins/sized-mixin.js +42 -0
  299. package/dist/mixins/sized-mixin.js.map +1 -0
  300. package/dist/utils/actual-placement.d.ts +10 -0
  301. package/dist/utils/actual-placement.js +8 -0
  302. package/dist/utils/actual-placement.js.map +1 -0
  303. package/dist/utils/capitalize.d.ts +26 -0
  304. package/dist/utils/capitalize.js +8 -0
  305. package/dist/utils/capitalize.js.map +1 -0
  306. package/dist/utils/deep-contains.d.ts +26 -0
  307. package/dist/utils/deep-contains.js +14 -0
  308. package/dist/utils/deep-contains.js.map +1 -0
  309. package/dist/utils/dev-validation.d.ts +88 -0
  310. package/dist/utils/dev-validation.js +33 -0
  311. package/dist/utils/dev-validation.js.map +1 -0
  312. package/dist/utils/dismissible-stack.d.ts +26 -0
  313. package/dist/utils/dismissible-stack.js +16 -0
  314. package/dist/utils/dismissible-stack.js.map +1 -0
  315. package/dist/utils/focusable-selectors.d.ts +43 -0
  316. package/dist/utils/focusable-selectors.js +18 -0
  317. package/dist/utils/focusable-selectors.js.map +1 -0
  318. package/dist/utils/get-active-element.d.ts +31 -0
  319. package/dist/utils/get-active-element.js +11 -0
  320. package/dist/utils/get-active-element.js.map +1 -0
  321. package/dist/utils/get-label-from-slot.d.ts +12 -0
  322. package/dist/utils/get-label-from-slot.js +10 -0
  323. package/dist/utils/get-label-from-slot.js.map +1 -0
  324. package/dist/utils/index.d.ts +22 -0
  325. package/dist/utils/index.js +12 -0
  326. package/dist/utils/is-focus-visible-in-tree.d.ts +33 -0
  327. package/dist/utils/is-focus-visible-in-tree.js +11 -0
  328. package/dist/utils/is-focus-visible-in-tree.js.map +1 -0
  329. package/dist/utils/resolve-trigger.d.ts +42 -0
  330. package/dist/utils/resolve-trigger.js +23 -0
  331. package/dist/utils/resolve-trigger.js.map +1 -0
  332. package/dist/utils/transition.d.ts +53 -0
  333. package/dist/utils/transition.js +26 -0
  334. package/dist/utils/transition.js.map +1 -0
  335. package/package.json +644 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-scroll-lock.js","names":[],"sources":["../../../../controllers/page-scroll-lock-controller/src/page-scroll-lock.ts"],"sourcesContent":["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\n\n// ────────────────────────────────────────────\n// Module-scoped reference-counted lock\n// ────────────────────────────────────────────\n//\n// Stacked blocking surfaces (e.g. nested modal dialogs, a modal popover opened\n// over another) must coordinate a single page-scroll lock. The document's\n// original `overflow` is captured once on the 0 -> 1 transition and restored\n// once on the 1 -> 0 transition. Saving per instance would let a later locker\n// capture an already-locked value (`hidden`) and then restore it permanently\n// when it releases, leaving the page unscrollable.\n\nlet lockCount = 0;\nlet savedOverflow = '';\n\nfunction acquirePageScrollLock(): void {\n if (lockCount === 0) {\n const html = document.documentElement;\n savedOverflow = html.style.overflow;\n html.style.overflow = 'hidden';\n }\n lockCount += 1;\n}\n\nfunction releasePageScrollLock(): void {\n if (lockCount === 0) {\n return;\n }\n lockCount -= 1;\n if (lockCount === 0) {\n document.documentElement.style.overflow = savedOverflow;\n savedOverflow = '';\n }\n}\n\n/**\n * Locks page scroll behind a blocking surface (a modal popover, dialog, or tray)\n * by setting `overflow: hidden` on the document element. A component's shadow\n * stylesheet cannot reach `<html>`, so this is done in JS.\n *\n * The lock is reference-counted at module scope so concurrent locks from stacked\n * surfaces do not clobber one another's saved state. Each host holds at most one\n * count (the per-instance `lock()` / `unlock()` are idempotent), and the\n * controller releases the host's count automatically on disconnect.\n */\nexport class PageScrollLockController implements ReactiveController {\n private _locked = false;\n\n constructor(host: ReactiveElement) {\n host.addController(this);\n }\n\n /** Lock page scroll on behalf of the host. Idempotent per host. */\n public lock(): void {\n if (this._locked) {\n return;\n }\n this._locked = true;\n acquirePageScrollLock();\n }\n\n /** Release the host's lock if it holds one. Idempotent per host. */\n public unlock(): void {\n if (!this._locked) {\n return;\n }\n this._locked = false;\n releasePageScrollLock();\n }\n\n public hostDisconnected(): void {\n this.unlock();\n }\n}\n"],"mappings":";AAyBA,IAAI,IAAY,GACZ,IAAgB;AAEpB,SAAS,IAA8B;AACrC,KAAI,MAAc,GAAG;EACnB,IAAM,IAAO,SAAS;AAEtB,EADA,IAAgB,EAAK,MAAM,UAC3B,EAAK,MAAM,WAAW;;AAExB,MAAa;;AAGf,SAAS,IAA8B;AACjC,OAAc,MAGlB,KACI,MAAc,MAChB,SAAS,gBAAgB,MAAM,WAAW,GAC1C,IAAgB;;AAcpB,IAAa,IAAb,MAAoE;CAGlE,YAAY,GAAuB;AACjC,iBAHgB,IAGhB,EAAK,cAAc,KAAK;;CAI1B,OAAoB;AACd,OAAK,YAGT,KAAK,UAAU,IACf,GAAuB;;CAIzB,SAAsB;AACf,OAAK,YAGV,KAAK,UAAU,IACf,GAAuB;;CAGzB,mBAAgC;AAC9B,OAAK,QAAQ"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright 2026 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ export { PendingController, type PendingControllerHost, type PendingControllerOptions, } from './src/pending-controller.js';
@@ -0,0 +1,2 @@
1
+ import { PendingController as e } from "./src/pending-controller.js";
2
+ export { e as PendingController };
@@ -0,0 +1,95 @@
1
+ import { ReactiveController, ReactiveElement } from 'lit';
2
+ import { PendingSpinnerResult } from '../../../directives/pending-spinner/index.js';
3
+ /** Minimum interface required from any element that hosts a {@link PendingController}. */
4
+ export interface PendingControllerHost extends ReactiveElement {
5
+ /** Whether the host is in a pending (busy) state. */
6
+ pending: boolean;
7
+ /**
8
+ * Optional explicit accessible label used during the pending state. When
9
+ * omitted, the controller derives a busy label from
10
+ * {@link PendingControllerOptions.resolveAccessibleName}.
11
+ */
12
+ pendingLabel?: string;
13
+ }
14
+ /** Configuration options for {@link PendingController}. */
15
+ export interface PendingControllerOptions {
16
+ /**
17
+ * Milliseconds to wait after `pending` becomes true before activating the
18
+ * pending visual, so the host does not flash to its busy appearance for
19
+ * operations that complete quickly. Defaults to `1000`.
20
+ */
21
+ delay?: number;
22
+ /**
23
+ * CSS selector, resolved within the host's `renderRoot`, for the element
24
+ * whose inline size should be frozen while pending (via
25
+ * `--swc-pending-inline-size`) so the host does not resize when its label or
26
+ * icon is hidden. Defaults to `'button'`. Pass `null` to skip the freeze.
27
+ */
28
+ targetSelector?: string | null;
29
+ /**
30
+ * Returns the host's non-busy accessible name, used to derive the default
31
+ * busy label (`"<name>, busy"`). Keeps the controller decoupled from how the
32
+ * host resolves its own name.
33
+ */
34
+ resolveAccessibleName?: () => string | null;
35
+ }
36
+ /**
37
+ * A Lit {@link ReactiveController} that manages the pending (busy) *state* of a
38
+ * host element: the delayed visual activation, freezing the host's inline size
39
+ * while busy, and deriving the pending accessible name. Rendering is handled
40
+ * separately by the `renderPendingSpinner` directive
41
+ * (`@adobe/spectrum-wc-core/directives/pending-spinner`); wiring (the
42
+ * `pending` / `pending-label` properties and click suppression) is handled by
43
+ * `PendingMixin` (`@adobe/spectrum-wc-core/mixins`).
44
+ *
45
+ * The accessible name and `aria-disabled` are applied by the host's own
46
+ * template, keyed off `host.pending` for an immediate (non-delayed) response;
47
+ * this controller exposes {@link getPendingAccessibleName} for the host to read.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const pendingController = new PendingController(this, {
52
+ * resolveAccessibleName: () => this.textContent?.trim() || null,
53
+ * });
54
+ * // in render(): class=${classMap({ active: pendingController.pendingActive })}
55
+ * ```
56
+ */
57
+ export declare class PendingController implements ReactiveController {
58
+ private readonly _host;
59
+ private readonly _delay;
60
+ private readonly _targetSelector;
61
+ private readonly _resolveAccessibleName;
62
+ private _timer;
63
+ /** Tracks the last-seen `pending` value so transitions can be detected in `hostUpdate`. */
64
+ private _wasPending;
65
+ /**
66
+ * Whether the pending visual is currently active. Becomes `true` only after
67
+ * the configured delay so the host does not flash to its busy appearance for
68
+ * operations that complete quickly. Read this from the host's `render`.
69
+ */
70
+ get pendingActive(): boolean;
71
+ private _pendingActive;
72
+ constructor(host: PendingControllerHost, options?: PendingControllerOptions);
73
+ /**
74
+ * Derives the pending-state accessible label. Prefers an explicit
75
+ * `pendingLabel`, then the resolved non-busy name plus a ", busy" suffix,
76
+ * then a fixed "Busy" fallback.
77
+ */
78
+ getPendingAccessibleName(): string;
79
+ /**
80
+ * Renders the pending spinner for the controller's current state via the
81
+ * `renderPendingSpinner` directive. Exposed here so a host gets the indicator
82
+ * straight from the controller, without importing the directive separately.
83
+ * Returns `nothing` while the host is not pending.
84
+ */
85
+ renderPendingState(): PendingSpinnerResult;
86
+ hostConnected(): void;
87
+ hostUpdate(): void;
88
+ hostDisconnected(): void;
89
+ private _activateAfterDelay;
90
+ private _deactivate;
91
+ private _clearTimer;
92
+ private get _freezeTarget();
93
+ private _freezeInlineSize;
94
+ private _releaseInlineSize;
95
+ }
@@ -0,0 +1,55 @@
1
+ import { renderPendingSpinner as e } from "../../../directives/pending-spinner/src/pending-spinner.js";
2
+ import "../../../directives/pending-spinner/index.js";
3
+ //#region controllers/pending-controller/src/pending-controller.ts
4
+ var t = 1e3, n = "--swc-pending-inline-size", r = class {
5
+ get pendingActive() {
6
+ return this._pendingActive;
7
+ }
8
+ constructor(e, n = {}) {
9
+ var r, i;
10
+ this._timer = null, this._wasPending = !1, this._pendingActive = !1, this._host = e, this._delay = (r = n.delay) == null ? t : r, this._targetSelector = n.targetSelector === void 0 ? "button" : n.targetSelector, this._resolveAccessibleName = (i = n.resolveAccessibleName) == null ? (() => null) : i, e.addController(this);
11
+ }
12
+ getPendingAccessibleName() {
13
+ if (this._host.pendingLabel) return this._host.pendingLabel;
14
+ let e = this._resolveAccessibleName();
15
+ return e ? `${e}, busy` : "Busy";
16
+ }
17
+ renderPendingState() {
18
+ return e(this._host.pending, this._pendingActive);
19
+ }
20
+ hostConnected() {
21
+ this._host.pending && !this._wasPending && (this._wasPending = !0, this._activateAfterDelay());
22
+ }
23
+ hostUpdate() {
24
+ this._host.pending !== this._wasPending && (this._wasPending = this._host.pending, this._host.pending ? this._activateAfterDelay() : this._deactivate());
25
+ }
26
+ hostDisconnected() {
27
+ this._clearTimer(), this._wasPending = !1, this._pendingActive = !1;
28
+ }
29
+ _activateAfterDelay() {
30
+ this._timer = setTimeout(() => {
31
+ this._timer = null, this._host.pending && (this._freezeInlineSize(), this._pendingActive = !0, this._host.requestUpdate());
32
+ }, this._delay);
33
+ }
34
+ _deactivate() {
35
+ this._clearTimer(), this._releaseInlineSize(), this._pendingActive && (this._pendingActive = !1, this._host.requestUpdate());
36
+ }
37
+ _clearTimer() {
38
+ this._timer !== null && (clearTimeout(this._timer), this._timer = null);
39
+ }
40
+ get _freezeTarget() {
41
+ return this._targetSelector ? this._host.renderRoot.querySelector(this._targetSelector) : null;
42
+ }
43
+ _freezeInlineSize() {
44
+ let e = this._freezeTarget;
45
+ e && e.style.setProperty(n, `${e.offsetWidth}px`);
46
+ }
47
+ _releaseInlineSize() {
48
+ var e;
49
+ (e = this._freezeTarget) == null || e.style.removeProperty(n);
50
+ }
51
+ };
52
+ //#endregion
53
+ export { r as PendingController };
54
+
55
+ //# sourceMappingURL=pending-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-controller.js","names":[],"sources":["../../../../controllers/pending-controller/src/pending-controller.ts"],"sourcesContent":["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport type { ReactiveController, ReactiveElement } from 'lit';\n\nimport {\n type PendingSpinnerResult,\n renderPendingSpinner,\n} from '../../../directives/pending-spinner/index.js';\n\n// ─────────────────────────\n// TYPES\n// ─────────────────────────\n\n/** Minimum interface required from any element that hosts a {@link PendingController}. */\nexport interface PendingControllerHost extends ReactiveElement {\n /** Whether the host is in a pending (busy) state. */\n pending: boolean;\n\n /**\n * Optional explicit accessible label used during the pending state. When\n * omitted, the controller derives a busy label from\n * {@link PendingControllerOptions.resolveAccessibleName}.\n */\n pendingLabel?: string;\n}\n\n/** Configuration options for {@link PendingController}. */\nexport interface PendingControllerOptions {\n /**\n * Milliseconds to wait after `pending` becomes true before activating the\n * pending visual, so the host does not flash to its busy appearance for\n * operations that complete quickly. Defaults to `1000`.\n */\n delay?: number;\n\n /**\n * CSS selector, resolved within the host's `renderRoot`, for the element\n * whose inline size should be frozen while pending (via\n * `--swc-pending-inline-size`) so the host does not resize when its label or\n * icon is hidden. Defaults to `'button'`. Pass `null` to skip the freeze.\n */\n targetSelector?: string | null;\n\n /**\n * Returns the host's non-busy accessible name, used to derive the default\n * busy label (`\"<name>, busy\"`). Keeps the controller decoupled from how the\n * host resolves its own name.\n */\n resolveAccessibleName?: () => string | null;\n}\n\nconst DEFAULT_DELAY = 1000;\n\n/**\n * Custom property the controller sets on the freeze target to lock its measured\n * inline size while pending. Consumers apply it via `inline-size: var(...)`.\n */\nconst INLINE_SIZE_PROPERTY = '--swc-pending-inline-size';\n\n// ─────────────────────────\n// CONTROLLER\n// ─────────────────────────\n\n/**\n * A Lit {@link ReactiveController} that manages the pending (busy) *state* of a\n * host element: the delayed visual activation, freezing the host's inline size\n * while busy, and deriving the pending accessible name. Rendering is handled\n * separately by the `renderPendingSpinner` directive\n * (`@adobe/spectrum-wc-core/directives/pending-spinner`); wiring (the\n * `pending` / `pending-label` properties and click suppression) is handled by\n * `PendingMixin` (`@adobe/spectrum-wc-core/mixins`).\n *\n * The accessible name and `aria-disabled` are applied by the host's own\n * template, keyed off `host.pending` for an immediate (non-delayed) response;\n * this controller exposes {@link getPendingAccessibleName} for the host to read.\n *\n * @example\n * ```ts\n * const pendingController = new PendingController(this, {\n * resolveAccessibleName: () => this.textContent?.trim() || null,\n * });\n * // in render(): class=${classMap({ active: pendingController.pendingActive })}\n * ```\n */\nexport class PendingController implements ReactiveController {\n private readonly _host: PendingControllerHost;\n private readonly _delay: number;\n private readonly _targetSelector: string | null;\n private readonly _resolveAccessibleName: () => string | null;\n\n private _timer: ReturnType<typeof setTimeout> | null = null;\n\n /** Tracks the last-seen `pending` value so transitions can be detected in `hostUpdate`. */\n private _wasPending = false;\n\n /**\n * Whether the pending visual is currently active. Becomes `true` only after\n * the configured delay so the host does not flash to its busy appearance for\n * operations that complete quickly. Read this from the host's `render`.\n */\n public get pendingActive(): boolean {\n return this._pendingActive;\n }\n private _pendingActive = false;\n\n constructor(\n host: PendingControllerHost,\n options: PendingControllerOptions = {}\n ) {\n this._host = host;\n this._delay = options.delay ?? DEFAULT_DELAY;\n this._targetSelector =\n options.targetSelector === undefined ? 'button' : options.targetSelector;\n this._resolveAccessibleName = options.resolveAccessibleName ?? (() => null);\n host.addController(this);\n }\n\n // ─────────────────────────\n // PUBLIC API\n // ─────────────────────────\n\n /**\n * Derives the pending-state accessible label. Prefers an explicit\n * `pendingLabel`, then the resolved non-busy name plus a \", busy\" suffix,\n * then a fixed \"Busy\" fallback.\n */\n public getPendingAccessibleName(): string {\n if (this._host.pendingLabel) {\n return this._host.pendingLabel;\n }\n const resolvedName = this._resolveAccessibleName();\n return resolvedName ? `${resolvedName}, busy` : 'Busy';\n }\n\n /**\n * Renders the pending spinner for the controller's current state via the\n * `renderPendingSpinner` directive. Exposed here so a host gets the indicator\n * straight from the controller, without importing the directive separately.\n * Returns `nothing` while the host is not pending.\n */\n public renderPendingState(): PendingSpinnerResult {\n return renderPendingSpinner(this._host.pending, this._pendingActive);\n }\n\n // ─────────────────────────\n // LIFECYCLE\n // ─────────────────────────\n\n public hostConnected(): void {\n // Lit does not schedule an update on reconnect, so `hostUpdate` would not\n // restart the delay timer for an element that reconnects while still\n // pending. Re-arm it here. Setting `_wasPending` first prevents a later\n // `hostUpdate` from starting a second timer.\n if (this._host.pending && !this._wasPending) {\n this._wasPending = true;\n this._activateAfterDelay();\n }\n }\n\n public hostUpdate(): void {\n if (this._host.pending === this._wasPending) {\n return;\n }\n this._wasPending = this._host.pending;\n if (this._host.pending) {\n this._activateAfterDelay();\n } else {\n this._deactivate();\n }\n }\n\n public hostDisconnected(): void {\n this._clearTimer();\n this._wasPending = false;\n this._pendingActive = false;\n }\n\n // ─────────────────────────\n // IMPLEMENTATION\n // ─────────────────────────\n\n private _activateAfterDelay(): void {\n this._timer = setTimeout(() => {\n this._timer = null;\n // Guard against `pending` flipping back to false after the timer fired\n // but before this callback ran.\n if (!this._host.pending) {\n return;\n }\n this._freezeInlineSize();\n this._pendingActive = true;\n this._host.requestUpdate();\n }, this._delay);\n }\n\n private _deactivate(): void {\n this._clearTimer();\n this._releaseInlineSize();\n if (this._pendingActive) {\n this._pendingActive = false;\n this._host.requestUpdate();\n }\n }\n\n private _clearTimer(): void {\n if (this._timer !== null) {\n clearTimeout(this._timer);\n this._timer = null;\n }\n }\n\n private get _freezeTarget(): HTMLElement | null {\n if (!this._targetSelector) {\n return null;\n }\n return this._host.renderRoot.querySelector<HTMLElement>(\n this._targetSelector\n );\n }\n\n private _freezeInlineSize(): void {\n const target = this._freezeTarget;\n if (target) {\n target.style.setProperty(INLINE_SIZE_PROPERTY, `${target.offsetWidth}px`);\n }\n }\n\n private _releaseInlineSize(): void {\n this._freezeTarget?.style.removeProperty(INLINE_SIZE_PROPERTY);\n }\n}\n"],"mappings":";;;AA6DA,IAAM,IAAgB,KAMhB,IAAuB,6BA2BhB,IAAb,MAA6D;CAgB3D,IAAW,gBAAyB;AAClC,SAAO,KAAK;;CAId,YACE,GACA,IAAoC,EAAE,EACtC;;AAMA,gBAxBqD,yBAGjC,0BAUG,IAMvB,KAAK,QAAQ,GACb,KAAK,UAAA,IAAS,EAAQ,UAAA,OAAS,IAAT,GACtB,KAAK,kBACH,EAAQ,mBAAmB,KAAA,IAAY,WAAW,EAAQ,gBAC5D,KAAK,0BAAA,IAAyB,EAAQ,0BAAA,cAAgC,QAAhC,GACtC,EAAK,cAAc,KAAK;;CAY1B,2BAA0C;AACxC,MAAI,KAAK,MAAM,aACb,QAAO,KAAK,MAAM;EAEpB,IAAM,IAAe,KAAK,wBAAwB;AAClD,SAAO,IAAe,GAAG,EAAa,UAAU;;CASlD,qBAAkD;AAChD,SAAO,EAAqB,KAAK,MAAM,SAAS,KAAK,eAAe;;CAOtE,gBAA6B;AAK3B,EAAI,KAAK,MAAM,WAAW,CAAC,KAAK,gBAC9B,KAAK,cAAc,IACnB,KAAK,qBAAqB;;CAI9B,aAA0B;AACpB,OAAK,MAAM,YAAY,KAAK,gBAGhC,KAAK,cAAc,KAAK,MAAM,SAC1B,KAAK,MAAM,UACb,KAAK,qBAAqB,GAE1B,KAAK,aAAa;;CAItB,mBAAgC;AAG9B,EAFA,KAAK,aAAa,EAClB,KAAK,cAAc,IACnB,KAAK,iBAAiB;;CAOxB,sBAAoC;AAClC,OAAK,SAAS,iBAAiB;AAC7B,QAAK,SAAS,MAGT,KAAK,MAAM,YAGhB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,IACtB,KAAK,MAAM,eAAe;KACzB,KAAK,OAAO;;CAGjB,cAA4B;AAG1B,EAFA,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACrB,KAAK,mBACP,KAAK,iBAAiB,IACtB,KAAK,MAAM,eAAe;;CAI9B,cAA4B;AAC1B,EAAI,KAAK,WAAW,SAClB,aAAa,KAAK,OAAO,EACzB,KAAK,SAAS;;CAIlB,IAAY,gBAAoC;AAI9C,SAHK,KAAK,kBAGH,KAAK,MAAM,WAAW,cAC3B,KAAK,gBACN,GAJQ;;CAOX,oBAAkC;EAChC,IAAM,IAAS,KAAK;AACpB,EAAI,KACF,EAAO,MAAM,YAAY,GAAsB,GAAG,EAAO,YAAY,IAAI;;CAI7E,qBAAmC;;AACjC,GAAA,IAAA,KAAK,kBAAA,QAAA,EAAe,MAAM,eAAe,EAAqB"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright 2026 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ export { ALL_PLACEMENTS, fromFloatingPlacement, PlacementController, toFloatingPlacement, type Placement, type PlacementOptions, type VirtualTrigger, } from './src/placement-controller.js';
@@ -0,0 +1,4 @@
1
+ import { fromFloatingPlacement as e, toFloatingPlacement as t } from "./src/placement-conversion.js";
2
+ import { ALL_PLACEMENTS as n } from "./src/types.js";
3
+ import { PlacementController as r } from "./src/placement-controller.js";
4
+ export { n as ALL_PLACEMENTS, r as PlacementController, e as fromFloatingPlacement, t as toFloatingPlacement };
@@ -0,0 +1,9 @@
1
+ import { Placement as FloatingPlacement } from '@floating-ui/dom';
2
+ /**
3
+ * Look up the fallback placement order for Floating UI's `flip` middleware
4
+ * when the anchor is a `VirtualTrigger`.
5
+ *
6
+ * @param placement - Normalized Floating UI placement for the current side.
7
+ * @returns Ordered list of placements to try when the primary side does not fit.
8
+ */
9
+ export declare function getFallbackPlacements(placement: FloatingPlacement): FloatingPlacement[];
@@ -0,0 +1,71 @@
1
+ //#region controllers/placement-controller/src/fallback-placements.ts
2
+ var e = {
3
+ left: [
4
+ "right",
5
+ "bottom",
6
+ "top"
7
+ ],
8
+ "left-start": [
9
+ "right-start",
10
+ "bottom",
11
+ "top"
12
+ ],
13
+ "left-end": [
14
+ "right-end",
15
+ "bottom",
16
+ "top"
17
+ ],
18
+ right: [
19
+ "left",
20
+ "bottom",
21
+ "top"
22
+ ],
23
+ "right-start": [
24
+ "left-start",
25
+ "bottom",
26
+ "top"
27
+ ],
28
+ "right-end": [
29
+ "left-end",
30
+ "bottom",
31
+ "top"
32
+ ],
33
+ top: [
34
+ "bottom",
35
+ "left",
36
+ "right"
37
+ ],
38
+ "top-start": [
39
+ "bottom-start",
40
+ "left",
41
+ "right"
42
+ ],
43
+ "top-end": [
44
+ "bottom-end",
45
+ "left",
46
+ "right"
47
+ ],
48
+ bottom: [
49
+ "top",
50
+ "left",
51
+ "right"
52
+ ],
53
+ "bottom-start": [
54
+ "top-start",
55
+ "left",
56
+ "right"
57
+ ],
58
+ "bottom-end": [
59
+ "top-end",
60
+ "left",
61
+ "right"
62
+ ]
63
+ };
64
+ function t(t) {
65
+ var n;
66
+ return (n = e[t]) == null ? [t] : n;
67
+ }
68
+ //#endregion
69
+ export { t as getFallbackPlacements };
70
+
71
+ //# sourceMappingURL=fallback-placements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallback-placements.js","names":[],"sources":["../../../../controllers/placement-controller/src/fallback-placements.ts"],"sourcesContent":["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport type { Placement as FloatingPlacement } from '@floating-ui/dom';\n\nconst FALLBACKS: Record<FloatingPlacement, FloatingPlacement[]> = {\n left: ['right', 'bottom', 'top'],\n 'left-start': ['right-start', 'bottom', 'top'],\n 'left-end': ['right-end', 'bottom', 'top'],\n right: ['left', 'bottom', 'top'],\n 'right-start': ['left-start', 'bottom', 'top'],\n 'right-end': ['left-end', 'bottom', 'top'],\n top: ['bottom', 'left', 'right'],\n 'top-start': ['bottom-start', 'left', 'right'],\n 'top-end': ['bottom-end', 'left', 'right'],\n bottom: ['top', 'left', 'right'],\n 'bottom-start': ['top-start', 'left', 'right'],\n 'bottom-end': ['top-end', 'left', 'right'],\n};\n\n/**\n * Look up the fallback placement order for Floating UI's `flip` middleware\n * when the anchor is a `VirtualTrigger`.\n *\n * @param placement - Normalized Floating UI placement for the current side.\n * @returns Ordered list of placements to try when the primary side does not fit.\n */\nexport function getFallbackPlacements(\n placement: FloatingPlacement\n): FloatingPlacement[] {\n return FALLBACKS[placement] ?? [placement];\n}\n"],"mappings":";AAcA,IAAM,IAA4D;CAChE,MAAM;EAAC;EAAS;EAAU;EAAM;CAChC,cAAc;EAAC;EAAe;EAAU;EAAM;CAC9C,YAAY;EAAC;EAAa;EAAU;EAAM;CAC1C,OAAO;EAAC;EAAQ;EAAU;EAAM;CAChC,eAAe;EAAC;EAAc;EAAU;EAAM;CAC9C,aAAa;EAAC;EAAY;EAAU;EAAM;CAC1C,KAAK;EAAC;EAAU;EAAQ;EAAQ;CAChC,aAAa;EAAC;EAAgB;EAAQ;EAAQ;CAC9C,WAAW;EAAC;EAAc;EAAQ;EAAQ;CAC1C,QAAQ;EAAC;EAAO;EAAQ;EAAQ;CAChC,gBAAgB;EAAC;EAAa;EAAQ;EAAQ;CAC9C,cAAc;EAAC;EAAW;EAAQ;EAAQ;CAC3C;AASD,SAAgB,EACd,GACqB;;AACrB,SAAA,IAAO,EAAU,OAAA,OAAc,CAAC,EAAU,GAAzB"}
@@ -0,0 +1,152 @@
1
+ import { ReactiveController, ReactiveControllerHost } from 'lit';
2
+ import { Placement, PlacementOptions, VirtualTrigger } from './types.js';
3
+ /**
4
+ * **PlacementController** — Lit reactive controller that positions a floating
5
+ * element relative to a trigger using [Floating UI](https://floating-ui.com/)
6
+ * (`computePosition` + `autoUpdate`).
7
+ *
8
+ * Hyphenated placements are accepted on the public API. Logical sides
9
+ * (`start`, `end`) resolve to physical sides against the trigger's computed
10
+ * writing direction (`start` is the left in LTR, the right in RTL), so the
11
+ * panel lands on the correct side. Logical alignment suffixes (`bottom-start`)
12
+ * are left for Floating UI's own RTL handling; the consumer's CSS still owns
13
+ * direction-aware styling such as tip orientation. A `dir` change on the
14
+ * document root or the trigger's nearest `[dir]` ancestor recomputes
15
+ * placement, so runtime LTR/RTL flips re-resolve correctly.
16
+ *
17
+ * ### Available-space custom properties
18
+ *
19
+ * The `size` middleware does **not** write `max-width` / `max-height` on the
20
+ * floating element — an inline max-size would override the consuming
21
+ * component's intended CSS max-size. Instead it exposes the space available to
22
+ * the trigger as two custom properties on the floating element, refreshed on
23
+ * every compute. The caller removes them after any exit transition completes
24
+ * (clearing them in `stop()` would snap the floating element's size
25
+ * mid-animation):
26
+ *
27
+ * - `--swc-placement-available-width` — usable inline space, in px.
28
+ * - `--swc-placement-available-height` — usable block space, in px (floored to
29
+ * a minimum so a cramped trigger still yields a usable panel).
30
+ *
31
+ * Only components positioned by this controller receive these properties.
32
+ * Such a component opts into viewport-bounded sizing by combining them with
33
+ * its own intended size via `min()`, with a fallback for when the controller
34
+ * is not active:
35
+ *
36
+ * ```css
37
+ * .floating {
38
+ * box-sizing: border-box;
39
+ * max-inline-size: min(var(--intended-width), var(--swc-placement-available-width, 100vi));
40
+ * max-block-size: min(var(--intended-height), var(--swc-placement-available-height, 90vb));
41
+ * overflow: auto;
42
+ * }
43
+ * ```
44
+ *
45
+ * The fallbacks use logical viewport units (`vi` / `vb`); `90vb` leaves a small
46
+ * buffer so the trigger isn't scrolled out of view. `box-sizing: border-box` is
47
+ * required so the available-space values account for the element's own padding
48
+ * and border rather than overflowing past them. Pair `max-block-size` with
49
+ * `overflow: auto` so the panel scrolls when the block space is constrained
50
+ * (read `isConstrained` to detect that state).
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * this.placement.start(this.trigger, this.dialog, {
55
+ * placement: 'bottom-start',
56
+ * offset: 0,
57
+ * onPlacementChange: (p) => {
58
+ * this.actualPlacement = p;
59
+ * },
60
+ * });
61
+ * ```
62
+ */
63
+ export declare class PlacementController implements ReactiveController {
64
+ private cleanup?;
65
+ private session;
66
+ /**
67
+ * The computed placement after `flip` reorients (hyphenated). `null` when
68
+ * `stop` has been called.
69
+ *
70
+ * Set synchronously to the requested `PlacementOptions.placement`
71
+ * (or `DEFAULT_PLACEMENT`) when `start` is called, then refreshed on every
72
+ * successful `computePlacement` pass. `PlacementOptions.onPlacementChange`
73
+ * fires when this value changes (and once after the first compute), so
74
+ * consumers can mirror it in a single callback without also reading it
75
+ * synchronously after `start()`.
76
+ */
77
+ actualPlacement: Placement | null;
78
+ /**
79
+ * Whether the floating content would overflow the available space
80
+ * below/above the trigger on the last compute. `true` when the content is
81
+ * taller than the available height, so a consumer applying
82
+ * `max-block-size: min(…, var(--swc-placement-available-height))` will be
83
+ * clamping (and should enable scrolling). Informational only — the
84
+ * controller no longer writes `max-height` itself.
85
+ */
86
+ isConstrained: boolean;
87
+ /**
88
+ * Natural floating-element height from the first un-constrained compute,
89
+ * used as the baseline that determines whether subsequent computes are
90
+ * clamping content. Cleared on `stop()`.
91
+ */
92
+ private initialHeight?;
93
+ /**
94
+ * Last placement handed to `onPlacementChange`. `actualPlacement` is refreshed
95
+ * on every compute, but the callback fires only when the computed placement
96
+ * actually changes — `autoUpdate` ticks that recompute the same placement do
97
+ * not re-notify consumers. `undefined` until the first compute (and after
98
+ * `stop`), so the first compute of a session always notifies.
99
+ */
100
+ private lastEmittedPlacement?;
101
+ /**
102
+ * Registers this controller on `host` via `addController`.
103
+ *
104
+ * @param host - Reactive element that owns the floating surface lifecycle.
105
+ */
106
+ constructor(host: ReactiveControllerHost);
107
+ /**
108
+ * Begin positioning `floating` relative to `trigger`.
109
+ *
110
+ * Tears down any prior session, stores the new options, and subscribes to
111
+ * Floating UI `autoUpdate` so placement stays correct on scroll and resize.
112
+ *
113
+ * @param trigger - Anchor element or `VirtualTrigger`.
114
+ * @param floating - Element to position (`position: fixed` or top-layer).
115
+ * @param options - `PlacementOptions`; omitted properties use defaults.
116
+ */
117
+ start(trigger: HTMLElement | VirtualTrigger, floating: HTMLElement, options?: PlacementOptions): void;
118
+ /**
119
+ * Stop positioning: tear down `autoUpdate`, clear `actualPlacement` and
120
+ * `isConstrained`. Inline style cleanup — including `translate`, `top`,
121
+ * `left`, and `--swc-placement-available-*` — is left to the caller so
122
+ * exit transitions can complete before those properties are removed.
123
+ * Safe to call multiple times.
124
+ */
125
+ stop(): void;
126
+ /**
127
+ * Force one recomputation outside the `autoUpdate` callback.
128
+ *
129
+ * Use when floating content reflows internally or when a
130
+ * `VirtualTrigger` moves without a DOM mutation. No-op if
131
+ * `start` has not been called.
132
+ */
133
+ recompute(): void;
134
+ /**
135
+ * Lit lifecycle hook — tears down positioning when the host disconnects.
136
+ *
137
+ * @internal
138
+ */
139
+ hostDisconnected(): void;
140
+ /**
141
+ * Run Floating UI `computePosition`, apply the result to the floating element,
142
+ * and update `actualPlacement` when `flip` reorients.
143
+ *
144
+ * Waits for web fonts and a WebKit animation frame before measuring. Skips
145
+ * when the floating element has zero dimensions. Aborts if `stop` or a
146
+ * new `start` call replaces the active session while awaiting async work.
147
+ */
148
+ private computePlacement;
149
+ }
150
+ export type { Placement, PlacementOptions, VirtualTrigger } from './types.js';
151
+ export { ALL_PLACEMENTS } from './types.js';
152
+ export { fromFloatingPlacement, toFloatingPlacement, } from './placement-conversion.js';
@@ -0,0 +1,129 @@
1
+ import { getFallbackPlacements as e } from "./fallback-placements.js";
2
+ import { fromFloatingPlacement as t, toFloatingPlacement as n } from "./placement-conversion.js";
3
+ import "./types.js";
4
+ import { arrow as r, autoUpdate as i, computePosition as a, flip as o, offset as s, shift as c, size as l } from "@floating-ui/dom";
5
+ //#region controllers/placement-controller/src/placement-controller.ts
6
+ var u = 100, d = "bottom", f = 0, p = 0, m = 8, h = !0, g = 8;
7
+ function _(e) {
8
+ let t = window.devicePixelRatio || 1;
9
+ return Math.round(e * t) / t;
10
+ }
11
+ function v() {
12
+ if (typeof navigator > "u") return !1;
13
+ let e = navigator.userAgent;
14
+ return /AppleWebKit/.test(e) && !/Chrome/.test(e);
15
+ }
16
+ var y = class {
17
+ constructor(e) {
18
+ this.session = null, this.actualPlacement = null, this.isConstrained = !1, e.addController(this);
19
+ }
20
+ start(e, t, n = {}) {
21
+ var r;
22
+ this.stop();
23
+ let a = {
24
+ trigger: e,
25
+ floating: t,
26
+ options: n,
27
+ isWebKit: v()
28
+ };
29
+ this.session = a, this.actualPlacement = (r = n.placement) == null ? d : r;
30
+ let o = i(e, t, () => {
31
+ this.computePlacement();
32
+ }), s, c = window.visualViewport;
33
+ if (a.isWebKit && c) {
34
+ let e = 0, t = !1, n = () => {
35
+ t || e || (e = requestAnimationFrame(() => {
36
+ e = 0, !t && this.computePlacement();
37
+ }));
38
+ };
39
+ c.addEventListener("resize", n, { passive: !0 }), c.addEventListener("scroll", n, { passive: !0 }), s = () => {
40
+ t = !0, e && (cancelAnimationFrame(e), e = 0), c.removeEventListener("resize", n), c.removeEventListener("scroll", n);
41
+ };
42
+ }
43
+ let l = e instanceof HTMLElement ? e : t, u = new MutationObserver(() => {
44
+ this.computePlacement();
45
+ }), f = (e) => {
46
+ e && u.observe(e, {
47
+ attributes: !0,
48
+ attributeFilter: ["dir"]
49
+ });
50
+ };
51
+ f(l.ownerDocument.documentElement), f(l.closest("[dir]")), this.cleanup = () => {
52
+ u.disconnect(), s == null || s(), o();
53
+ };
54
+ }
55
+ stop() {
56
+ var e;
57
+ (e = this.cleanup) == null || e.call(this), this.cleanup = void 0, this.session = null, this.actualPlacement = null, this.isConstrained = !1, this.initialHeight = void 0, this.lastEmittedPlacement = void 0;
58
+ }
59
+ recompute() {
60
+ this.computePlacement();
61
+ }
62
+ hostDisconnected() {
63
+ this.stop();
64
+ }
65
+ async computePlacement() {
66
+ var i, v, y, b, x, S;
67
+ let C = this.session;
68
+ if (!C) return;
69
+ let { trigger: w, floating: T, options: E } = C;
70
+ if (document.fonts && await document.fonts.ready, this.session !== C || C.isWebKit && (await new Promise((e) => requestAnimationFrame(() => e())), this.session !== C)) return;
71
+ let D = T.getBoundingClientRect();
72
+ if (D.width === 0 && D.height === 0) return;
73
+ let O = (i = E.placement) == null ? d : i, k = w instanceof HTMLElement ? w : T, A = n(O, getComputedStyle(k).direction === "rtl" ? "rtl" : "ltr"), j = (v = E.containerPadding) == null ? m : v, M = (y = E.shouldFlip) == null ? h : y, N = (b = E.offset) == null ? f : b, P = (x = E.crossOffset) == null ? p : x, F = M && (w instanceof HTMLElement ? o({
74
+ padding: j,
75
+ fallbackStrategy: "bestFit"
76
+ }) : o({
77
+ padding: j,
78
+ fallbackPlacements: e(A),
79
+ fallbackStrategy: "bestFit"
80
+ })), I = E.tipElement, L = (S = E.tipPadding) == null ? g : S, { x: R, y: z, placement: B, middlewareData: V } = await a(w, T, {
81
+ placement: A,
82
+ middleware: [
83
+ s({
84
+ mainAxis: N,
85
+ crossAxis: P
86
+ }),
87
+ c({ padding: j }),
88
+ F,
89
+ l({
90
+ padding: j,
91
+ apply: ({ availableHeight: e, availableWidth: t, rects: n }) => {
92
+ var r;
93
+ if (this.session !== C) return;
94
+ let i = Math.max(u, Math.floor(e)), a = n.floating.height;
95
+ this.initialHeight = this.isConstrained ? (r = this.initialHeight) == null ? a : r : a, this.isConstrained = a < this.initialHeight || i <= a, T.style.setProperty("--swc-placement-available-width", `${Math.floor(t)}px`), T.style.setProperty("--swc-placement-available-height", `${i}px`);
96
+ }
97
+ }),
98
+ I ? r({
99
+ element: I,
100
+ padding: L
101
+ }) : null
102
+ ],
103
+ strategy: "absolute"
104
+ });
105
+ if (this.session !== C) return;
106
+ let H = R, U = z, W = window.visualViewport;
107
+ if (W && C.isWebKit && (H -= W.offsetLeft, U -= W.offsetTop), Object.assign(T.style, {
108
+ top: "0px",
109
+ left: "0px",
110
+ translate: `${_(H)}px ${_(U)}px`
111
+ }), I && V.arrow) {
112
+ let { x: e, y: t } = V.arrow;
113
+ Object.assign(I.style, {
114
+ top: B.startsWith("right") || B.startsWith("left") ? "0px" : "",
115
+ left: B.startsWith("bottom") || B.startsWith("top") ? "0px" : "",
116
+ translate: `${_(e == null ? 0 : e)}px ${_(t == null ? 0 : t)}px`
117
+ });
118
+ }
119
+ let G = t(B);
120
+ if (this.actualPlacement = G, G !== this.lastEmittedPlacement) {
121
+ var K;
122
+ this.lastEmittedPlacement = G, (K = E.onPlacementChange) == null || K.call(E, G);
123
+ }
124
+ }
125
+ };
126
+ //#endregion
127
+ export { y as PlacementController };
128
+
129
+ //# sourceMappingURL=placement-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placement-controller.js","names":[],"sources":["../../../../controllers/placement-controller/src/placement-controller.ts"],"sourcesContent":["/**\n * Copyright 2026 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport {\n arrow,\n autoUpdate,\n computePosition,\n flip,\n offset,\n shift,\n size,\n} from '@floating-ui/dom';\n\nimport { getFallbackPlacements } from './fallback-placements.js';\nimport {\n fromFloatingPlacement,\n toFloatingPlacement,\n} from './placement-conversion.js';\nimport type { Placement, PlacementOptions, VirtualTrigger } from './types.js';\n\n/** Minimum height the `size` middleware will allow the floating content to clamp to. */\nconst MIN_FLOATING_HEIGHT = 100;\n\nconst DEFAULT_PLACEMENT: Placement = 'bottom';\n// Neutral default — controller does not impose a trigger gap. Consuming\n// components set their own pattern-specific default.\nconst DEFAULT_OFFSET = 0;\nconst DEFAULT_CROSS_OFFSET = 0;\nconst DEFAULT_CONTAINER_PADDING = 8;\nconst DEFAULT_SHOULD_FLIP = true;\nconst DEFAULT_TIP_PADDING = 8;\n\n/**\n * Round a pixel value to the nearest device-pixel boundary so translated\n * coordinates stay sharp on high-DPR displays.\n *\n * @param num - Coordinate in CSS pixels.\n * @returns The value rounded to the nearest physical pixel.\n */\nfunction roundByDPR(num: number): number {\n const dpr = window.devicePixelRatio || 1;\n return Math.round(num * dpr) / dpr;\n}\n\n/**\n * Detect WebKit-based browsers (Safari, iOS) where `visualViewport` offset\n * correction is required after `computePosition`.\n *\n * @returns True when the runtime appears to be WebKit without Chrome.\n */\nfunction isWebKit(): boolean {\n if (typeof navigator === 'undefined') {\n return false;\n }\n const ua = navigator.userAgent;\n return /AppleWebKit/.test(ua) && !/Chrome/.test(ua);\n}\n\ntype ActiveSession = {\n trigger: HTMLElement | VirtualTrigger;\n floating: HTMLElement;\n options: PlacementOptions;\n\n /**\n * Cached `isWebKit()` result so `computePlacement` doesn't run a UA\n * regex per `autoUpdate` tick.\n */\n isWebKit: boolean;\n};\n\n/**\n * **PlacementController** — Lit reactive controller that positions a floating\n * element relative to a trigger using [Floating UI](https://floating-ui.com/)\n * (`computePosition` + `autoUpdate`).\n *\n * Hyphenated placements are accepted on the public API. Logical sides\n * (`start`, `end`) resolve to physical sides against the trigger's computed\n * writing direction (`start` is the left in LTR, the right in RTL), so the\n * panel lands on the correct side. Logical alignment suffixes (`bottom-start`)\n * are left for Floating UI's own RTL handling; the consumer's CSS still owns\n * direction-aware styling such as tip orientation. A `dir` change on the\n * document root or the trigger's nearest `[dir]` ancestor recomputes\n * placement, so runtime LTR/RTL flips re-resolve correctly.\n *\n * ### Available-space custom properties\n *\n * The `size` middleware does **not** write `max-width` / `max-height` on the\n * floating element — an inline max-size would override the consuming\n * component's intended CSS max-size. Instead it exposes the space available to\n * the trigger as two custom properties on the floating element, refreshed on\n * every compute. The caller removes them after any exit transition completes\n * (clearing them in `stop()` would snap the floating element's size\n * mid-animation):\n *\n * - `--swc-placement-available-width` — usable inline space, in px.\n * - `--swc-placement-available-height` — usable block space, in px (floored to\n * a minimum so a cramped trigger still yields a usable panel).\n *\n * Only components positioned by this controller receive these properties.\n * Such a component opts into viewport-bounded sizing by combining them with\n * its own intended size via `min()`, with a fallback for when the controller\n * is not active:\n *\n * ```css\n * .floating {\n * box-sizing: border-box;\n * max-inline-size: min(var(--intended-width), var(--swc-placement-available-width, 100vi));\n * max-block-size: min(var(--intended-height), var(--swc-placement-available-height, 90vb));\n * overflow: auto;\n * }\n * ```\n *\n * The fallbacks use logical viewport units (`vi` / `vb`); `90vb` leaves a small\n * buffer so the trigger isn't scrolled out of view. `box-sizing: border-box` is\n * required so the available-space values account for the element's own padding\n * and border rather than overflowing past them. Pair `max-block-size` with\n * `overflow: auto` so the panel scrolls when the block space is constrained\n * (read `isConstrained` to detect that state).\n *\n * @example\n * ```typescript\n * this.placement.start(this.trigger, this.dialog, {\n * placement: 'bottom-start',\n * offset: 0,\n * onPlacementChange: (p) => {\n * this.actualPlacement = p;\n * },\n * });\n * ```\n */\nexport class PlacementController implements ReactiveController {\n private cleanup?: () => void;\n private session: ActiveSession | null = null;\n\n /**\n * The computed placement after `flip` reorients (hyphenated). `null` when\n * `stop` has been called.\n *\n * Set synchronously to the requested `PlacementOptions.placement`\n * (or `DEFAULT_PLACEMENT`) when `start` is called, then refreshed on every\n * successful `computePlacement` pass. `PlacementOptions.onPlacementChange`\n * fires when this value changes (and once after the first compute), so\n * consumers can mirror it in a single callback without also reading it\n * synchronously after `start()`.\n */\n public actualPlacement: Placement | null = null;\n\n /**\n * Whether the floating content would overflow the available space\n * below/above the trigger on the last compute. `true` when the content is\n * taller than the available height, so a consumer applying\n * `max-block-size: min(…, var(--swc-placement-available-height))` will be\n * clamping (and should enable scrolling). Informational only — the\n * controller no longer writes `max-height` itself.\n */\n public isConstrained = false;\n\n /**\n * Natural floating-element height from the first un-constrained compute,\n * used as the baseline that determines whether subsequent computes are\n * clamping content. Cleared on `stop()`.\n */\n private initialHeight?: number;\n\n /**\n * Last placement handed to `onPlacementChange`. `actualPlacement` is refreshed\n * on every compute, but the callback fires only when the computed placement\n * actually changes — `autoUpdate` ticks that recompute the same placement do\n * not re-notify consumers. `undefined` until the first compute (and after\n * `stop`), so the first compute of a session always notifies.\n */\n private lastEmittedPlacement?: Placement;\n\n /**\n * Registers this controller on `host` via `addController`.\n *\n * @param host - Reactive element that owns the floating surface lifecycle.\n */\n constructor(host: ReactiveControllerHost) {\n host.addController(this);\n }\n\n /**\n * Begin positioning `floating` relative to `trigger`.\n *\n * Tears down any prior session, stores the new options, and subscribes to\n * Floating UI `autoUpdate` so placement stays correct on scroll and resize.\n *\n * @param trigger - Anchor element or `VirtualTrigger`.\n * @param floating - Element to position (`position: fixed` or top-layer).\n * @param options - `PlacementOptions`; omitted properties use defaults.\n */\n public start(\n trigger: HTMLElement | VirtualTrigger,\n floating: HTMLElement,\n options: PlacementOptions = {}\n ) {\n this.stop();\n const session: ActiveSession = {\n trigger,\n floating,\n options,\n isWebKit: isWebKit(),\n };\n this.session = session;\n this.actualPlacement = options.placement ?? DEFAULT_PLACEMENT;\n\n // Single `autoUpdate` channel — receives `ancestorScroll`,\n // `ancestorResize`, `elementResize`, and `layoutShift` by default. The\n // controller owns geometry only and just repositions on every event;\n // the caller decides whether ancestor scroll should close the surface.\n const autoUpdateCleanup = autoUpdate(trigger, floating, () => {\n this.computePlacement();\n });\n\n // iOS WebKit `visualViewport` recompute channel. Floating UI's\n // `autoUpdate` doesn't observe `window.visualViewport`, so without this\n // an open floating element can drift away from its trigger on WebKit\n // (iOS Safari, WKWebView, desktop Safari while pinch-zoomed) when the\n // URL bar shows/hides, the virtual keyboard opens, etc. — until the\n // next event `autoUpdate` does observe. Listeners are passive and\n // rAF-coalesced so a burst of resize/scroll events compresses to one\n // compute per frame. The matching `visualViewport.offset*` correction\n // lives in `computePlacement`.\n let visualViewportCleanup: (() => void) | undefined;\n const visualViewport = window.visualViewport;\n if (session.isWebKit && visualViewport) {\n let rafId = 0;\n let cancelled = false;\n const onViewportChange = () => {\n if (cancelled || rafId) {\n return;\n }\n rafId = requestAnimationFrame(() => {\n rafId = 0;\n if (cancelled) {\n return;\n }\n this.computePlacement();\n });\n };\n visualViewport.addEventListener('resize', onViewportChange, {\n passive: true,\n });\n visualViewport.addEventListener('scroll', onViewportChange, {\n passive: true,\n });\n visualViewportCleanup = () => {\n cancelled = true;\n if (rafId) {\n cancelAnimationFrame(rafId);\n rafId = 0;\n }\n visualViewport.removeEventListener('resize', onViewportChange);\n visualViewport.removeEventListener('scroll', onViewportChange);\n };\n }\n\n // Direction channel — `autoUpdate` watches layout, not the `dir` attribute,\n // so a runtime LTR/RTL flip (or a `dir` applied after the first compute)\n // wouldn't re-resolve logical `start` / `end` sides. Observe `dir` on the\n // document root and on the trigger's nearest `[dir]` ancestor, and\n // recompute when it changes.\n const directionSource = trigger instanceof HTMLElement ? trigger : floating;\n const directionObserver = new MutationObserver(() => {\n this.computePlacement();\n });\n const observeDir = (node: Element | null | undefined) => {\n if (node) {\n directionObserver.observe(node, {\n attributes: true,\n attributeFilter: ['dir'],\n });\n }\n };\n observeDir(directionSource.ownerDocument.documentElement);\n observeDir(directionSource.closest('[dir]'));\n\n this.cleanup = () => {\n directionObserver.disconnect();\n visualViewportCleanup?.();\n autoUpdateCleanup();\n };\n }\n\n /**\n * Stop positioning: tear down `autoUpdate`, clear `actualPlacement` and\n * `isConstrained`. Inline style cleanup — including `translate`, `top`,\n * `left`, and `--swc-placement-available-*` — is left to the caller so\n * exit transitions can complete before those properties are removed.\n * Safe to call multiple times.\n */\n public stop() {\n this.cleanup?.();\n this.cleanup = undefined;\n this.session = null;\n this.actualPlacement = null;\n this.isConstrained = false;\n this.initialHeight = undefined;\n this.lastEmittedPlacement = undefined;\n }\n\n /**\n * Force one recomputation outside the `autoUpdate` callback.\n *\n * Use when floating content reflows internally or when a\n * `VirtualTrigger` moves without a DOM mutation. No-op if\n * `start` has not been called.\n */\n public recompute() {\n this.computePlacement();\n }\n\n /**\n * Lit lifecycle hook — tears down positioning when the host disconnects.\n *\n * @internal\n */\n public hostDisconnected() {\n this.stop();\n }\n\n /**\n * Run Floating UI `computePosition`, apply the result to the floating element,\n * and update `actualPlacement` when `flip` reorients.\n *\n * Waits for web fonts and a WebKit animation frame before measuring. Skips\n * when the floating element has zero dimensions. Aborts if `stop` or a\n * new `start` call replaces the active session while awaiting async work.\n */\n private async computePlacement(): Promise<void> {\n const session = this.session;\n if (!session) {\n return;\n }\n\n const { trigger, floating, options } = session;\n\n if (document.fonts) {\n await document.fonts.ready;\n }\n if (this.session !== session) {\n return;\n }\n\n if (session.isWebKit) {\n await new Promise<void>((resolve) =>\n requestAnimationFrame(() => resolve())\n );\n if (this.session !== session) {\n return;\n }\n }\n\n const floatingRect = floating.getBoundingClientRect();\n if (floatingRect.width === 0 && floatingRect.height === 0) {\n return;\n }\n\n const requestedPlacement = options.placement ?? DEFAULT_PLACEMENT;\n // Resolve logical sides (`start` / `end`) against the trigger's writing\n // direction so RTL positions the panel on the correct physical side. Read\n // from the trigger (it lives in the consumer's possibly scoped-RTL subtree);\n // fall back to the floating element for a `VirtualTrigger`.\n const directionSource = trigger instanceof HTMLElement ? trigger : floating;\n const direction =\n getComputedStyle(directionSource).direction === 'rtl' ? 'rtl' : 'ltr';\n const floatingPlacement = toFloatingPlacement(\n requestedPlacement,\n direction\n );\n const containerPadding =\n options.containerPadding ?? DEFAULT_CONTAINER_PADDING;\n const shouldFlip = options.shouldFlip ?? DEFAULT_SHOULD_FLIP;\n const mainAxis = options.offset ?? DEFAULT_OFFSET;\n const crossAxis = options.crossOffset ?? DEFAULT_CROSS_OFFSET;\n\n const flipMiddleware =\n shouldFlip &&\n (!(trigger instanceof HTMLElement)\n ? flip({\n padding: containerPadding,\n fallbackPlacements: getFallbackPlacements(floatingPlacement),\n fallbackStrategy: 'bestFit',\n })\n : flip({\n padding: containerPadding,\n fallbackStrategy: 'bestFit',\n }));\n\n // Middleware order matches Gen1: offset → shift → flip → size → arrow.\n // `shift` runs before `flip` so the panel slides along the current\n // side before any decision to flip; `size` runs after the final\n // placement is known so it measures the available space accurately;\n // `arrow` (when a tip element is provided) runs last so it positions\n // the tip relative to the trigger after every other middleware has\n // settled.\n const tipElement = options.tipElement;\n const tipPadding = options.tipPadding ?? DEFAULT_TIP_PADDING;\n const middleware = [\n offset({ mainAxis, crossAxis }),\n shift({ padding: containerPadding }),\n flipMiddleware,\n size({\n padding: containerPadding,\n apply: ({ availableHeight, availableWidth, rects }) => {\n // Ignore a superseded compute: a new `start()` (or `stop()`) may\n // have replaced the session while this `computePosition` was in\n // flight, and writing baseline state here would bleed into it.\n if (this.session !== session) {\n return;\n }\n const maxHeight = Math.max(\n MIN_FLOATING_HEIGHT,\n Math.floor(availableHeight)\n );\n const actualHeight = rects.floating.height;\n // Track the natural (un-constrained) height on the first compute\n // so subsequent computes can detect whether content is currently\n // being clamped.\n this.initialHeight = !this.isConstrained\n ? actualHeight\n : (this.initialHeight ?? actualHeight);\n this.isConstrained =\n actualHeight < this.initialHeight || maxHeight <= actualHeight;\n // Expose the available space as custom properties rather than writing\n // `max-width` / `max-height` directly: an inline max-size would\n // override a component's intended CSS max-size, so instead each\n // component opts in by combining these with its own value, e.g.\n // `max-inline-size: min(<intended>, var(--swc-placement-available-width))`.\n floating.style.setProperty(\n '--swc-placement-available-width',\n `${Math.floor(availableWidth)}px`\n );\n floating.style.setProperty(\n '--swc-placement-available-height',\n `${maxHeight}px`\n );\n },\n }),\n tipElement ? arrow({ element: tipElement, padding: tipPadding }) : null,\n ];\n\n const { x, y, placement, middlewareData } = await computePosition(\n trigger,\n floating,\n {\n placement: floatingPlacement,\n middleware,\n strategy: 'absolute', // Required for correct top-layer element placement\n }\n );\n if (this.session !== session) {\n return;\n }\n\n let translateX = x;\n let translateY = y;\n const visualViewport = window.visualViewport;\n if (visualViewport && session.isWebKit) {\n translateX -= visualViewport.offsetLeft;\n translateY -= visualViewport.offsetTop;\n }\n\n Object.assign(floating.style, {\n top: '0px',\n left: '0px',\n translate: `${roundByDPR(translateX)}px ${roundByDPR(translateY)}px`,\n });\n\n // Position the tip element (Gen1 pattern). Floating UI exposes\n // either `arrow.x` (top/bottom placements — arrow on a horizontal\n // edge) or `arrow.y` (left/right placements — arrow on a vertical\n // edge). Reset whichever inline offset would conflict with the\n // edge we're on, then write the computed translate.\n if (tipElement && middlewareData.arrow) {\n const { x: arrowX, y: arrowY } = middlewareData.arrow;\n Object.assign(tipElement.style, {\n top:\n placement.startsWith('right') || placement.startsWith('left')\n ? '0px'\n : '',\n left:\n placement.startsWith('bottom') || placement.startsWith('top')\n ? '0px'\n : '',\n translate: `${roundByDPR(arrowX ?? 0)}px ${roundByDPR(arrowY ?? 0)}px`,\n });\n }\n\n const nextPlacement = fromFloatingPlacement(placement);\n this.actualPlacement = nextPlacement;\n // Notify on change only: `autoUpdate` recomputes on every scroll/resize\n // tick, but a consumer wiring `onPlacementChange` to reactive state should\n // not re-render when the placement is unchanged. The first compute always\n // fires (`lastEmittedPlacement` starts `undefined`).\n if (nextPlacement !== this.lastEmittedPlacement) {\n this.lastEmittedPlacement = nextPlacement;\n options.onPlacementChange?.(nextPlacement);\n }\n }\n}\n\nexport type { Placement, PlacementOptions, VirtualTrigger } from './types.js';\nexport { ALL_PLACEMENTS } from './types.js';\nexport {\n fromFloatingPlacement,\n toFloatingPlacement,\n} from './placement-conversion.js';\n"],"mappings":"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"}