@mhmo91/schmancy 0.10.28 → 0.10.30

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 (451) hide show
  1. package/custom-elements.json +7 -2
  2. package/dist/SchmancyElement-BQ4DFufc.js +300 -0
  3. package/dist/SchmancyElement-BQ4DFufc.js.map +1 -0
  4. package/dist/SchmancyElement-DhSiMp6Y.cjs +2 -0
  5. package/dist/SchmancyElement-DhSiMp6Y.cjs.map +1 -0
  6. package/dist/agent/{flow-3RrZM-e7.js.map → flow-CvG1fLW5.js.map} +1 -1
  7. package/dist/agent/schmancy.agent.js +7843 -3334
  8. package/dist/agent/schmancy.agent.js.map +1 -1
  9. package/dist/agent/schmancy.manifest.json +1 -2
  10. package/dist/agent/{vendor-material-color-33Mj762T.js.map → vendor-material-color-DcL7ZPxx.js.map} +1 -1
  11. package/dist/animation-CCOIW4wJ.cjs.map +1 -1
  12. package/dist/animation-DCznELuT.js.map +1 -1
  13. package/dist/{area-C_Yvjmad.js → area-BjpUWvzE.js} +7 -7
  14. package/dist/{area-C_Yvjmad.js.map → area-BjpUWvzE.js.map} +1 -1
  15. package/dist/area-CgTzkxah.cjs +21 -0
  16. package/dist/{area-BSVOYQDA.cjs.map → area-CgTzkxah.cjs.map} +1 -1
  17. package/dist/area.cjs +1 -1
  18. package/dist/area.js +1 -1
  19. package/dist/{audio-CxO5a2HL.js → audio-CwBJntnB.js} +1 -1
  20. package/dist/{audio-CxO5a2HL.js.map → audio-CwBJntnB.js.map} +1 -1
  21. package/dist/{audio-Cvmemu84.cjs → audio-DISBFOaR.cjs} +1 -1
  22. package/dist/{audio-Cvmemu84.cjs.map → audio-DISBFOaR.cjs.map} +1 -1
  23. package/dist/audio.cjs +1 -1
  24. package/dist/audio.js +2 -2
  25. package/dist/{autocomplete-B50VXUzw.cjs → autocomplete-DbCUOgWU.cjs} +2 -2
  26. package/dist/{autocomplete-B50VXUzw.cjs.map → autocomplete-DbCUOgWU.cjs.map} +1 -1
  27. package/dist/{autocomplete-C6I1mfOT.js → autocomplete-Dy708jem.js} +7 -7
  28. package/dist/{autocomplete-C6I1mfOT.js.map → autocomplete-Dy708jem.js.map} +1 -1
  29. package/dist/autocomplete.cjs +1 -1
  30. package/dist/autocomplete.js +1 -1
  31. package/dist/avatar.cjs +3 -3
  32. package/dist/avatar.cjs.map +1 -1
  33. package/dist/avatar.js +5 -5
  34. package/dist/avatar.js.map +1 -1
  35. package/dist/badge.cjs +1 -1
  36. package/dist/badge.js +1 -1
  37. package/dist/{boat-DVQBNkk5.cjs → boat-BzZN_iwp.cjs} +11 -11
  38. package/dist/{boat-DVQBNkk5.cjs.map → boat-BzZN_iwp.cjs.map} +1 -1
  39. package/dist/{boat-C94QZ4Zt.js → boat-Z4Lzl3ai.js} +8 -8
  40. package/dist/{boat-C94QZ4Zt.js.map → boat-Z4Lzl3ai.js.map} +1 -1
  41. package/dist/boat.cjs +1 -1
  42. package/dist/boat.js +1 -1
  43. package/dist/breadcrumb.cjs +4 -4
  44. package/dist/breadcrumb.cjs.map +1 -1
  45. package/dist/breadcrumb.js +7 -7
  46. package/dist/breadcrumb.js.map +1 -1
  47. package/dist/{busy--bNb42rM.js → busy-CRFGPkcP.js} +7 -7
  48. package/dist/{busy--bNb42rM.js.map → busy-CRFGPkcP.js.map} +1 -1
  49. package/dist/{busy-DuxFvEkY.cjs → busy-Cu-47DfN.cjs} +8 -8
  50. package/dist/{busy-DuxFvEkY.cjs.map → busy-Cu-47DfN.cjs.map} +1 -1
  51. package/dist/busy.cjs +1 -1
  52. package/dist/busy.js +1 -1
  53. package/dist/{button-DAFZ5A4O.cjs → button-CN_JTjRd.cjs} +15 -15
  54. package/dist/{button-DAFZ5A4O.cjs.map → button-CN_JTjRd.cjs.map} +1 -1
  55. package/dist/{button-B7b9L_h5.js → button-D_USF3tt.js} +10 -10
  56. package/dist/{button-B7b9L_h5.js.map → button-D_USF3tt.js.map} +1 -1
  57. package/dist/button.cjs +19 -19
  58. package/dist/button.cjs.map +1 -1
  59. package/dist/button.js +9 -9
  60. package/dist/button.js.map +1 -1
  61. package/dist/{card-DZPd24Sn.cjs → card-D4P5_gg9.cjs} +10 -10
  62. package/dist/{card-DZPd24Sn.cjs.map → card-D4P5_gg9.cjs.map} +1 -1
  63. package/dist/{card-ixzxOW-Q.js → card-DpN5KIYc.js} +15 -15
  64. package/dist/{card-ixzxOW-Q.js.map → card-DpN5KIYc.js.map} +1 -1
  65. package/dist/card.cjs +1 -1
  66. package/dist/card.js +1 -1
  67. package/dist/{checkbox-DdGpepTh.js → checkbox-C8ChypKf.js} +5 -5
  68. package/dist/{checkbox-DdGpepTh.js.map → checkbox-C8ChypKf.js.map} +1 -1
  69. package/dist/{checkbox-Bi_Fm2mf.cjs → checkbox-hhXVXDV1.cjs} +3 -3
  70. package/dist/{checkbox-Bi_Fm2mf.cjs.map → checkbox-hhXVXDV1.cjs.map} +1 -1
  71. package/dist/checkbox.cjs +1 -1
  72. package/dist/checkbox.js +1 -1
  73. package/dist/{chips-DLTynyVB.js → chips-B8R9q4yl.js} +27 -27
  74. package/dist/{chips-DLTynyVB.js.map → chips-B8R9q4yl.js.map} +1 -1
  75. package/dist/{chips-DWQMZErr.cjs → chips-BTLlO_Ow.cjs} +18 -18
  76. package/dist/{chips-DWQMZErr.cjs.map → chips-BTLlO_Ow.cjs.map} +1 -1
  77. package/dist/chips.cjs +1 -1
  78. package/dist/chips.js +2 -2
  79. package/dist/connectivity.cjs +7 -7
  80. package/dist/connectivity.cjs.map +1 -1
  81. package/dist/connectivity.js +5 -5
  82. package/dist/connectivity.js.map +1 -1
  83. package/dist/content-drawer.cjs +1 -1
  84. package/dist/content-drawer.js +1 -1
  85. package/dist/cursor-glow-Ah7VXSj7.js.map +1 -1
  86. package/dist/cursor-glow-Bulq-38P.cjs.map +1 -1
  87. package/dist/{date-range-DQpmMJH-.cjs → date-range-9h6ZSkZb.cjs} +3 -3
  88. package/dist/{date-range-DQpmMJH-.cjs.map → date-range-9h6ZSkZb.cjs.map} +1 -1
  89. package/dist/{date-range-CJ6MiTpF.js → date-range-CS96dWMh.js} +7 -7
  90. package/dist/{date-range-CJ6MiTpF.js.map → date-range-CS96dWMh.js.map} +1 -1
  91. package/dist/date-range-inline-CAxnHA-l.cjs +43 -0
  92. package/dist/{date-range-inline-nPWIs-3C.cjs.map → date-range-inline-CAxnHA-l.cjs.map} +1 -1
  93. package/dist/{date-range-inline-Ho3CENTh.js → date-range-inline-DCXdGeRv.js} +5 -5
  94. package/dist/{date-range-inline-Ho3CENTh.js.map → date-range-inline-DCXdGeRv.js.map} +1 -1
  95. package/dist/date-range-inline.cjs +1 -1
  96. package/dist/date-range-inline.js +1 -1
  97. package/dist/date-range.cjs +1 -1
  98. package/dist/date-range.js +1 -1
  99. package/dist/delay.cjs +4 -4
  100. package/dist/delay.cjs.map +1 -1
  101. package/dist/delay.js +6 -6
  102. package/dist/delay.js.map +1 -1
  103. package/dist/{details-BnRWMZdt.cjs → details-BC0IObBd.cjs} +2 -2
  104. package/dist/{details-BnRWMZdt.cjs.map → details-BC0IObBd.cjs.map} +1 -1
  105. package/dist/{details-CcMTvYo7.js → details-Pgd0slKn.js} +11 -11
  106. package/dist/{details-CcMTvYo7.js.map → details-Pgd0slKn.js.map} +1 -1
  107. package/dist/details.cjs +1 -1
  108. package/dist/details.js +1 -1
  109. package/dist/{directives-DgPbz0lQ.js → directives-B-RT9R2u.js} +3 -3
  110. package/dist/{directives-DgPbz0lQ.js.map → directives-B-RT9R2u.js.map} +1 -1
  111. package/dist/{directives-BkSqmLBV.cjs → directives-CFWacnWU.cjs} +1 -1
  112. package/dist/{directives-BkSqmLBV.cjs.map → directives-CFWacnWU.cjs.map} +1 -1
  113. package/dist/directives.cjs +1 -1
  114. package/dist/directives.js +2 -2
  115. package/dist/discovery.service-CIa3Eeuk.cjs.map +1 -1
  116. package/dist/discovery.service-DZFxtRwW.js.map +1 -1
  117. package/dist/{divider-CZCj0ioH.js → divider-BMzm0lOz.js} +5 -5
  118. package/dist/{divider-CZCj0ioH.js.map → divider-BMzm0lOz.js.map} +1 -1
  119. package/dist/{divider-C6yJSL1c.cjs → divider-D1OzaRAQ.cjs} +3 -3
  120. package/dist/{divider-C6yJSL1c.cjs.map → divider-D1OzaRAQ.cjs.map} +1 -1
  121. package/dist/divider.cjs +1 -1
  122. package/dist/divider.js +1 -1
  123. package/dist/dropdown.cjs +4 -4
  124. package/dist/dropdown.cjs.map +1 -1
  125. package/dist/dropdown.js +8 -8
  126. package/dist/dropdown.js.map +1 -1
  127. package/dist/{expand-Cc6ogXsR.js → expand-C0Uqxfv0.js} +10 -10
  128. package/dist/{expand-Cc6ogXsR.js.map → expand-C0Uqxfv0.js.map} +1 -1
  129. package/dist/{expand-D4EhwOYh.cjs → expand-CiQkzth9.cjs} +3 -3
  130. package/dist/{expand-D4EhwOYh.cjs.map → expand-CiQkzth9.cjs.map} +1 -1
  131. package/dist/expand.cjs +1 -1
  132. package/dist/expand.js +1 -1
  133. package/dist/float-Bu_IfKRd.cjs +1 -0
  134. package/dist/{float-B8EPc_OG.cjs.map → float-Bu_IfKRd.cjs.map} +1 -1
  135. package/dist/{float-BvI3HTtB.js → float-DwBMXhek.js} +2 -2
  136. package/dist/{float-BvI3HTtB.js.map → float-DwBMXhek.js.map} +1 -1
  137. package/dist/float.cjs +1 -1
  138. package/dist/float.js +1 -1
  139. package/dist/{form-FtYtZScl.js → form-B9Je2W_m.js} +15 -95
  140. package/dist/form-B9Je2W_m.js.map +1 -0
  141. package/dist/{form-SHg5FLsd.cjs → form-BnbAVZyf.cjs} +4 -19
  142. package/dist/form-BnbAVZyf.cjs.map +1 -0
  143. package/dist/form.cjs +18 -1
  144. package/dist/form.cjs.map +1 -0
  145. package/dist/form.js +93 -9
  146. package/dist/form.js.map +1 -0
  147. package/dist/gravity-6pL6CfIr.cjs.map +1 -1
  148. package/dist/gravity-sVK3zGBF.js.map +1 -1
  149. package/dist/handover/agent-runtime-followups.md +1 -1
  150. package/dist/handover/agent-runtime-v1.md +3 -3
  151. package/dist/hashContent-BqU6v1Xr.js.map +1 -1
  152. package/dist/hashContent-iRZJJWtE.cjs.map +1 -1
  153. package/dist/{icon-CgIXAvKI.cjs → icons-BfWQl5k5.cjs} +6 -6
  154. package/dist/icons-BfWQl5k5.cjs.map +1 -0
  155. package/dist/{icon-B1eZr2ZL.js → icons-DJHPXKgR.js} +4 -4
  156. package/dist/{icon-CgIXAvKI.cjs.map → icons-DJHPXKgR.js.map} +1 -1
  157. package/dist/icons.cjs +1 -1
  158. package/dist/icons.js +1 -1
  159. package/dist/{iframe-CmpAZc61.js → iframe-DLz8ll0s.js} +5 -5
  160. package/dist/{iframe-CmpAZc61.js.map → iframe-DLz8ll0s.js.map} +1 -1
  161. package/dist/{iframe-BO3BpRLH.cjs → iframe-UtczJypj.cjs} +5 -5
  162. package/dist/{iframe-BO3BpRLH.cjs.map → iframe-UtczJypj.cjs.map} +1 -1
  163. package/dist/iframe.cjs +1 -1
  164. package/dist/iframe.js +1 -1
  165. package/dist/index.cjs +1 -1
  166. package/dist/index.js +69 -69
  167. package/dist/{input-_Hft9vov.js → input-AQbBEj2f.js} +15 -15
  168. package/dist/{input-_Hft9vov.js.map → input-AQbBEj2f.js.map} +1 -1
  169. package/dist/{input-5YL2oUBr.cjs → input-Pp6A1m3s.cjs} +2 -2
  170. package/dist/{input-5YL2oUBr.cjs.map → input-Pp6A1m3s.cjs.map} +1 -1
  171. package/dist/{input-chip-DKMNpcED.cjs → input-chip-B5vYNuEm.cjs} +9 -9
  172. package/dist/{input-chip-DKMNpcED.cjs.map → input-chip-B5vYNuEm.cjs.map} +1 -1
  173. package/dist/{input-chip-BNTojQT6.js → input-chip-Bbs_gXOB.js} +10 -10
  174. package/dist/{input-chip-BNTojQT6.js.map → input-chip-Bbs_gXOB.js.map} +1 -1
  175. package/dist/input.cjs +1 -1
  176. package/dist/input.js +1 -1
  177. package/dist/json.cjs +3 -3
  178. package/dist/json.cjs.map +1 -1
  179. package/dist/json.js +5 -5
  180. package/dist/json.js.map +1 -1
  181. package/dist/kbd.cjs +2 -2
  182. package/dist/kbd.cjs.map +1 -1
  183. package/dist/kbd.js +5 -5
  184. package/dist/kbd.js.map +1 -1
  185. package/dist/{layout-DSAjo92m.js → layout-9K1zxhZn.js} +1 -1
  186. package/dist/{layout-DSAjo92m.js.map → layout-9K1zxhZn.js.map} +1 -1
  187. package/dist/{layout-eXb9wjDh.cjs → layout-B0dct--7.cjs} +1 -1
  188. package/dist/{layout-eXb9wjDh.cjs.map → layout-B0dct--7.cjs.map} +1 -1
  189. package/dist/layout.cjs +2 -2
  190. package/dist/layout.cjs.map +1 -1
  191. package/dist/layout.js +7 -7
  192. package/dist/layout.js.map +1 -1
  193. package/dist/lazy-CayEFyC3.cjs.map +1 -1
  194. package/dist/lazy-D-bO2r4m.js.map +1 -1
  195. package/dist/{lightbox-t4dvb8_A.cjs → lightbox-D_EizrG3.cjs} +21 -21
  196. package/dist/{lightbox-t4dvb8_A.cjs.map → lightbox-D_EizrG3.cjs.map} +1 -1
  197. package/dist/{lightbox-CKlYcnHV.js → lightbox-DmJTs2My.js} +9 -9
  198. package/dist/{lightbox-CKlYcnHV.js.map → lightbox-DmJTs2My.js.map} +1 -1
  199. package/dist/lightbox.cjs +1 -1
  200. package/dist/lightbox.js +1 -1
  201. package/dist/{list-21mWtDKg.cjs → list-BSn8czyO.cjs} +5 -5
  202. package/dist/{list-21mWtDKg.cjs.map → list-BSn8czyO.cjs.map} +1 -1
  203. package/dist/{list-B6QhxgRJ.js → list-DjSSRZxF.js} +12 -12
  204. package/dist/{list-B6QhxgRJ.js.map → list-DjSSRZxF.js.map} +1 -1
  205. package/dist/list.cjs +1 -1
  206. package/dist/list.js +1 -1
  207. package/dist/magnetic-B2VKNfDu.js.map +1 -1
  208. package/dist/magnetic-MQ3HMHJi.cjs.map +1 -1
  209. package/dist/{menu-C5qcgMnw.js → menu-CCVEde6u.js} +7 -7
  210. package/dist/{menu-C5qcgMnw.js.map → menu-CCVEde6u.js.map} +1 -1
  211. package/dist/menu-DTNnq7j_.cjs +23 -0
  212. package/dist/{menu-Cuxt5K4Y.cjs.map → menu-DTNnq7j_.cjs.map} +1 -1
  213. package/dist/menu.cjs +1 -1
  214. package/dist/menu.js +1 -1
  215. package/dist/mixins-BYfSDvbP.js +412 -0
  216. package/dist/mixins-BYfSDvbP.js.map +1 -0
  217. package/dist/mixins-YQI9JogS.cjs +245 -0
  218. package/dist/mixins-YQI9JogS.cjs.map +1 -0
  219. package/dist/mixins.cjs +1 -1
  220. package/dist/mixins.js +3 -2
  221. package/dist/nav-drawer.cjs +1 -1
  222. package/dist/nav-drawer.js +1 -1
  223. package/dist/navigation-bar.cjs +1 -1
  224. package/dist/navigation-bar.js +1 -1
  225. package/dist/navigation-rail.cjs +10 -10
  226. package/dist/navigation-rail.cjs.map +1 -1
  227. package/dist/navigation-rail.js +15 -15
  228. package/dist/navigation-rail.js.map +1 -1
  229. package/dist/{notification-CDKBKh63.js → notification-BNEuu3Q2.js} +7 -7
  230. package/dist/{notification-CDKBKh63.js.map → notification-BNEuu3Q2.js.map} +1 -1
  231. package/dist/notification-RhaYvA1I.cjs +24 -0
  232. package/dist/{notification-CcNoBFEJ.cjs.map → notification-RhaYvA1I.cjs.map} +1 -1
  233. package/dist/notification.cjs +1 -1
  234. package/dist/notification.js +1 -1
  235. package/dist/{option-BWfmDJvm.js → option-BLMYRy5C.js} +6 -6
  236. package/dist/{option-BWfmDJvm.js.map → option-BLMYRy5C.js.map} +1 -1
  237. package/dist/{option-DejeqOad.cjs → option-Dk7UFFlr.cjs} +5 -5
  238. package/dist/{option-DejeqOad.cjs.map → option-Dk7UFFlr.cjs.map} +1 -1
  239. package/dist/option.cjs +1 -1
  240. package/dist/option.js +1 -1
  241. package/dist/overlay-BbntqsVm.cjs +43 -0
  242. package/dist/overlay-BbntqsVm.cjs.map +1 -0
  243. package/dist/{overlay-D3c_NY18.js → overlay-CujzmLxg.js} +93 -144
  244. package/dist/overlay-CujzmLxg.js.map +1 -0
  245. package/dist/overlay-stack-Bdr9lOqi.cjs.map +1 -1
  246. package/dist/overlay-stack-D2rgxQLh.js.map +1 -1
  247. package/dist/overlay.cjs +1 -1
  248. package/dist/overlay.confirm-body-CMge0LP5.cjs +70 -0
  249. package/dist/overlay.confirm-body-CMge0LP5.cjs.map +1 -0
  250. package/dist/{overlay.confirm-body-B_v0ivkn.js → overlay.confirm-body-CRk4MvKh.js} +15 -27
  251. package/dist/overlay.confirm-body-CRk4MvKh.js.map +1 -0
  252. package/dist/overlay.js +3 -3
  253. package/dist/{overlay.service-B3FjXCqc.js → overlay.service-DnT4SBlJ.js} +31 -27
  254. package/dist/{overlay.service-B3FjXCqc.js.map → overlay.service-DnT4SBlJ.js.map} +1 -1
  255. package/dist/overlay.service-Dq5XtSEL.cjs +1 -0
  256. package/dist/{overlay.service-BkSeqXIv.cjs.map → overlay.service-Dq5XtSEL.cjs.map} +1 -1
  257. package/dist/{progress-6_rb3Ah9.cjs → progress-Bqd4DdOQ.cjs} +7 -7
  258. package/dist/{progress-6_rb3Ah9.cjs.map → progress-Bqd4DdOQ.cjs.map} +1 -1
  259. package/dist/{progress-CFcmO0wv.js → progress-Cu_wh6Sl.js} +10 -10
  260. package/dist/{progress-CFcmO0wv.js.map → progress-Cu_wh6Sl.js.map} +1 -1
  261. package/dist/progress.cjs +1 -1
  262. package/dist/progress.js +1 -1
  263. package/dist/radio-group-C8rUbYL6.cjs +19 -0
  264. package/dist/{radio-group-_WZg8EKM.cjs.map → radio-group-C8rUbYL6.cjs.map} +1 -1
  265. package/dist/{radio-group-Bd8y9QpX.js → radio-group-Duzgx17I.js} +7 -7
  266. package/dist/{radio-group-Bd8y9QpX.js.map → radio-group-Duzgx17I.js.map} +1 -1
  267. package/dist/radio-group.cjs +1 -1
  268. package/dist/radio-group.js +1 -1
  269. package/dist/range.cjs +2 -2
  270. package/dist/range.cjs.map +1 -1
  271. package/dist/range.js +5 -5
  272. package/dist/range.js.map +1 -1
  273. package/dist/reduced-motion-D-L12p7G.js.map +1 -1
  274. package/dist/reduced-motion-Ds-HjMzn.cjs.map +1 -1
  275. package/dist/rxjs-utils-Csnks202.cjs.map +1 -1
  276. package/dist/rxjs-utils-d-ivVN84.js.map +1 -1
  277. package/dist/search-DPKoC-dT.cjs.map +1 -1
  278. package/dist/search-MvIBA93K.js.map +1 -1
  279. package/dist/{select-Czpl1ztD.js → select-CzCv1f1c.js} +6 -6
  280. package/dist/{select-Czpl1ztD.js.map → select-CzCv1f1c.js.map} +1 -1
  281. package/dist/{select-BaioT3yY.cjs → select-DdqEsfnG.cjs} +2 -2
  282. package/dist/{select-BaioT3yY.cjs.map → select-DdqEsfnG.cjs.map} +1 -1
  283. package/dist/select.cjs +1 -1
  284. package/dist/select.js +1 -1
  285. package/dist/skeleton.cjs +2 -2
  286. package/dist/skeleton.cjs.map +1 -1
  287. package/dist/skeleton.js +5 -5
  288. package/dist/skeleton.js.map +1 -1
  289. package/dist/skills/form.md +34 -0
  290. package/dist/skills/schmancy/form.md +34 -0
  291. package/dist/slider.cjs +7 -7
  292. package/dist/slider.cjs.map +1 -1
  293. package/dist/slider.js +6 -6
  294. package/dist/slider.js.map +1 -1
  295. package/dist/{sound.service-v_jqCkos.js → sound.service-BOWTBG16.js} +1 -1
  296. package/dist/{sound.service-v_jqCkos.js.map → sound.service-BOWTBG16.js.map} +1 -1
  297. package/dist/{sound.service-DVJZb9ox.cjs → sound.service-BwIzAFQx.cjs} +1 -1
  298. package/dist/{sound.service-DVJZb9ox.cjs.map → sound.service-BwIzAFQx.cjs.map} +1 -1
  299. package/dist/{splash-screen-YtTVkJg8.js → splash-screen-Dj-zuGuB.js} +6 -6
  300. package/dist/{splash-screen-YtTVkJg8.js.map → splash-screen-Dj-zuGuB.js.map} +1 -1
  301. package/dist/splash-screen-_KhxgneW.cjs +41 -0
  302. package/dist/{splash-screen-3FtgdVy3.cjs.map → splash-screen-_KhxgneW.cjs.map} +1 -1
  303. package/dist/splash-screen.cjs +1 -1
  304. package/dist/splash-screen.js +1 -1
  305. package/dist/src-BSjgxN07.cjs +263 -0
  306. package/dist/{src-AYRNg63f.cjs.map → src-BSjgxN07.cjs.map} +1 -1
  307. package/dist/{src-DKMEgT2z.js → src-Curgs4Yp.js} +83 -83
  308. package/dist/{src-DKMEgT2z.js.map → src-Curgs4Yp.js.map} +1 -1
  309. package/dist/state-BthYuA3T.cjs +1 -0
  310. package/dist/state-BthYuA3T.cjs.map +1 -0
  311. package/dist/{state-CHbIt2Dw.js → state-E0bVrZ7q.js} +293 -279
  312. package/dist/state-E0bVrZ7q.js.map +1 -0
  313. package/dist/state.cjs +1 -1
  314. package/dist/state.js +3 -3
  315. package/dist/steps.cjs +10 -10
  316. package/dist/steps.cjs.map +1 -1
  317. package/dist/steps.js +9 -9
  318. package/dist/steps.js.map +1 -1
  319. package/dist/{surface-CVxyQPln.js → surface-C2TIedTq.js} +4 -4
  320. package/dist/{surface-CVxyQPln.js.map → surface-C2TIedTq.js.map} +1 -1
  321. package/dist/surface-D-GqzyLn.cjs +7 -0
  322. package/dist/{surface-BNvxLEDN.cjs.map → surface-D-GqzyLn.cjs.map} +1 -1
  323. package/dist/surface.cjs +1 -1
  324. package/dist/surface.js +1 -1
  325. package/dist/switch.cjs +2 -2
  326. package/dist/switch.cjs.map +1 -1
  327. package/dist/switch.js +6 -6
  328. package/dist/switch.js.map +1 -1
  329. package/dist/table.cjs +11 -11
  330. package/dist/table.cjs.map +1 -1
  331. package/dist/table.js +10 -10
  332. package/dist/table.js.map +1 -1
  333. package/dist/{tabs-CnPXvZuZ.js → tabs-CLRVe23a.js} +11 -11
  334. package/dist/{tabs-CnPXvZuZ.js.map → tabs-CLRVe23a.js.map} +1 -1
  335. package/dist/{tabs-DTU7748z.cjs → tabs-C_493iod.cjs} +4 -4
  336. package/dist/{tabs-DTU7748z.cjs.map → tabs-C_493iod.cjs.map} +1 -1
  337. package/dist/tabs.cjs +1 -1
  338. package/dist/tabs.js +1 -1
  339. package/dist/teleport.cjs +1 -1
  340. package/dist/teleport.js +1 -1
  341. package/dist/{textarea-mQPsppmd.js → textarea-BWEyOtPy.js} +9 -9
  342. package/dist/{textarea-mQPsppmd.js.map → textarea-BWEyOtPy.js.map} +1 -1
  343. package/dist/textarea-CICgd2oP.cjs +43 -0
  344. package/dist/{textarea-Bqth6Q8P.cjs.map → textarea-CICgd2oP.cjs.map} +1 -1
  345. package/dist/textarea.cjs +1 -1
  346. package/dist/textarea.js +1 -1
  347. package/dist/{theme-BJqpv4cG.js → theme-Bfg_H2AF.js} +12 -12
  348. package/dist/{theme-BJqpv4cG.js.map → theme-Bfg_H2AF.js.map} +1 -1
  349. package/dist/theme-D7zOJiyg.cjs +181 -0
  350. package/dist/{theme-D4HGKt7N.cjs.map → theme-D7zOJiyg.cjs.map} +1 -1
  351. package/dist/{theme-button-Jap7G_IH.js → theme-button-C53GdQER.js} +4 -4
  352. package/dist/{theme-button-Jap7G_IH.js.map → theme-button-C53GdQER.js.map} +1 -1
  353. package/dist/theme-button-DgeBcqFm.cjs +8 -0
  354. package/dist/{theme-button-LP-Dgr17.cjs.map → theme-button-DgeBcqFm.cjs.map} +1 -1
  355. package/dist/theme-button.cjs +1 -1
  356. package/dist/theme-button.js +1 -1
  357. package/dist/theme.cjs +1 -1
  358. package/dist/theme.interface-CSt7JUBD.cjs.map +1 -1
  359. package/dist/theme.interface-odQEpZZH.js.map +1 -1
  360. package/dist/theme.js +3 -3
  361. package/dist/{theme.service-Bh08uOSJ.js → theme.service-BqDuioYc.js} +1 -1
  362. package/dist/{theme.service-Bh08uOSJ.js.map → theme.service-BqDuioYc.js.map} +1 -1
  363. package/dist/{theme.service-Y-e8b331.cjs → theme.service-C3PoISGd.cjs} +1 -1
  364. package/dist/{theme.service-Y-e8b331.cjs.map → theme.service-C3PoISGd.cjs.map} +1 -1
  365. package/dist/tooltip.cjs.map +1 -1
  366. package/dist/tooltip.js.map +1 -1
  367. package/dist/tree.cjs +3 -3
  368. package/dist/tree.cjs.map +1 -1
  369. package/dist/tree.js +4 -4
  370. package/dist/tree.js.map +1 -1
  371. package/dist/types.cjs.map +1 -1
  372. package/dist/types.js.map +1 -1
  373. package/dist/typewriter.cjs.map +1 -1
  374. package/dist/typewriter.js.map +1 -1
  375. package/dist/{typography-Bc4MmSal.cjs → typography-B19fJ5YT.cjs} +4 -4
  376. package/dist/{typography-Bc4MmSal.cjs.map → typography-B19fJ5YT.cjs.map} +1 -1
  377. package/dist/{typography-BJMm6b0b.js → typography-CzbQv-X0.js} +10 -10
  378. package/dist/{typography-BJMm6b0b.js.map → typography-CzbQv-X0.js.map} +1 -1
  379. package/dist/typography.cjs +1 -1
  380. package/dist/typography.js +1 -1
  381. package/dist/utils-DTa3QHxk.cjs.map +1 -1
  382. package/dist/utils-H8wNknWC.js.map +1 -1
  383. package/dist/visually-hidden.cjs +2 -2
  384. package/dist/visually-hidden.cjs.map +1 -1
  385. package/dist/visually-hidden.js +4 -4
  386. package/dist/visually-hidden.js.map +1 -1
  387. package/dist/window-DXB53PuA.cjs +59 -0
  388. package/dist/{window-CNu_WnsY.cjs.map → window-DXB53PuA.cjs.map} +1 -1
  389. package/dist/{window-DZTjkE24.js → window-DpctMXiy.js} +9 -9
  390. package/dist/{window-DZTjkE24.js.map → window-DpctMXiy.js.map} +1 -1
  391. package/dist/window.cjs +1 -1
  392. package/dist/window.js +1 -1
  393. package/package.json +1 -1
  394. package/skills/schmancy/form.md +34 -0
  395. package/src/form/form.ts +5 -1
  396. package/src/overlay/overlay.animations.ts +0 -29
  397. package/src/overlay/overlay.component.ts +30 -38
  398. package/src/overlay/overlay.confirm-body.ts +3 -15
  399. package/src/overlay/overlay.layout.ts +11 -53
  400. package/src/overlay/overlay.stack.test.ts +113 -0
  401. package/src/overlay/overlay.types.ts +17 -11
  402. package/src/state/active-host.ts +50 -1
  403. package/src/state/index.ts +50 -11
  404. package/src/state/schmancy-context.ts +97 -88
  405. package/src/surface/surface.styles.ts +14 -10
  406. package/types/src/form/form.d.ts +1 -0
  407. package/types/src/overlay/overlay.confirm-body.d.ts +1 -1
  408. package/types/src/overlay/overlay.layout.d.ts +10 -30
  409. package/types/src/overlay/overlay.stack.test.d.ts +1 -0
  410. package/types/src/overlay/overlay.types.d.ts +17 -11
  411. package/types/src/state/active-host.d.ts +3 -0
  412. package/types/src/state/index.d.ts +16 -2
  413. package/types/src/state/schmancy-context.d.ts +2 -2
  414. package/dist/active-host-BP0zy_Y9.js +0 -63
  415. package/dist/active-host-BP0zy_Y9.js.map +0 -1
  416. package/dist/active-host-jH3iloCR.cjs +0 -1
  417. package/dist/active-host-jH3iloCR.cjs.map +0 -1
  418. package/dist/agent/overlay.confirm-body-BZoUgkdK.js +0 -4574
  419. package/dist/agent/overlay.confirm-body-BZoUgkdK.js.map +0 -1
  420. package/dist/area-BSVOYQDA.cjs +0 -21
  421. package/dist/date-range-inline-nPWIs-3C.cjs +0 -43
  422. package/dist/float-B8EPc_OG.cjs +0 -1
  423. package/dist/form-FtYtZScl.js.map +0 -1
  424. package/dist/form-SHg5FLsd.cjs.map +0 -1
  425. package/dist/icon-B1eZr2ZL.js.map +0 -1
  426. package/dist/menu-Cuxt5K4Y.cjs +0 -23
  427. package/dist/mixins-8dT5j6CS.js +0 -627
  428. package/dist/mixins-8dT5j6CS.js.map +0 -1
  429. package/dist/mixins-BF3Vj8_c.cjs +0 -242
  430. package/dist/mixins-BF3Vj8_c.cjs.map +0 -1
  431. package/dist/notification-CcNoBFEJ.cjs +0 -24
  432. package/dist/overlay-D3c_NY18.js.map +0 -1
  433. package/dist/overlay-Dv2utO4C.cjs +0 -43
  434. package/dist/overlay-Dv2utO4C.cjs.map +0 -1
  435. package/dist/overlay.confirm-body-B2ntyquG.cjs +0 -79
  436. package/dist/overlay.confirm-body-B2ntyquG.cjs.map +0 -1
  437. package/dist/overlay.confirm-body-B_v0ivkn.js.map +0 -1
  438. package/dist/overlay.service-BkSeqXIv.cjs +0 -1
  439. package/dist/radio-group-_WZg8EKM.cjs +0 -19
  440. package/dist/splash-screen-3FtgdVy3.cjs +0 -41
  441. package/dist/src-AYRNg63f.cjs +0 -263
  442. package/dist/state-CHbIt2Dw.js.map +0 -1
  443. package/dist/state-DcGj-pJJ.cjs +0 -1
  444. package/dist/state-DcGj-pJJ.cjs.map +0 -1
  445. package/dist/surface-BNvxLEDN.cjs +0 -7
  446. package/dist/textarea-Bqth6Q8P.cjs +0 -43
  447. package/dist/theme-D4HGKt7N.cjs +0 -181
  448. package/dist/theme-button-LP-Dgr17.cjs +0 -8
  449. package/dist/window-CNu_WnsY.cjs +0 -59
  450. /package/dist/agent/{flow-3RrZM-e7.js → flow-CvG1fLW5.js} +0 -0
  451. /package/dist/agent/{vendor-material-color-33Mj762T.js → vendor-material-color-DcL7ZPxx.js} +0 -0
package/src/form/form.ts CHANGED
@@ -16,7 +16,7 @@
16
16
  * etc.) via the `schema` property to get typed `submit` event detail.
17
17
  */
18
18
 
19
- import { html } from 'lit'
19
+ import { css, html } from 'lit'
20
20
  import { customElement, property, state } from 'lit/decorators.js'
21
21
  import { fromEvent, takeUntil } from 'rxjs'
22
22
  import { SchmancyElement } from '../../mixins'
@@ -48,6 +48,10 @@ export type SchmancyFormSubmitDetail<T = Record<string, FormDataEntryValue>> = {
48
48
  @customElement('schmancy-form')
49
49
  export default class SchmancyForm<TSchema extends ParseSchema | undefined = undefined>
50
50
  extends SchmancyElement {
51
+ static styles = css`
52
+ :host { display: block; }
53
+ `
54
+
51
55
  public static readonly tagName: string = 'schmancy-form'
52
56
 
53
57
  /**
@@ -154,35 +154,6 @@ export function surfaceAnimation(layout: OverlayLayout, direction: 'in' | 'out')
154
154
  }
155
155
 
156
156
  switch (layout) {
157
- case 'centered':
158
- // Anchor-origin bloom: scale 0.6 → 1 from the var-driven origin.
159
- // More aggressive than dialog's 0.92 because the origin carries the
160
- // spatial work, so less translate is needed. Caller sets the origin
161
- // vars via anchorOriginVars() before triggering this animation.
162
- return direction === 'in'
163
- ? {
164
- keyframes: [
165
- { opacity: 0, transform: 'scale(0.6)', transformOrigin: ORIGIN_CSS },
166
- { opacity: 1, transform: 'scale(1)', transformOrigin: ORIGIN_CSS },
167
- ],
168
- options: {
169
- duration: SPRING_SNAPPY.duration,
170
- easing: getEasing(SPRING_SNAPPY),
171
- fill: 'forwards',
172
- },
173
- }
174
- : {
175
- keyframes: [
176
- { opacity: 1, transform: 'scale(1)', transformOrigin: ORIGIN_CSS },
177
- { opacity: 0, transform: 'scale(0.95)', transformOrigin: ORIGIN_CSS },
178
- ],
179
- options: {
180
- duration: DURATION_EXIT,
181
- easing: getEasing(SPRING_SMOOTH),
182
- fill: 'forwards',
183
- },
184
- }
185
-
186
157
  case 'sheet':
187
158
  return direction === 'in'
188
159
  ? {
@@ -24,7 +24,6 @@ import {
24
24
  } from './overlay.animations'
25
25
  import { swipeToDismiss$ } from './overlay.gestures'
26
26
  import {
27
- readViewport,
28
27
  resolveAnchorRef,
29
28
  resolveLayout,
30
29
  type ResolvedAnchor,
@@ -35,6 +34,7 @@ import {
35
34
  positionFloatingUI,
36
35
  positionPopoverAPI,
37
36
  } from './overlay.positioning'
37
+ import { currentStack } from './overlay.stack'
38
38
  import type {
39
39
  Anchor,
40
40
  CloseReason,
@@ -98,7 +98,7 @@ export class SchmancyOverlay extends SchmancyElement {
98
98
  }
99
99
  `]
100
100
 
101
- @property({ type: String, reflect: true }) layout: OverlayLayout = 'centered'
101
+ @property({ type: String, reflect: true }) layout: OverlayLayout = 'sheet'
102
102
  @property({ type: Boolean, reflect: true }) dismissable = true
103
103
  @property({ type: Boolean, reflect: true }) modal = true
104
104
  @property({ type: String, reflect: true }) tier: OverlayTier = 'modal'
@@ -149,21 +149,11 @@ export class SchmancyOverlay extends SchmancyElement {
149
149
  if (!mount) throw new Error('schmancy-overlay: mount point missing')
150
150
  await mountContent(content, mount, options.props)
151
151
 
152
- // Measure content after mount for layout dispatch.
153
- const viewport = readViewport()
154
- const contentSize = {
155
- width: mount.scrollWidth,
156
- height: mount.scrollHeight,
157
- }
158
- this.layout = resolveLayout({
159
- anchor: options.anchor,
160
- content: contentSize,
161
- viewport,
162
- })
152
+ // Caller-forced layout (`as`) wins; otherwise resolver decides from anchor.
153
+ this.layout = options.as ?? resolveLayout({ anchor: options.anchor })
163
154
 
164
- // Modal defaults per layout, with the caller's `modal` as escape hatch.
165
- this.modal =
166
- options.modal ?? (this.layout === 'centered' || this.layout === 'sheet')
155
+ // Modal is derived from layout: sheet is always modal, anchored never is.
156
+ this.modal = this.layout === 'sheet'
167
157
 
168
158
  // Pick the positioning tier. Modal layouts always use the 'modal'
169
159
  // tier (custom shell + manual backdrop); anchored uses the CAPS-driven
@@ -264,11 +254,9 @@ export class SchmancyOverlay extends SchmancyElement {
264
254
  'bg-surface-container/85 text-surface-on backdrop-blur-md ' +
265
255
  'border border-surface-on/8'
266
256
  const layoutClasses =
267
- this.layout === 'centered'
268
- ? 'top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 max-w-[min(calc(100vw-2rem),560px)] max-h-[90dvh] rounded-3xl shadow-overlay'
269
- : this.layout === 'sheet'
270
- ? 'left-0 right-0 bottom-0 w-full max-h-[90dvh] rounded-t-[28px] shadow-overlay'
271
- : 'max-w-[min(480px,calc(100vw-2rem))] max-h-[90dvh] rounded-3xl shadow-overlay-anchored'
257
+ this.layout === 'sheet'
258
+ ? 'left-0 right-0 bottom-0 w-full max-h-[90dvh] rounded-t-[28px] shadow-overlay'
259
+ : 'max-w-[min(480px,calc(100vw-2rem))] max-h-[90dvh] rounded-3xl shadow-overlay-anchored'
272
260
  return html`
273
261
  <div class="shell fixed inset-0 pointer-events-none" part="shell">
274
262
  ${when(
@@ -301,11 +289,9 @@ export class SchmancyOverlay extends SchmancyElement {
301
289
  if (!surface) return
302
290
  const rect = surface.getBoundingClientRect()
303
291
  const vars =
304
- this.layout === 'centered' && !this._anchorOriginAnchor
305
- ? { '--schmancy-overlay-origin-x': '50%', '--schmancy-overlay-origin-y': '50%' }
306
- : this.layout === 'sheet' && !this._anchorOriginAnchor
307
- ? { '--schmancy-overlay-origin-x': '50%', '--schmancy-overlay-origin-y': '100%' }
308
- : anchorOriginVars(this._anchorOriginAnchor, rect)
292
+ this.layout === 'sheet' && !this._anchorOriginAnchor
293
+ ? { '--schmancy-overlay-origin-x': '50%', '--schmancy-overlay-origin-y': '100%' }
294
+ : anchorOriginVars(this._anchorOriginAnchor, rect)
309
295
  for (const [k, v] of Object.entries(vars)) {
310
296
  surface.style.setProperty(k, v)
311
297
  }
@@ -407,6 +393,19 @@ export class SchmancyOverlay extends SchmancyElement {
407
393
  const path = e.composedPath()
408
394
  if (this._surface && path.includes(this._surface)) return false
409
395
  if (this._resolvedAnchor?.el && path.includes(this._resolvedAnchor.el)) return false
396
+ // Suppress dismiss when the click lands inside any overlay that sits
397
+ // ABOVE this one in the stack (nested overlays sibling-appended to
398
+ // body). Read the stack fresh per pointerdown — it mutates as overlays
399
+ // open and close.
400
+ const stack = currentStack()
401
+ const myIndex = stack.findIndex((entry) => entry.element === this)
402
+ if (myIndex !== -1) {
403
+ for (let i = myIndex + 1; i < stack.length; i++) {
404
+ if (path.includes(stack[i].element)) return false
405
+ const aboveSurface = stack[i].element.shadowRoot?.querySelector('.surface')
406
+ if (aboveSurface && path.includes(aboveSurface)) return false
407
+ }
408
+ }
410
409
  return true
411
410
  }),
412
411
  map(() => ({ reason: 'backdrop' as CloseReason })),
@@ -464,14 +463,9 @@ export class SchmancyOverlay extends SchmancyElement {
464
463
  .subscribe((size) => this.maybeReResolve(size))
465
464
  }
466
465
 
467
- private async maybeReResolve(size: { w: number; h: number }): Promise<void> {
466
+ private async maybeReResolve(_size: { w: number; h: number }): Promise<void> {
468
467
  if (this._closing) return
469
- const viewport = readViewport()
470
- const next = resolveLayout({
471
- anchor: this._rawAnchor,
472
- content: { width: size.w, height: size.h },
473
- viewport,
474
- })
468
+ const next = resolveLayout({ anchor: this._rawAnchor })
475
469
  if (next === this.layout) return
476
470
  // Cooldown: prevent churn-driven bouncing.
477
471
  const now = performance.now()
@@ -592,9 +586,7 @@ function isLazy(x: unknown): x is LazyComponent {
592
586
  }
593
587
 
594
588
  function isUpwardTransition(from: OverlayLayout, to: OverlayLayout): boolean {
595
- // Upward ladder: centered < sheet. anchored sheet is also upward
596
- // (overflow went past threshold). anchored centered is NOT upward.
597
- if (from === 'centered' && to === 'sheet') return true
598
- if (from === 'anchored' && to === 'sheet') return true
599
- return false
589
+ // Anchored sheet is the only valid runtime transition (content
590
+ // overflowed and the surface re-resolves to a sheet). Sheet stays sheet.
591
+ return from === 'anchored' && to === 'sheet'
600
592
  }
@@ -7,7 +7,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'
7
7
  import { gravity } from '../directives/gravity'
8
8
  import type SchmancyInput from '../form/fields/input/input'
9
9
 
10
- import '../icons/icon'
10
+ import '../form/form'
11
11
  import '../form/fields/input/input'
12
12
  import '../typography/typography'
13
13
  import '../button/button'
@@ -30,7 +30,6 @@ export class SchmancyOverlayPromptBody extends SchmancyElement {
30
30
  display: block;
31
31
  min-width: 280px;
32
32
  max-width: 480px;
33
- padding: 1.5rem;
34
33
  }
35
34
  `]
36
35
 
@@ -99,19 +98,8 @@ export class SchmancyOverlayPromptBody extends SchmancyElement {
99
98
 
100
99
  protected render(): TemplateResult {
101
100
  return html`
102
- <form @submit=${this.handleSubmit}>
101
+ <schmancy-form @submit=${this.handleSubmit} class="p-6">
103
102
  <div class="flex flex-col gap-3">
104
- ${when(
105
- this.variant === 'danger',
106
- () => html`
107
- <schmancy-icon
108
- ${gravity({ delay: 0, mass: 0.7 })}
109
- class="text-error-default"
110
- style="font-size:32px"
111
- >error_outline</schmancy-icon>
112
- `,
113
- )}
114
-
115
103
  ${when(
116
104
  this.heading,
117
105
  () => html`
@@ -192,7 +180,7 @@ export class SchmancyOverlayPromptBody extends SchmancyElement {
192
180
  color=${this.variant === 'danger' ? 'error' : 'primary'}
193
181
  >${this.confirmText}</schmancy-button>
194
182
  </div>
195
- </form>
183
+ </schmancy-form>
196
184
  `
197
185
  }
198
186
  }
@@ -9,70 +9,28 @@ import type { Anchor, OverlayLayout, VirtualAnchor } from './overlay.types'
9
9
  * "thresholds ARE the policy").
10
10
  */
11
11
 
12
- /** Below this viewport width, every overlay becomes a bottom sheet. */
13
- export const NARROW_VIEWPORT_PX = 640
14
-
15
- /** Content taller than this fraction of viewport height → sheet. */
16
- export const TALL_CONTENT_FRACTION = 0.8
17
-
18
- /** Content wider than this fraction of viewport width → sheet. */
19
- export const WIDE_CONTENT_FRACTION = 0.9
20
-
21
12
  /** Floating UI / CSS anchor-positioning safety padding. */
22
13
  export const ANCHOR_FIT_PADDING_PX = 16
23
14
 
24
15
  export interface LayoutInputs {
25
16
  anchor?: Anchor
26
- content: { width: number; height: number }
27
- viewport: {
28
- width: number
29
- height: number
30
- /** `matchMedia('(pointer: coarse)').matches` at call time. */
31
- isCoarsePointer: boolean
32
- }
33
17
  }
34
18
 
35
19
  /**
36
- * Priority order:
37
- * 1. viewport / content forces sheet
38
- * 2. anchor provided → anchored (the novel default)
39
- * 3. fallbackcentered
20
+ * Two outcomes, one signal: anchor presence.
21
+ *
22
+ * - anchor provided → anchored (popover/menu/dropdown next to a trigger)
23
+ * - no anchor sheet (everything else: dialogs, takeovers, content panels)
40
24
  *
41
- * Floating UI's `flip` + `shift` + `size` middleware handles "anchor
42
- * doesn't fit initially" it returns a fitting position rather than
43
- * rejecting. So step 2 does NOT branch on "does the anchor fit?";
44
- * Floating UI's output IS the answer. If content is genuinely too
45
- * large for any anchored position, step 1 already routed to sheet.
25
+ * Callers who want to force a specific layout regardless of anchor pass
26
+ * `ShowOptions.as` the resolver is bypassed entirely in that case.
27
+ *
28
+ * Floating UI's `flip` + `shift` + `size` middleware handles "anchor doesn't
29
+ * fit initially" it returns a fitting position rather than rejecting. So
30
+ * anchored layouts don't need a fallback; Floating UI's output IS the answer.
46
31
  */
47
32
  export function resolveLayout(inputs: LayoutInputs): OverlayLayout {
48
- const { anchor, content, viewport } = inputs
49
-
50
- const isNarrow = viewport.width < NARROW_VIEWPORT_PX
51
- const isCoarse = viewport.isCoarsePointer
52
- const contentTall = content.height > viewport.height * TALL_CONTENT_FRACTION
53
- const contentWide = content.width > viewport.width * WIDE_CONTENT_FRACTION
54
-
55
- if (isNarrow || isCoarse || contentTall || contentWide) {
56
- return 'sheet'
57
- }
58
-
59
- if (anchor !== undefined) {
60
- return 'anchored'
61
- }
62
-
63
- return 'centered'
64
- }
65
-
66
- /**
67
- * Read the current viewport + pointer inputs. Separated so tests can
68
- * substitute synthetic inputs and the `resolveLayout` fn stays pure.
69
- */
70
- export function readViewport(): LayoutInputs['viewport'] {
71
- return {
72
- width: window.innerWidth,
73
- height: window.innerHeight,
74
- isCoarsePointer: window.matchMedia('(pointer: coarse)').matches,
75
- }
33
+ return inputs.anchor !== undefined ? 'anchored' : 'sheet'
76
34
  }
77
35
 
78
36
  /**
@@ -0,0 +1,113 @@
1
+ // overlay.stack.test.ts — unit tests for the stacked-overlay dismiss guard
2
+ //
3
+ // Exercises the outsideClick$ filter in SchmancyOverlay by driving the element
4
+ // state directly and calling wireCloseTriggers via type-cast. The test spies on
5
+ // close() so it doesn't need to wait for animation promises to settle.
6
+ //
7
+ // Uses the real browser DOM (vitest browser mode) so composedPath and
8
+ // shadow-DOM queries behave identically to production.
9
+
10
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
11
+ import './overlay.component'
12
+ import { clearStack, currentStack, pushEntry, removeEntry } from './overlay.stack'
13
+ import type { OverlayEntry } from './overlay.types'
14
+
15
+ const nextFrame = () => new Promise<void>(r => requestAnimationFrame(() => r()))
16
+
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ type AnyOverlay = any
19
+
20
+ function entryFor(element: HTMLElement, id: string): OverlayEntry {
21
+ return { id, element, layout: 'anchored', modal: false, tier: 'fui-only' }
22
+ }
23
+
24
+ // Patch the @query getter for _surface (read-only) so wireCloseTriggers reads it.
25
+ function patchSurface(overlay: AnyOverlay, surface: HTMLElement): void {
26
+ Object.defineProperty(overlay, '_surface', { get: () => surface, configurable: true })
27
+ }
28
+
29
+ // Stub close() so tests don't wait for animation promises.
30
+ function stubClose(overlay: AnyOverlay): ReturnType<typeof vi.fn> {
31
+ const spy = vi.fn().mockResolvedValue(undefined)
32
+ Object.defineProperty(overlay, 'close', { value: spy, configurable: true })
33
+ return spy
34
+ }
35
+
36
+ describe('overlay stacked-dismiss guard', () => {
37
+ beforeEach(() => clearStack())
38
+ afterEach(() => { clearStack(); vi.restoreAllMocks() })
39
+
40
+ it('single overlay: body click invokes close("backdrop") (baseline)', async () => {
41
+ const overlayA: AnyOverlay = document.createElement('schmancy-overlay')
42
+ document.body.appendChild(overlayA)
43
+ await nextFrame()
44
+
45
+ const fakesurf = document.createElement('div')
46
+ fakesurf.className = 'surface'
47
+ document.body.appendChild(fakesurf)
48
+ patchSurface(overlayA, fakesurf)
49
+
50
+ overlayA.tier = 'fui-only'
51
+ overlayA.dismissable = true
52
+ overlayA.modal = false
53
+
54
+ const closeSpy = stubClose(overlayA)
55
+
56
+ pushEntry(entryFor(overlayA, 'a'))
57
+ expect(currentStack()).toHaveLength(1)
58
+
59
+ overlayA.wireCloseTriggers()
60
+
61
+ // Dispatch on a separate span — not inside the overlay's surface.
62
+ const outside = document.createElement('span')
63
+ document.body.appendChild(outside)
64
+ outside.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, composed: true, cancelable: true }))
65
+ await nextFrame()
66
+
67
+ expect(closeSpy.mock.calls[0]?.[0]).toBe('backdrop')
68
+
69
+ outside.remove()
70
+ fakesurf.remove()
71
+ overlayA.remove()
72
+ removeEntry('a')
73
+ })
74
+
75
+ it('nested overlay: click inside overlay B does not close overlay A', async () => {
76
+ const overlayA: AnyOverlay = document.createElement('schmancy-overlay')
77
+ const overlayB: AnyOverlay = document.createElement('schmancy-overlay')
78
+ document.body.appendChild(overlayA)
79
+ document.body.appendChild(overlayB)
80
+ await nextFrame()
81
+
82
+ const surfA = document.createElement('div')
83
+ surfA.className = 'surface'
84
+ document.body.appendChild(surfA)
85
+ patchSurface(overlayA, surfA)
86
+
87
+ overlayA.tier = 'fui-only'
88
+ overlayA.dismissable = true
89
+ overlayA.modal = false
90
+
91
+ const closeSpy = stubClose(overlayA)
92
+
93
+ // Register A first, then B on top.
94
+ pushEntry(entryFor(overlayA, 'a'))
95
+ pushEntry(entryFor(overlayB, 'b'))
96
+ expect(currentStack()).toHaveLength(2)
97
+
98
+ overlayA.wireCloseTriggers()
99
+
100
+ // Dispatch a pointerdown on overlayB — its host element IS in composedPath.
101
+ overlayB.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, composed: true, cancelable: true }))
102
+ await nextFrame()
103
+
104
+ // A must not have been closed.
105
+ expect(closeSpy).not.toHaveBeenCalled()
106
+
107
+ surfA.remove()
108
+ overlayA.remove()
109
+ overlayB.remove()
110
+ removeEntry('a')
111
+ removeEntry('b')
112
+ })
113
+ })
@@ -97,11 +97,11 @@ export interface ShowOptions {
97
97
  * dismisses (same as unsubscribe). */
98
98
  signal?: AbortSignal
99
99
 
100
- /** Rare escape hatch. Defaults: `false` for anchored, `true` for
101
- * centered/sheet. Setting `modal: true` on an anchored overlay forces
102
- * <dialog>.showModal() semantics (focus trap + background inert)
103
- * use for destructive-confirm menus. */
104
- modal?: boolean
100
+ /** Override the resolved layout. When set, short-circuits the resolver
101
+ * and forces this layout. Use when the caller knows the content's nature
102
+ * better than the resolver can e.g. `as: 'sheet'` for an immersive
103
+ * takeover view that doesn't have an anchor. */
104
+ as?: OverlayLayout
105
105
 
106
106
  /** Default `'push'`. Same vocabulary as `area.push()`.
107
107
  * - `'push'` — new history entry; back dismisses, forward re-opens.
@@ -129,14 +129,20 @@ export interface ShowOptions {
129
129
  }
130
130
 
131
131
  /**
132
- * Resolved layout. Pure output of the dispatch engine; callers never pick.
133
- * - `'centered'` — native <dialog>.showModal(), focus-trapped.
132
+ * Resolved layout. Two values:
134
133
  * - `'anchored'` — popover="auto" + CSS Anchor Positioning / Floating UI,
135
- * non-modal, background stays interactive.
136
- * - `'sheet'` — native <dialog>.showModal() as a bottom sheet,
137
- * swipe-to-dismiss, safe-area aware.
134
+ * non-modal, background stays interactive. Used when the
135
+ * caller passes an anchor (the novel default for menus,
136
+ * popovers, dropdowns).
137
+ * - `'sheet'` — bottom sheet (mobile) or modal panel (desktop) with
138
+ * swipe-to-dismiss, safe-area aware. The default for every
139
+ * non-anchored overlay — confirm/prompt, immersive content
140
+ * views, legal pages, takeovers.
141
+ *
142
+ * Callers can force a layout with `ShowOptions.as` — useful for an anchored
143
+ * trigger whose content should still render as a sheet, or vice versa.
138
144
  */
139
- export type OverlayLayout = 'centered' | 'anchored' | 'sheet'
145
+ export type OverlayLayout = 'anchored' | 'sheet'
140
146
 
141
147
  /**
142
148
  * Positioning tier an anchored overlay is using.
@@ -177,10 +177,59 @@ export function resolveActiveHost(): HTMLElement | undefined {
177
177
  return document.activeElement
178
178
  }
179
179
 
180
- // 4. undefined — caller falls back to module-scoped.
180
+ // 4. undefined — caller falls back to module-scoped (or ambient tier 5).
181
181
  return undefined
182
182
  }
183
183
 
184
+ // ---------------------------------------------------------------------------
185
+ // Tier 5 — Ambient provider registry.
186
+ //
187
+ // When exactly one <schmancy-context> provides a namespace and no active host
188
+ // is on the stack, state writes from async callbacks (Firestore onSnapshot,
189
+ // setTimeout, WebSocket handlers, etc.) automatically route to that isolated
190
+ // copy. No consumer-side _activeHost.run() boilerplate required.
191
+ //
192
+ // Ambiguity rule: if two or more contexts simultaneously provide the same
193
+ // namespace the entry is marked AMBIGUOUS and getAmbientProvider returns
194
+ // undefined — we fall through to the global rather than guess. Safe
195
+ // degradation: never silently write to the wrong isolated copy.
196
+ //
197
+ // Singleton across module copies via Symbol.for so source + dist share one map.
198
+ // ---------------------------------------------------------------------------
199
+ const AMBIENT_KEY = Symbol.for('schmancy.state.activeHost.ambientProviders')
200
+ type AmbientEntry = { instance: unknown; count: number }
201
+ const _ambientMap: Map<string, AmbientEntry> =
202
+ ((globalThis as { [AMBIENT_KEY]?: Map<string, AmbientEntry> })[AMBIENT_KEY] ??= new Map())
203
+
204
+ const AMBIGUOUS: unique symbol = Symbol('ambiguous')
205
+
206
+ export function registerAmbientProvider(namespace: string, instance: unknown): void {
207
+ const e = _ambientMap.get(namespace)
208
+ if (e) {
209
+ e.count++
210
+ e.instance = AMBIGUOUS
211
+ } else {
212
+ _ambientMap.set(namespace, { instance, count: 1 })
213
+ }
214
+ }
215
+
216
+ export function deregisterAmbientProvider(namespace: string): void {
217
+ const e = _ambientMap.get(namespace)
218
+ if (!e) return
219
+ if (e.count <= 1) {
220
+ _ambientMap.delete(namespace)
221
+ } else {
222
+ e.count--
223
+ // Once ambiguous, stays ambiguous until fully deregistered — we've lost
224
+ // the individual instance references so can't safely restore one.
225
+ }
226
+ }
227
+
228
+ export function getAmbientProvider(namespace: string): unknown | undefined {
229
+ const e = _ambientMap.get(namespace)
230
+ return e && e.instance !== AMBIGUOUS ? e.instance : undefined
231
+ }
232
+
184
233
  /** Stable context key for a state namespace. `Symbol.for(...)` so the same
185
234
  * namespace string yields the same symbol across module boundaries — the
186
235
  * ContextProvider on `<schmancy-context>` and the ContextRequestEvent
@@ -19,11 +19,11 @@ import { Signal } from '@lit-labs/signals'
19
19
  // `@lit/context` re-exports `ContextRequestEvent` as `ContextEvent` from
20
20
  // its public entry. Same class, just a shorter public name.
21
21
  import { ContextEvent as ContextRequestEvent, createContext } from '@lit/context'
22
- import { Observable } from 'rxjs'
22
+ import { Observable, type MonoTypeOperatorFunction } from 'rxjs'
23
23
  import { produce, type Draft } from 'immer'
24
24
 
25
25
  import { createAdapter, type StorageAdapter, type StorageBackend } from './persist'
26
- import { resolveActiveHost, stateContextKey } from './active-host'
26
+ import { _activeHost, getAmbientProvider, resolveActiveHost, stateContextKey } from './active-host'
27
27
  // Side-effect import: registers the `<schmancy-context>` element so users
28
28
  // only need to import from `@mhmo91/schmancy/state` to get both the factory
29
29
  // and the scoping primitive.
@@ -31,7 +31,7 @@ import './schmancy-context'
31
31
 
32
32
  export type { StorageBackend } from './persist'
33
33
  export { Signal } from '@lit-labs/signals'
34
- export { _activeHost } from './active-host'
34
+ export { _activeHost, registerAmbientProvider, deregisterAmbientProvider, getAmbientProvider } from './active-host'
35
35
  export { SchmancyContext } from './schmancy-context'
36
36
 
37
37
  // ---------------------------------------------------------------------------
@@ -253,7 +253,10 @@ const hostResolverCache = __cacheSlot[CACHE_KEY]!
253
253
 
254
254
  function resolveContextual(namespace: string, fallback: unknown): unknown {
255
255
  const host = resolveActiveHost()
256
- if (host === undefined) return fallback
256
+ if (host === undefined) {
257
+ const ambient = getAmbientProvider(namespace)
258
+ return ambient !== undefined ? ambient : fallback
259
+ }
257
260
 
258
261
  const cached = hostResolverCache.get(host)?.get(namespace)
259
262
  if (cached !== undefined) return cached
@@ -266,14 +269,25 @@ function resolveContextual(namespace: string, fallback: unknown): unknown {
266
269
  }),
267
270
  )
268
271
 
269
- const result = resolved !== undefined ? resolved : fallback
270
- let perHost = hostResolverCache.get(host)
271
- if (!perHost) {
272
- perHost = new Map<string, unknown>()
273
- hostResolverCache.set(host, perHost)
272
+ if (resolved !== undefined) {
273
+ // Real provider in the host's ancestor chain — safe to cache against
274
+ // the host: the binding lives as long as the host is connected.
275
+ let perHost = hostResolverCache.get(host)
276
+ if (!perHost) {
277
+ perHost = new Map<string, unknown>()
278
+ hostResolverCache.set(host, perHost)
279
+ }
280
+ perHost.set(namespace, resolved)
281
+ return resolved
274
282
  }
275
- perHost.set(namespace, result)
276
- return result
283
+
284
+ // Host exists (tier 1/2/3 found one) but it's not inside a schmancy-context
285
+ // for this namespace. Try the ambient registry before falling through to
286
+ // the global. Don't cache: the ambient provider can be unmounted while
287
+ // this host remains connected, which would leave a stale isolated copy
288
+ // pinned in the cache.
289
+ const ambient = getAmbientProvider(namespace)
290
+ return ambient !== undefined ? ambient : fallback
277
291
  }
278
292
 
279
293
  interface InternalState {
@@ -897,3 +911,28 @@ export function observe<T>(source: ObservableState<T>) {
897
911
  })
898
912
  }
899
913
  }
914
+
915
+
916
+ /**
917
+ * RxJS operator that restores `host` as the active schmancy context for every
918
+ * emission. Drop this into any pipeline whose subscriber calls state mutators
919
+ * from an async scheduler that bypasses the Promise.then patch (Firestore
920
+ * onSnapshot, WebSockets, native timers, etc.).
921
+ *
922
+ * ```ts
923
+ * snapshotDoc$(ref).pipe(
924
+ * schmancyContext(this),
925
+ * takeUntil(this.disconnecting),
926
+ * ).subscribe(snap => { ws.legalEntity.set(parse(snap)) })
927
+ * ```
928
+ */
929
+ export function schmancyContext<T>(host: HTMLElement): MonoTypeOperatorFunction<T> {
930
+ return (source) =>
931
+ new Observable<T>((subscriber) =>
932
+ source.subscribe({
933
+ next: (v) => _activeHost.run(host, () => subscriber.next(v)),
934
+ error: (e) => subscriber.error(e),
935
+ complete: () => subscriber.complete(),
936
+ }),
937
+ )
938
+ }