@mhmo91/schmancy 0.10.23 → 0.10.25

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 (438) hide show
  1. package/dist/agent/{overlay.confirm-body-xfOh5Q28.js → overlay.confirm-body-DozUyDYx.js} +242 -242
  2. package/dist/agent/{overlay.confirm-body-xfOh5Q28.js.map → overlay.confirm-body-DozUyDYx.js.map} +1 -1
  3. package/dist/agent/schmancy.agent.js +5670 -2939
  4. package/dist/agent/schmancy.agent.js.map +1 -1
  5. package/dist/{area-Ddk7P5wD.js → area-1EG1LrkX.js} +1 -1
  6. package/dist/{area-Ddk7P5wD.js.map → area-1EG1LrkX.js.map} +1 -1
  7. package/dist/{area-Cbkt0NX4.cjs → area-DrVE5pXW.cjs} +1 -1
  8. package/dist/{area-Cbkt0NX4.cjs.map → area-DrVE5pXW.cjs.map} +1 -1
  9. package/dist/area.cjs +1 -1
  10. package/dist/area.js +1 -1
  11. package/dist/{autocomplete-CfBFDSc3.cjs → autocomplete-6pdZxEab.cjs} +1 -1
  12. package/dist/{autocomplete-CfBFDSc3.cjs.map → autocomplete-6pdZxEab.cjs.map} +1 -1
  13. package/dist/{autocomplete-Ds3Q2cwR.js → autocomplete-nrIcCilw.js} +2 -2
  14. package/dist/{autocomplete-Ds3Q2cwR.js.map → autocomplete-nrIcCilw.js.map} +1 -1
  15. package/dist/autocomplete.cjs +1 -1
  16. package/dist/autocomplete.js +1 -1
  17. package/dist/avatar.cjs +2 -2
  18. package/dist/avatar.cjs.map +1 -1
  19. package/dist/avatar.js +3 -3
  20. package/dist/badge.cjs +1 -1
  21. package/dist/badge.js +1 -1
  22. package/dist/{boat-BF5P6p_f.js → boat--fLgbDAE.js} +3 -3
  23. package/dist/{boat-BF5P6p_f.js.map → boat--fLgbDAE.js.map} +1 -1
  24. package/dist/{boat-BPN8HLzZ.cjs → boat-BIB-gPqy.cjs} +1 -1
  25. package/dist/{boat-BPN8HLzZ.cjs.map → boat-BIB-gPqy.cjs.map} +1 -1
  26. package/dist/boat.cjs +1 -1
  27. package/dist/boat.js +1 -1
  28. package/dist/breadcrumb.cjs +1 -1
  29. package/dist/breadcrumb.js +1 -1
  30. package/dist/{busy-C7ejPa-Q.cjs → busy-DVCIxBVf.cjs} +1 -1
  31. package/dist/{busy-C7ejPa-Q.cjs.map → busy-DVCIxBVf.cjs.map} +1 -1
  32. package/dist/{busy-BuACDJy6.js → busy-DshZcVZ4.js} +1 -1
  33. package/dist/{busy-BuACDJy6.js.map → busy-DshZcVZ4.js.map} +1 -1
  34. package/dist/busy.cjs +1 -1
  35. package/dist/busy.js +1 -1
  36. package/dist/{button-C1IMGS6M.js → button-D9UJ7I6Z.js} +5 -5
  37. package/dist/{button-C1IMGS6M.js.map → button-D9UJ7I6Z.js.map} +1 -1
  38. package/dist/{button-CWNbPPq-.cjs → button-JrTMzwHY.cjs} +4 -4
  39. package/dist/{button-CWNbPPq-.cjs.map → button-JrTMzwHY.cjs.map} +1 -1
  40. package/dist/button.cjs +1 -1
  41. package/dist/button.js +1 -1
  42. package/dist/{card-CgQwXO8L.js → card-BvCFuX3J.js} +2 -2
  43. package/dist/{card-CgQwXO8L.js.map → card-BvCFuX3J.js.map} +1 -1
  44. package/dist/{card-BIzaLuEg.cjs → card-CTotavhH.cjs} +1 -1
  45. package/dist/{card-BIzaLuEg.cjs.map → card-CTotavhH.cjs.map} +1 -1
  46. package/dist/card.cjs +1 -1
  47. package/dist/card.js +1 -1
  48. package/dist/{checkbox-BAqE3sTx.cjs → checkbox-By4fFmjt.cjs} +1 -1
  49. package/dist/{checkbox-BAqE3sTx.cjs.map → checkbox-By4fFmjt.cjs.map} +1 -1
  50. package/dist/{checkbox-BNdg57Om.js → checkbox-GPsdCUbs.js} +1 -1
  51. package/dist/{checkbox-BNdg57Om.js.map → checkbox-GPsdCUbs.js.map} +1 -1
  52. package/dist/checkbox.cjs +1 -1
  53. package/dist/checkbox.js +1 -1
  54. package/dist/{chips-DnqLaOb1.js → chips-27umqnat.js} +4 -4
  55. package/dist/{chips-DnqLaOb1.js.map → chips-27umqnat.js.map} +1 -1
  56. package/dist/{chips-DS3y4Lbn.cjs → chips-BZf9sGA8.cjs} +1 -1
  57. package/dist/{chips-DS3y4Lbn.cjs.map → chips-BZf9sGA8.cjs.map} +1 -1
  58. package/dist/chips.cjs +1 -1
  59. package/dist/chips.js +2 -2
  60. package/dist/connectivity.cjs +1 -1
  61. package/dist/connectivity.js +1 -1
  62. package/dist/content-drawer.cjs +1 -1
  63. package/dist/content-drawer.js +1 -1
  64. package/dist/{cursor-glow-Cs2XLDB9.js → cursor-glow-Ah7VXSj7.js} +1 -1
  65. package/dist/{cursor-glow-Cs2XLDB9.js.map → cursor-glow-Ah7VXSj7.js.map} +1 -1
  66. package/dist/{cursor-glow-C8LgCxpI.cjs → cursor-glow-Bulq-38P.cjs} +1 -1
  67. package/dist/{cursor-glow-C8LgCxpI.cjs.map → cursor-glow-Bulq-38P.cjs.map} +1 -1
  68. package/dist/{date-range-VA1mi1N7.cjs → date-range-BJnLWCRF.cjs} +1 -1
  69. package/dist/{date-range-VA1mi1N7.cjs.map → date-range-BJnLWCRF.cjs.map} +1 -1
  70. package/dist/{date-range-inline-CAa0_4EI.cjs → date-range-inline-B6uKUliV.cjs} +1 -1
  71. package/dist/{date-range-inline-CAa0_4EI.cjs.map → date-range-inline-B6uKUliV.cjs.map} +1 -1
  72. package/dist/{date-range-inline-PeRt1iIF.js → date-range-inline-BNbbRfIA.js} +1 -1
  73. package/dist/{date-range-inline-PeRt1iIF.js.map → date-range-inline-BNbbRfIA.js.map} +1 -1
  74. package/dist/date-range-inline.cjs +1 -1
  75. package/dist/date-range-inline.js +1 -1
  76. package/dist/{date-range-CAqB-B0M.js → date-range-wDVHcr0u.js} +2 -2
  77. package/dist/{date-range-CAqB-B0M.js.map → date-range-wDVHcr0u.js.map} +1 -1
  78. package/dist/date-range.cjs +1 -1
  79. package/dist/date-range.js +1 -1
  80. package/dist/delay.cjs +1 -1
  81. package/dist/delay.js +2 -2
  82. package/dist/{details-BpFjVclg.js → details-Ckxpwacj.js} +4 -4
  83. package/dist/{details-BpFjVclg.js.map → details-Ckxpwacj.js.map} +1 -1
  84. package/dist/{details-BnXbDpt7.cjs → details-DNrWIes6.cjs} +1 -1
  85. package/dist/{details-BnXbDpt7.cjs.map → details-DNrWIes6.cjs.map} +1 -1
  86. package/dist/details.cjs +1 -1
  87. package/dist/details.js +1 -1
  88. package/dist/directives-BBMqe8x3.js +4082 -0
  89. package/dist/directives-BBMqe8x3.js.map +1 -0
  90. package/dist/directives-F15SJZUR.cjs +348 -0
  91. package/dist/directives-F15SJZUR.cjs.map +1 -0
  92. package/dist/directives.cjs +1 -99
  93. package/dist/directives.js +6 -1363
  94. package/dist/discovery.cjs +1 -1
  95. package/dist/discovery.js +2 -61
  96. package/dist/discovery.service-COmbHaoI.js +61 -0
  97. package/dist/discovery.service-COmbHaoI.js.map +1 -0
  98. package/dist/discovery.service-CVDXO9rH.cjs +1 -0
  99. package/dist/discovery.service-CVDXO9rH.cjs.map +1 -0
  100. package/dist/{divider-D8cBBkdG.js → divider-BzcZGo4S.js} +1 -1
  101. package/dist/{divider-D8cBBkdG.js.map → divider-BzcZGo4S.js.map} +1 -1
  102. package/dist/{divider-B84lt1A3.cjs → divider-Cde33ivs.cjs} +1 -1
  103. package/dist/{divider-B84lt1A3.cjs.map → divider-Cde33ivs.cjs.map} +1 -1
  104. package/dist/divider.cjs +1 -1
  105. package/dist/divider.js +1 -1
  106. package/dist/dropdown.cjs +1 -1
  107. package/dist/dropdown.js +1 -1
  108. package/dist/{expand-BJiKggfg.js → expand-DI144OzN.js} +3 -3
  109. package/dist/{expand-BJiKggfg.js.map → expand-DI144OzN.js.map} +1 -1
  110. package/dist/{expand-DK-O37-j.cjs → expand-Db4V0jj-.cjs} +1 -1
  111. package/dist/{expand-DK-O37-j.cjs.map → expand-Db4V0jj-.cjs.map} +1 -1
  112. package/dist/expand.cjs +1 -1
  113. package/dist/expand.js +1 -1
  114. package/dist/{float-RWR6Q1Hh.cjs → float--RScf9BZ.cjs} +1 -1
  115. package/dist/{float-RWR6Q1Hh.cjs.map → float--RScf9BZ.cjs.map} +1 -1
  116. package/dist/{float-B4FDN40h.js → float-DIyzy1c2.js} +1 -1
  117. package/dist/{float-B4FDN40h.js.map → float-DIyzy1c2.js.map} +1 -1
  118. package/dist/float.cjs +1 -1
  119. package/dist/float.js +1 -1
  120. package/dist/{form-ha3df3K7.cjs → form-DWNpOsIU.cjs} +1 -1
  121. package/dist/{form-ha3df3K7.cjs.map → form-DWNpOsIU.cjs.map} +1 -1
  122. package/dist/{form-B-Sm6u25.js → form-RtXH8UHQ.js} +8 -8
  123. package/dist/{form-B-Sm6u25.js.map → form-RtXH8UHQ.js.map} +1 -1
  124. package/dist/form.cjs +1 -1
  125. package/dist/form.js +6 -6
  126. package/dist/handover/agent-runtime-followups.md +1 -1
  127. package/dist/handover/agent-runtime-v1.md +3 -3
  128. package/dist/{hashContent-dJrI-9sc.js.map → hashContent-Dgmzc32o.js.map} +1 -1
  129. package/dist/{hashContent-Ck6laKlk.cjs.map → hashContent-Dh1VzIAb.cjs.map} +1 -1
  130. package/dist/icons-DXanGDZ_.js +52 -0
  131. package/dist/icons-DXanGDZ_.js.map +1 -0
  132. package/dist/icons-bNxlWLlk.cjs +24 -0
  133. package/dist/icons-bNxlWLlk.cjs.map +1 -0
  134. package/dist/icons.cjs +1 -1
  135. package/dist/icons.js +1 -1
  136. package/dist/{iframe-BXe1TPx1.cjs → iframe-B1XWRaLC.cjs} +1 -1
  137. package/dist/{iframe-BXe1TPx1.cjs.map → iframe-B1XWRaLC.cjs.map} +1 -1
  138. package/dist/{iframe-CByrVlZy.js → iframe-BlHK0cjy.js} +1 -1
  139. package/dist/{iframe-CByrVlZy.js.map → iframe-BlHK0cjy.js.map} +1 -1
  140. package/dist/iframe.cjs +1 -1
  141. package/dist/iframe.js +1 -1
  142. package/dist/index.cjs +1 -1
  143. package/dist/index.js +60 -60
  144. package/dist/{input-BY9OCQWr.cjs → input-C-_XU9AX.cjs} +1 -1
  145. package/dist/{input-BY9OCQWr.cjs.map → input-C-_XU9AX.cjs.map} +1 -1
  146. package/dist/{input-Q0fm34Co.js → input-CiGa8Dkl.js} +1 -1
  147. package/dist/{input-Q0fm34Co.js.map → input-CiGa8Dkl.js.map} +1 -1
  148. package/dist/{input-chip-BwNf3GD0.cjs → input-chip-5aYnuRZ_.cjs} +1 -1
  149. package/dist/{input-chip-BwNf3GD0.cjs.map → input-chip-5aYnuRZ_.cjs.map} +1 -1
  150. package/dist/{input-chip-CytUirVS.js → input-chip-l--zCMGR.js} +1 -1
  151. package/dist/{input-chip-CytUirVS.js.map → input-chip-l--zCMGR.js.map} +1 -1
  152. package/dist/input.cjs +1 -1
  153. package/dist/input.js +1 -1
  154. package/dist/json.cjs +2 -2
  155. package/dist/json.cjs.map +1 -1
  156. package/dist/json.js +3 -3
  157. package/dist/json.js.map +1 -1
  158. package/dist/kbd.cjs +1 -1
  159. package/dist/kbd.js +1 -1
  160. package/dist/{layout-Dq2oeOTS.js → layout-DSAjo92m.js} +1 -1
  161. package/dist/{layout-Dq2oeOTS.js.map → layout-DSAjo92m.js.map} +1 -1
  162. package/dist/{layout-BbCIfIgo.cjs → layout-eXb9wjDh.cjs} +1 -1
  163. package/dist/{layout-BbCIfIgo.cjs.map → layout-eXb9wjDh.cjs.map} +1 -1
  164. package/dist/layout.cjs +1 -1
  165. package/dist/layout.js +1 -1
  166. package/dist/{lightbox-p2E0oVR0.cjs → lightbox-CfRDkeeb.cjs} +2 -2
  167. package/dist/{lightbox-p2E0oVR0.cjs.map → lightbox-CfRDkeeb.cjs.map} +1 -1
  168. package/dist/{lightbox-Ckvn5YNF.js → lightbox-D9oiu1Nv.js} +2 -2
  169. package/dist/{lightbox-Ckvn5YNF.js.map → lightbox-D9oiu1Nv.js.map} +1 -1
  170. package/dist/lightbox.cjs +1 -1
  171. package/dist/lightbox.js +1 -1
  172. package/dist/{list-CsrPVvmm.js → list-BOlRka4v.js} +1 -1
  173. package/dist/{list-CsrPVvmm.js.map → list-BOlRka4v.js.map} +1 -1
  174. package/dist/{list-r57UFHu3.cjs → list-CDJi3_Ut.cjs} +1 -1
  175. package/dist/{list-r57UFHu3.cjs.map → list-CDJi3_Ut.cjs.map} +1 -1
  176. package/dist/list.cjs +1 -1
  177. package/dist/list.js +1 -1
  178. package/dist/{magnetic-Bgh7aHHI.cjs → magnetic-D-ph029G.cjs} +1 -1
  179. package/dist/{magnetic-Bgh7aHHI.cjs.map → magnetic-D-ph029G.cjs.map} +1 -1
  180. package/dist/{magnetic-DxvoEz8_.js → magnetic-mHXl54Z8.js} +1 -1
  181. package/dist/{magnetic-DxvoEz8_.js.map → magnetic-mHXl54Z8.js.map} +1 -1
  182. package/dist/{menu-DBuZiPyW.cjs → menu-CJaDL2cd.cjs} +1 -1
  183. package/dist/{menu-DBuZiPyW.cjs.map → menu-CJaDL2cd.cjs.map} +1 -1
  184. package/dist/{menu-Csm6Fg88.js → menu-XyrLmCi_.js} +2 -2
  185. package/dist/{menu-Csm6Fg88.js.map → menu-XyrLmCi_.js.map} +1 -1
  186. package/dist/menu.cjs +1 -1
  187. package/dist/menu.js +1 -1
  188. package/dist/mixins-CsYsIJOI.cjs +254 -0
  189. package/dist/mixins-CsYsIJOI.cjs.map +1 -0
  190. package/dist/mixins-DySzfmal.js +642 -0
  191. package/dist/mixins-DySzfmal.js.map +1 -0
  192. package/dist/mixins.cjs +1 -1
  193. package/dist/mixins.js +2 -2
  194. package/dist/nav-drawer.cjs +1 -1
  195. package/dist/nav-drawer.js +1 -1
  196. package/dist/navigation-bar.cjs +1 -1
  197. package/dist/navigation-bar.js +1 -1
  198. package/dist/navigation-rail.cjs +5 -9
  199. package/dist/navigation-rail.cjs.map +1 -1
  200. package/dist/navigation-rail.js +5 -11
  201. package/dist/navigation-rail.js.map +1 -1
  202. package/dist/{notification-CgTBiAdf.js → notification-CHrEY4u8.js} +2 -2
  203. package/dist/{notification-CgTBiAdf.js.map → notification-CHrEY4u8.js.map} +1 -1
  204. package/dist/{notification-58tkVys8.cjs → notification-DKp4tjaB.cjs} +1 -1
  205. package/dist/{notification-58tkVys8.cjs.map → notification-DKp4tjaB.cjs.map} +1 -1
  206. package/dist/notification.cjs +1 -1
  207. package/dist/notification.js +1 -1
  208. package/dist/{option-Bicf6xpI.js → option-Vpy4UQ-D.js} +1 -1
  209. package/dist/{option-Bicf6xpI.js.map → option-Vpy4UQ-D.js.map} +1 -1
  210. package/dist/{option-61YE3gub.cjs → option-nRk4MuXH.cjs} +1 -1
  211. package/dist/{option-61YE3gub.cjs.map → option-nRk4MuXH.cjs.map} +1 -1
  212. package/dist/option.cjs +1 -1
  213. package/dist/option.js +1 -1
  214. package/dist/{overlay-CpvmytrQ.cjs → overlay-HNrWZ4sB.cjs} +1 -1
  215. package/dist/{overlay-CpvmytrQ.cjs.map → overlay-HNrWZ4sB.cjs.map} +1 -1
  216. package/dist/{overlay-CAI2FAp7.js → overlay-jlkcrt8F.js} +5 -5
  217. package/dist/{overlay-CAI2FAp7.js.map → overlay-jlkcrt8F.js.map} +1 -1
  218. package/dist/{overlay-stack-Dk0xETTy.cjs.map → overlay-stack-Bdr9lOqi.cjs.map} +1 -1
  219. package/dist/{overlay-stack-BR4iYivO.js.map → overlay-stack-D2rgxQLh.js.map} +1 -1
  220. package/dist/overlay.cjs +1 -1
  221. package/dist/{overlay.confirm-body-QD-5cj3_.cjs → overlay.confirm-body-B8dFI3cj.cjs} +1 -1
  222. package/dist/{overlay.confirm-body-QD-5cj3_.cjs.map → overlay.confirm-body-B8dFI3cj.cjs.map} +1 -1
  223. package/dist/{overlay.confirm-body-Cq25CkTw.js → overlay.confirm-body-CYShkjI6.js} +1 -1
  224. package/dist/{overlay.confirm-body-Cq25CkTw.js.map → overlay.confirm-body-CYShkjI6.js.map} +1 -1
  225. package/dist/overlay.js +3 -3
  226. package/dist/{overlay.service-BG0bqPwJ.cjs → overlay.service-BTPn7Uv7.cjs} +1 -1
  227. package/dist/{overlay.service-BG0bqPwJ.cjs.map → overlay.service-BTPn7Uv7.cjs.map} +1 -1
  228. package/dist/{overlay.service-Bpjrhaxh.js → overlay.service-BqhhxVJp.js} +2 -2
  229. package/dist/{overlay.service-Bpjrhaxh.js.map → overlay.service-BqhhxVJp.js.map} +1 -1
  230. package/dist/{progress-Zqx-S9NZ.js → progress-8Bn88GK_.js} +1 -1
  231. package/dist/{progress-Zqx-S9NZ.js.map → progress-8Bn88GK_.js.map} +1 -1
  232. package/dist/{progress-D8XZJVl5.cjs → progress-CAp_4jtq.cjs} +1 -1
  233. package/dist/{progress-D8XZJVl5.cjs.map → progress-CAp_4jtq.cjs.map} +1 -1
  234. package/dist/progress.cjs +1 -1
  235. package/dist/progress.js +1 -1
  236. package/dist/{radio-group-bl8K4Gls.cjs → radio-group-CN44mAoc.cjs} +1 -1
  237. package/dist/{radio-group-bl8K4Gls.cjs.map → radio-group-CN44mAoc.cjs.map} +1 -1
  238. package/dist/{radio-group-D9MU1Mxz.js → radio-group-GNHA7qJR.js} +1 -1
  239. package/dist/{radio-group-D9MU1Mxz.js.map → radio-group-GNHA7qJR.js.map} +1 -1
  240. package/dist/radio-group.cjs +1 -1
  241. package/dist/radio-group.js +1 -1
  242. package/dist/range.cjs +1 -1
  243. package/dist/range.js +1 -1
  244. package/dist/{reduced-motion-D7LqTUMn.js.map → reduced-motion-D-L12p7G.js.map} +1 -1
  245. package/dist/{reduced-motion-Dzfp_w5x.cjs.map → reduced-motion-Ds-HjMzn.cjs.map} +1 -1
  246. package/dist/{rxjs-utils-BK8VMe3K.js.map → rxjs-utils-BXpvHN4-.js.map} +1 -1
  247. package/dist/{rxjs-utils-DhOKenkS.cjs.map → rxjs-utils-CaC-tdot.cjs.map} +1 -1
  248. package/dist/rxjs-utils.cjs +1 -1
  249. package/dist/rxjs-utils.js +1 -1
  250. package/dist/{select-CMwkl-D6.js → select-BnuXRHS4.js} +3 -3
  251. package/dist/{select-CMwkl-D6.js.map → select-BnuXRHS4.js.map} +1 -1
  252. package/dist/{select-COIfVtZl.cjs → select-DZNns5Pa.cjs} +2 -2
  253. package/dist/{select-COIfVtZl.cjs.map → select-DZNns5Pa.cjs.map} +1 -1
  254. package/dist/select.cjs +1 -1
  255. package/dist/select.js +1 -1
  256. package/dist/skeleton.cjs +1 -1
  257. package/dist/skeleton.js +1 -1
  258. package/dist/skills/INDEX.md +2 -1
  259. package/dist/skills/SKILL.md +33 -23
  260. package/dist/skills/area.md +5 -4
  261. package/dist/skills/connectivity.md +1 -3
  262. package/dist/skills/directives.md +36 -0
  263. package/dist/skills/icons.md +95 -31
  264. package/dist/skills/layout.md +36 -53
  265. package/dist/skills/mixins.md +26 -5
  266. package/dist/skills/schmancy/INDEX.md +2 -1
  267. package/dist/skills/schmancy/SKILL.md +33 -23
  268. package/dist/skills/schmancy/area.md +5 -4
  269. package/dist/skills/schmancy/connectivity.md +1 -3
  270. package/dist/skills/schmancy/directives.md +36 -0
  271. package/dist/skills/schmancy/icons.md +95 -31
  272. package/dist/skills/schmancy/layout.md +36 -53
  273. package/dist/skills/schmancy/mixins.md +26 -5
  274. package/dist/slider.cjs +1 -1
  275. package/dist/slider.js +1 -1
  276. package/dist/{splash-screen-xrMNpzkm.js → splash-screen-CUP_elaT.js} +1 -1
  277. package/dist/{splash-screen-xrMNpzkm.js.map → splash-screen-CUP_elaT.js.map} +1 -1
  278. package/dist/{splash-screen-2hxq8Sft.cjs → splash-screen-DeoPRrOu.cjs} +1 -1
  279. package/dist/{splash-screen-2hxq8Sft.cjs.map → splash-screen-DeoPRrOu.cjs.map} +1 -1
  280. package/dist/splash-screen.cjs +1 -1
  281. package/dist/splash-screen.js +1 -1
  282. package/dist/{src-B15R32Sp.js → src-B1VkLX3l.js} +159 -159
  283. package/dist/src-B1VkLX3l.js.map +1 -0
  284. package/dist/{src-BWQvtOOf.cjs → src-DQ4wr0qq.cjs} +13 -13
  285. package/dist/src-DQ4wr0qq.cjs.map +1 -0
  286. package/dist/steps.cjs +1 -1
  287. package/dist/steps.js +1 -1
  288. package/dist/{surface-BkQ44Wuo.cjs → surface-LkaZQXZn.cjs} +1 -1
  289. package/dist/{surface-BkQ44Wuo.cjs.map → surface-LkaZQXZn.cjs.map} +1 -1
  290. package/dist/{surface-3nnvlxeE.js → surface-hOvkrjGN.js} +1 -1
  291. package/dist/{surface-3nnvlxeE.js.map → surface-hOvkrjGN.js.map} +1 -1
  292. package/dist/surface.cjs +1 -1
  293. package/dist/surface.js +1 -1
  294. package/dist/switch.cjs +1 -1
  295. package/dist/switch.js +1 -1
  296. package/dist/table.cjs +2 -2
  297. package/dist/table.cjs.map +1 -1
  298. package/dist/table.js +2 -2
  299. package/dist/table.js.map +1 -1
  300. package/dist/{tabs-CnLIe8nE.js → tabs-CfwIHhHo.js} +1 -1
  301. package/dist/{tabs-CnLIe8nE.js.map → tabs-CfwIHhHo.js.map} +1 -1
  302. package/dist/{tabs-Dql0rcqZ.cjs → tabs-bplzstz6.cjs} +1 -1
  303. package/dist/{tabs-Dql0rcqZ.cjs.map → tabs-bplzstz6.cjs.map} +1 -1
  304. package/dist/tabs.cjs +1 -1
  305. package/dist/tabs.js +1 -1
  306. package/dist/teleport.cjs +1 -1
  307. package/dist/teleport.js +1 -1
  308. package/dist/{textarea-BAogS_Ff.js → textarea-C1A5xuw9.js} +1 -1
  309. package/dist/{textarea-BAogS_Ff.js.map → textarea-C1A5xuw9.js.map} +1 -1
  310. package/dist/{textarea-CGD6lAEe.cjs → textarea-hrDp5gQq.cjs} +1 -1
  311. package/dist/{textarea-CGD6lAEe.cjs.map → textarea-hrDp5gQq.cjs.map} +1 -1
  312. package/dist/textarea.cjs +1 -1
  313. package/dist/textarea.js +1 -1
  314. package/dist/{theme-CUK0HrS3.js → theme-BniFOMEo.js} +4 -4
  315. package/dist/{theme-CUK0HrS3.js.map → theme-BniFOMEo.js.map} +1 -1
  316. package/dist/{theme-DKrrQ-ic.cjs → theme-DmR6PKV8.cjs} +3 -3
  317. package/dist/{theme-DKrrQ-ic.cjs.map → theme-DmR6PKV8.cjs.map} +1 -1
  318. package/dist/{theme-button-Bb8qW2IH.js → theme-button--ruZIb0T.js} +1 -1
  319. package/dist/{theme-button-Bb8qW2IH.js.map → theme-button--ruZIb0T.js.map} +1 -1
  320. package/dist/{theme-button-CmTwFm3l.cjs → theme-button-a0LgZ7hQ.cjs} +1 -1
  321. package/dist/{theme-button-CmTwFm3l.cjs.map → theme-button-a0LgZ7hQ.cjs.map} +1 -1
  322. package/dist/theme-button.cjs +1 -1
  323. package/dist/theme-button.js +1 -1
  324. package/dist/theme.cjs +1 -1
  325. package/dist/{theme.interface-D4NeufQA.cjs.map → theme.interface-B5xjEk74.cjs.map} +1 -1
  326. package/dist/{theme.interface-C2XNgsLB.js.map → theme.interface-DVEw3s8m.js.map} +1 -1
  327. package/dist/theme.js +4 -4
  328. package/dist/{theme.service-CSzNkqBB.js.map → theme.service-Bh08uOSJ.js.map} +1 -1
  329. package/dist/{theme.service-CnFUmUpc.cjs.map → theme.service-Y-e8b331.cjs.map} +1 -1
  330. package/dist/tree.cjs +1 -1
  331. package/dist/tree.js +1 -1
  332. package/dist/typography.cjs +1 -1
  333. package/dist/typography.js +1 -1
  334. package/dist/{utils-Cxg0Kfy5.js → utils-578eFTx4.js} +1 -1
  335. package/dist/{utils-Cxg0Kfy5.js.map → utils-578eFTx4.js.map} +1 -1
  336. package/dist/{utils-aCJYAGUr.cjs → utils-CVWUrECT.cjs} +1 -1
  337. package/dist/{utils-aCJYAGUr.cjs.map → utils-CVWUrECT.cjs.map} +1 -1
  338. package/dist/utils.cjs +1 -1
  339. package/dist/utils.js +2 -2
  340. package/dist/visually-hidden.cjs +1 -1
  341. package/dist/visually-hidden.js +1 -1
  342. package/dist/{window-DuDAQa6y.js → window-BT9JecWy.js} +5 -5
  343. package/dist/{window-DuDAQa6y.js.map → window-BT9JecWy.js.map} +1 -1
  344. package/dist/{window-BbWlaPZv.cjs → window-Bp7zWZpu.cjs} +1 -1
  345. package/dist/{window-BbWlaPZv.cjs.map → window-Bp7zWZpu.cjs.map} +1 -1
  346. package/dist/window.cjs +1 -1
  347. package/dist/window.js +1 -1
  348. package/package.json +1 -1
  349. package/skills/schmancy/INDEX.md +2 -1
  350. package/skills/schmancy/SKILL.md +33 -23
  351. package/skills/schmancy/area.md +5 -4
  352. package/skills/schmancy/connectivity.md +1 -3
  353. package/skills/schmancy/directives.md +36 -0
  354. package/skills/schmancy/icons.md +95 -31
  355. package/skills/schmancy/layout.md +36 -53
  356. package/skills/schmancy/mixins.md +26 -5
  357. package/src/badge/badge.ts +7 -11
  358. package/src/button/icon-button.ts +3 -4
  359. package/src/directives/ai-badge.ts +95 -0
  360. package/src/directives/art/art.directive.ts +228 -0
  361. package/src/directives/art/effects/error.ts +192 -0
  362. package/src/directives/art/effects/funkhaus.ts +121 -0
  363. package/src/directives/art/effects/howl.ts +203 -0
  364. package/src/directives/art/effects/samwa.ts +228 -0
  365. package/src/directives/art/effects/snow.ts +207 -0
  366. package/src/directives/art/effects/starfield.ts +107 -0
  367. package/src/directives/art/index.ts +2 -0
  368. package/src/directives/art/particle-pool.ts +40 -0
  369. package/src/directives/art/types.ts +129 -0
  370. package/src/directives/art/utils.ts +35 -0
  371. package/src/directives/battery.ts +1014 -0
  372. package/src/directives/beta.ts +44 -0
  373. package/src/directives/fill.ts +32 -60
  374. package/src/directives/fyi.ts +551 -0
  375. package/src/directives/hummingbird.ts +1712 -0
  376. package/src/directives/index.ts +9 -0
  377. package/src/directives/missed-punch.ts +407 -0
  378. package/src/directives/urgent.ts +660 -0
  379. package/src/directives/working-snake.ts +294 -0
  380. package/src/icons/icon.ts +53 -30
  381. package/src/json/json.ts +1 -1
  382. package/src/navigation-rail/navigation-rail-item.ts +7 -12
  383. package/src/navigation-rail/navigation-rail.ts +0 -2
  384. package/src/table/table.ts +2 -2
  385. package/src/theme/theme-audio-player.ts +1 -1
  386. package/types/mixins/SchmancyElement.d.ts +31 -0
  387. package/types/src/badge/badge.d.ts +1 -1
  388. package/types/src/directives/ai-badge.d.ts +15 -0
  389. package/types/src/directives/art/art.directive.d.ts +19 -0
  390. package/types/src/directives/art/effects/error.d.ts +7 -0
  391. package/types/src/directives/art/effects/funkhaus.d.ts +7 -0
  392. package/types/src/directives/art/effects/howl.d.ts +7 -0
  393. package/types/src/directives/art/effects/samwa.d.ts +7 -0
  394. package/types/src/directives/art/effects/snow.d.ts +7 -0
  395. package/types/src/directives/art/effects/starfield.d.ts +10 -0
  396. package/types/src/directives/art/index.d.ts +2 -0
  397. package/types/src/directives/art/particle-pool.d.ts +16 -0
  398. package/types/src/directives/art/types.d.ts +126 -0
  399. package/types/src/directives/art/utils.d.ts +5 -0
  400. package/types/src/directives/battery.d.ts +96 -0
  401. package/types/src/directives/beta.d.ts +33 -0
  402. package/types/src/directives/fill.d.ts +4 -11
  403. package/types/src/directives/fyi.d.ts +76 -0
  404. package/types/src/directives/hummingbird.d.ts +180 -0
  405. package/types/src/directives/index.d.ts +9 -0
  406. package/types/src/directives/missed-punch.d.ts +28 -0
  407. package/types/src/directives/urgent.d.ts +88 -0
  408. package/types/src/directives/working-snake.d.ts +46 -0
  409. package/types/src/icons/icon.d.ts +22 -0
  410. package/dist/directives.cjs.map +0 -1
  411. package/dist/directives.js.map +0 -1
  412. package/dist/discovery.cjs.map +0 -1
  413. package/dist/discovery.js.map +0 -1
  414. package/dist/icons-DJuXwn8D.js +0 -48
  415. package/dist/icons-DJuXwn8D.js.map +0 -1
  416. package/dist/icons-oNRUCAEY.cjs +0 -33
  417. package/dist/icons-oNRUCAEY.cjs.map +0 -1
  418. package/dist/mixins-DTCHPEd4.cjs +0 -254
  419. package/dist/mixins-DTCHPEd4.cjs.map +0 -1
  420. package/dist/mixins-pU53qf6R.js +0 -636
  421. package/dist/mixins-pU53qf6R.js.map +0 -1
  422. package/dist/skills/page.md +0 -84
  423. package/dist/skills/schmancy/page.md +0 -84
  424. package/dist/src-B15R32Sp.js.map +0 -1
  425. package/dist/src-BWQvtOOf.cjs.map +0 -1
  426. package/skills/schmancy/page.md +0 -84
  427. /package/dist/{hashContent-dJrI-9sc.js → hashContent-Dgmzc32o.js} +0 -0
  428. /package/dist/{hashContent-Ck6laKlk.cjs → hashContent-Dh1VzIAb.cjs} +0 -0
  429. /package/dist/{overlay-stack-Dk0xETTy.cjs → overlay-stack-Bdr9lOqi.cjs} +0 -0
  430. /package/dist/{overlay-stack-BR4iYivO.js → overlay-stack-D2rgxQLh.js} +0 -0
  431. /package/dist/{reduced-motion-D7LqTUMn.js → reduced-motion-D-L12p7G.js} +0 -0
  432. /package/dist/{reduced-motion-Dzfp_w5x.cjs → reduced-motion-Ds-HjMzn.cjs} +0 -0
  433. /package/dist/{rxjs-utils-BK8VMe3K.js → rxjs-utils-BXpvHN4-.js} +0 -0
  434. /package/dist/{rxjs-utils-DhOKenkS.cjs → rxjs-utils-CaC-tdot.cjs} +0 -0
  435. /package/dist/{theme.interface-D4NeufQA.cjs → theme.interface-B5xjEk74.cjs} +0 -0
  436. /package/dist/{theme.interface-C2XNgsLB.js → theme.interface-DVEw3s8m.js} +0 -0
  437. /package/dist/{theme.service-CSzNkqBB.js → theme.service-Bh08uOSJ.js} +0 -0
  438. /package/dist/{theme.service-CnFUmUpc.cjs → theme.service-Y-e8b331.cjs} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"window-BbWlaPZv.cjs","names":[],"sources":["../src/window/window-manager.ts","../src/window/window-position.ts","../src/window/window.ts"],"sourcesContent":["/**\n * Window Manager — singleton service for multi-window coordination.\n *\n * Tracks all schmancy-window instances: positions, z-indices, focus, visual states.\n * Components register on connectedCallback, unregister on disconnectedCallback.\n * Focus changes, position updates, and overlap queries all flow through here.\n *\n * Follows the ThemeService singleton pattern (theme/theme.service.ts).\n *\n * Example:\n * windowManager.register('chat-1', bounds, 'bottom-right')\n * windowManager.focus('chat-1') // bumps z-index, updates focusedId\n * const overlaps = windowManager.findOverlaps(projectedBounds, 'chat-1')\n */\n\nimport { BehaviorSubject, Observable, distinctUntilChanged, map } from 'rxjs'\nimport { overlayStack } from '../utils/overlay-stack.js'\nimport type { WindowBounds, WindowRecord, WindowRegistryState, SnapTarget } from './window-registry.js'\n\nconst STORAGE_PREFIX = 'schmancy-window-'\nconst LEGACY_STORAGE_PREFIX = 'schmancy-float-'\n\nclass WindowManagerService {\n\tprivate static instance: WindowManagerService\n\n\tprivate readonly _state$ = new BehaviorSubject<WindowRegistryState>({\n\t\twindows: new Map(),\n\t\tfocusedId: null,\n\t\tstackOrder: [],\n\t})\n\n\treadonly state$ = this._state$.asObservable()\n\n\tprivate constructor() {}\n\n\tstatic getInstance(): WindowManagerService {\n\t\tif (!WindowManagerService.instance) {\n\t\t\tWindowManagerService.instance = new WindowManagerService()\n\t\t}\n\t\treturn WindowManagerService.instance\n\t}\n\n\t// ── Synchronous accessors ──────────────────────────────────────────\n\n\tget windows(): Map<string, WindowRecord> {\n\t\treturn this._state$.value.windows\n\t}\n\n\tget focusedId(): string | null {\n\t\treturn this._state$.value.focusedId\n\t}\n\n\t// ── Registration ───────────────────────────────────────────────────\n\n\tregister(id: string, initialBounds: WindowBounds, snapTarget: SnapTarget): void {\n\t\tconst state = this._state$.value\n\t\tif (state.windows.has(id)) return\n\n\t\tconst zIndex = overlayStack.assignZIndex(id)\n\t\tconst record: WindowRecord = {\n\t\t\tid,\n\t\t\tbounds: initialBounds,\n\t\t\tvisualState: 'normal',\n\t\t\tzIndex,\n\t\t\topen: false,\n\t\t\tsnapTarget,\n\t\t}\n\n\t\tconst windows = new Map(state.windows)\n\t\twindows.set(id, record)\n\t\tconst stackOrder = overlayStack.getStackOrder()\n\n\t\tthis._state$.next({ ...state, windows, stackOrder })\n\t}\n\n\tunregister(id: string): void {\n\t\tconst state = this._state$.value\n\t\tif (!state.windows.has(id)) return\n\n\t\toverlayStack.releaseId(id)\n\t\tconst windows = new Map(state.windows)\n\t\twindows.delete(id)\n\t\tconst stackOrder = overlayStack.getStackOrder()\n\t\tconst focusedId = state.focusedId === id ? null : state.focusedId\n\n\t\tthis._state$.next({ ...state, windows, stackOrder, focusedId })\n\t}\n\n\t// ── State mutations ────────────────────────────────────────────────\n\n\tupdateBounds(id: string, bounds: WindowBounds): void {\n\t\tthis._updateRecord(id, { bounds })\n\t}\n\n\tupdateVisualState(id: string, visualState: WindowRecord['visualState']): void {\n\t\tthis._updateRecord(id, { visualState })\n\t}\n\n\tupdateOpen(id: string, open: boolean): void {\n\t\tthis._updateRecord(id, { open })\n\t}\n\n\tfocus(id: string): void {\n\t\tconst state = this._state$.value\n\t\tif (!state.windows.has(id)) return\n\t\tif (state.focusedId === id) return\n\n\t\tconst zIndex = overlayStack.bringToFront(id)\n\t\tconst windows = new Map(state.windows)\n\t\tconst record = windows.get(id)\n\t\tif (record) {\n\t\t\twindows.set(id, { ...record, zIndex })\n\t\t}\n\t\tconst stackOrder = overlayStack.getStackOrder()\n\n\t\tthis._state$.next({ ...state, windows, stackOrder, focusedId: id })\n\t}\n\n\t// ── Queries ────────────────────────────────────────────────────────\n\n\tfindOverlaps(bounds: WindowBounds, excludeId: string): WindowRecord[] {\n\t\tconst result: WindowRecord[] = []\n\t\tfor (const [id, record] of this._state$.value.windows) {\n\t\t\tif (id === excludeId) continue\n\t\t\tif (rectsOverlap(bounds, record.bounds)) {\n\t\t\t\tresult.push(record)\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\n\tgetNeighbors(id: string): WindowRecord[] {\n\t\tconst result: WindowRecord[] = []\n\t\tfor (const [otherId, record] of this._state$.value.windows) {\n\t\t\tif (otherId !== id) result.push(record)\n\t\t}\n\t\treturn result\n\t}\n\n\t// ── Selectors ──────────────────────────────────────────────────────\n\n\tselectWindow(id: string): Observable<WindowRecord | undefined> {\n\t\treturn this._state$.pipe(\n\t\t\tmap(state => state.windows.get(id)),\n\t\t\tdistinctUntilChanged(),\n\t\t)\n\t}\n\n\tselectFocused(): Observable<string | null> {\n\t\treturn this._state$.pipe(\n\t\t\tmap(state => state.focusedId),\n\t\t\tdistinctUntilChanged(),\n\t\t)\n\t}\n\n\t// ── Persistence ────────────────────────────────────────────────────\n\n\tloadPosition(id: string): { x: number; y: number; anchor: string } | null {\n\t\ttry {\n\t\t\t// Try new key first, fall back to legacy\n\t\t\tconst raw = localStorage.getItem(STORAGE_PREFIX + id) ?? localStorage.getItem(LEGACY_STORAGE_PREFIX + id)\n\t\t\tif (!raw) return null\n\t\t\treturn JSON.parse(raw) as { x: number; y: number; anchor: string }\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\n\tsavePosition(id: string, data: { x: number; y: number; anchor: string }): void {\n\t\ttry {\n\t\t\tlocalStorage.setItem(STORAGE_PREFIX + id, JSON.stringify(data))\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\tclearPosition(id: string): void {\n\t\ttry {\n\t\t\tlocalStorage.removeItem(STORAGE_PREFIX + id)\n\t\t\tlocalStorage.removeItem(LEGACY_STORAGE_PREFIX + id)\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\t// ── Internal ───────────────────────────────────────────────────────\n\n\tprivate _updateRecord(id: string, updates: Partial<WindowRecord>): void {\n\t\tconst state = this._state$.value\n\t\tconst record = state.windows.get(id)\n\t\tif (!record) return\n\n\t\tconst windows = new Map(state.windows)\n\t\twindows.set(id, { ...record, ...updates })\n\t\tthis._state$.next({ ...state, windows })\n\t}\n}\n\n/** Simple rect overlap check (inline — no circular import with window-position) */\nfunction rectsOverlap(a: WindowBounds, b: WindowBounds): boolean {\n\treturn !(a.left >= b.left + b.width || a.left + a.width <= b.left || a.top >= b.top + b.height || a.top + a.height <= b.top)\n}\n\nexport const windowManager = WindowManagerService.getInstance()\n","/**\n * Window Position — pure functions for overlap resolution, cascade, and snapping.\n *\n * All functions are stateless: they take window bounds and viewport dimensions,\n * return new bounds. No side effects, no DOM access, no subscriptions.\n *\n * Example:\n * const projected = { left: 100, top: 400, width: 360, height: 500 }\n * const neighbors = windowManager.findOverlaps(projected, 'my-id')\n * const resolved = resolveOverlap(projected, neighbors, { width: 1440, height: 900 })\n * // → { left: 144, top: 444, width: 360, height: 500 } (cascaded away from conflict)\n */\n\nimport type { WindowBounds, WindowRecord } from './window-registry.js'\n\nconst HEAD_HEIGHT = 44\nconst CASCADE_OFFSET = HEAD_HEIGHT\nconst MAX_CASCADE_ATTEMPTS = 10\n\n/** Check if two rectangles overlap (edges touching does NOT count as overlap) */\nexport function rectsOverlap(a: WindowBounds, b: WindowBounds): boolean {\n\treturn !(a.left >= b.left + b.width || a.left + a.width <= b.left || a.top >= b.top + b.height || a.top + a.height <= b.top)\n}\n\n/**\n * Resolve overlap by cascading diagonally until no conflict.\n * Shifts by (HEAD_HEIGHT, HEAD_HEIGHT) per attempt, clamped to viewport.\n */\nexport function resolveOverlap(\n\tcandidate: WindowBounds,\n\texisting: WindowRecord[],\n\tviewport: { width: number; height: number },\n): WindowBounds {\n\tconst bounds = { ...candidate }\n\n\tfor (let attempt = 0; attempt < MAX_CASCADE_ATTEMPTS; attempt++) {\n\t\tconst hasOverlap = existing.some(w => rectsOverlap(bounds, w.bounds))\n\t\tif (!hasOverlap) break\n\n\t\tbounds.left += CASCADE_OFFSET\n\t\tbounds.top += CASCADE_OFFSET\n\t}\n\n\treturn clampToViewport(bounds, viewport)\n}\n\n/**\n * Clamp bounds so the window stays fully within the viewport.\n */\nexport function clampToViewport(\n\tbounds: WindowBounds,\n\tviewport: { width: number; height: number },\n): WindowBounds {\n\treturn {\n\t\twidth: bounds.width,\n\t\theight: bounds.height,\n\t\tleft: Math.max(0, Math.min(bounds.left, viewport.width - bounds.width)),\n\t\ttop: Math.max(0, Math.min(bounds.top, viewport.height - bounds.height)),\n\t}\n}\n","import { SchmancyElement } from '@mixins/index'\nimport { css, html, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { styleMap } from 'lit/directives/style-map.js'\nimport {\n\tanimationFrameScheduler,\n\tauditTime,\n\tcatchError,\n\tEMPTY,\n\tfilter,\n\tfinalize,\n\tfrom,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tObservable,\n\tswitchMap,\n\ttake,\n\ttakeUntil,\n\ttap,\n} from 'rxjs'\nimport { SPRING_SMOOTH, SPRING_SNAPPY } from '../utils/animation.js'\nimport { cursorGlow } from '../directives/cursor-glow'\nimport { reducedMotion$ } from '../directives/reduced-motion'\nimport { theme } from '../theme/theme.service.js'\nimport type { SnapCorner, WindowBounds, WindowVisualState } from './window-registry.js'\nimport { windowManager } from './window-manager.js'\nimport { resolveOverlap } from './window-position.js'\n\nconst HEAD_HEIGHT = 48\nconst DRAG_THRESHOLD = 5\n\ninterface Position {\n\tx: number\n\ty: number\n}\n\n@customElement('schmancy-window')\nexport default class SchmancyWindow extends SchmancyElement {\n\tstatic styles = [css`\n\t:host {\n\t\tdisplay: contents;\n\t\tposition: relative;\n\t\tz-index: 1000;\n\t}\n\t:host([hidden]) {\n\t\tdisplay: none !important;\n\t}\n`]\n\n\t@property({ type: String }) id: string = 'default'\n\t/** Override the expanded panel width (e.g. '320px', '24rem'). Defaults to responsive sizing. */\n\t@property({ type: String }) expandedWidth?: string\n\t/** Override the expanded panel height (e.g. '400px', '50vh'). */\n\t@property({ type: String }) expandedHeight?: string\n\t/** When true, uses a lower elevation shadow in the collapsed state. */\n\t@property({ type: Boolean, reflect: true }) lowered: boolean = false\n\t/** Corner the window is anchored to. */\n\t@property({ type: String }) corner: SnapCorner = 'bottom-right'\n\t/** When true, window can be resized by the user. */\n\t@property({ type: Boolean }) resizable = false\n\t/** When true, window stays at its dragged position instead of snapping to a corner. */\n\t@property({ type: Boolean }) freePosition = false\n\t/** Visual state of the window (minimized, normal, maximized). */\n\t@property({ type: String, reflect: true }) visualState: WindowVisualState = 'normal'\n\t/** Minimum width in pixels. */\n\t@property({ type: Number }) minWidth = 280\n\t/** Minimum height in pixels. */\n\t@property({ type: Number }) minHeight = 200\n\n\t/** Whether the body is expanded. */\n\t@property({ type: Boolean, reflect: true }) open = false\n\n\tprivate _currentAnimation?: Animation\n\n\t/** Lazy rendering: body content not in DOM until first expand. */\n\t@state() private _hasOpened = false\n\n\t// Internal position -- plain fields, updated directly during drag\n\tprivate _position: Position = { x: 16, y: 16 }\n\t@state() private _currentCorner: SnapCorner = 'bottom-right'\n\n\t// Track applied corner to avoid unnecessary style.removeProperty calls during drag\n\tprivate _appliedCorner: string = ''\n\n\t// Refs\n\tprivate _containerRef = createRef<HTMLElement>()\n\tprivate _bodyRef = createRef<HTMLElement>()\n\tprivate _headRef = createRef<HTMLElement>()\n\n\t// ============================================\n\t// COMPUTED\n\t// ============================================\n\n\tprivate get panelWidth(): string {\n\t\treturn this.expandedWidth ?? 'min(360px, calc(100vw - 32px))'\n\t}\n\n\tprivate get isBottomCorner(): boolean {\n\t\treturn this._currentCorner.startsWith('bottom')\n\t}\n\n\tprivate get closedClipPath(): string {\n\t\treturn this.isBottomCorner\n\t\t\t? `inset(calc(100% - ${HEAD_HEIGHT}px) 0px 0px 0px round 22px)`\n\t\t\t: `inset(0px 0px calc(100% - ${HEAD_HEIGHT}px) 0px round 22px)`\n\t}\n\n\tprivate get openClipPath(): string {\n\t\treturn 'inset(0px 0px 0px 0px round 12px)'\n\t}\n\n\tprivate get elevation(): 0 | 1 | 2 | 3 | 4 | 5 {\n\t\tif (this.open) return 4\n\t\treturn this.lowered ? 1 : 3\n\t}\n\n\t// ============================================\n\t// POSITION MANAGEMENT\n\t// ============================================\n\n\tprivate _applyContainerPosition() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\t\t// Only clear position properties when corner changes (avoids 4 style invalidations per drag frame)\n\t\tif (this._appliedCorner !== this._currentCorner) {\n\t\t\tcontainer.style.removeProperty('left')\n\t\t\tcontainer.style.removeProperty('right')\n\t\t\tcontainer.style.removeProperty('top')\n\t\t\tcontainer.style.removeProperty('bottom')\n\t\t\tthis._appliedCorner = this._currentCorner\n\t\t}\n\t\tconst { x, y } = this._position\n\t\tif (this._currentCorner.includes('right')) {\n\t\t\tcontainer.style.right = `${x}px`\n\t\t} else {\n\t\t\tcontainer.style.left = `${x}px`\n\t\t}\n\t\tif (this._currentCorner.includes('bottom')) {\n\t\t\tcontainer.style.bottom = `${y + theme.bottomOffset}px`\n\t\t} else {\n\t\t\tcontainer.style.top = `${y}px`\n\t\t}\n\t}\n\n\tprivate static readonly VALID_CORNERS = new Set<string>(['top-left', 'top-right', 'bottom-left', 'bottom-right'])\n\n\tprivate _loadPosition() {\n\t\tconst saved = windowManager.loadPosition(this.id)\n\t\tif (saved) {\n\t\t\tthis._position = { x: saved.x, y: saved.y }\n\t\t\tif (SchmancyWindow.VALID_CORNERS.has(saved.anchor)) {\n\t\t\t\tthis._currentCorner = saved.anchor as SnapCorner\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _savePosition() {\n\t\twindowManager.savePosition(this.id, { ...this._position, anchor: this._currentCorner })\n\t}\n\n\tprivate _validateBounds() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tif (rect.width === 0) return\n\t\tconst vw = window.innerWidth\n\t\tconst vh = window.innerHeight\n\t\tconst isRight = this._currentCorner.includes('right')\n\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\tconst actualLeft = isRight ? vw - this._position.x - rect.width : this._position.x\n\t\tconst actualTop = isBottom ? vh - this._position.y - rect.height : this._position.y\n\t\tconst newLeft = Math.max(0, Math.min(actualLeft, vw - rect.width))\n\t\tconst newTop = Math.max(0, Math.min(actualTop, vh - rect.height))\n\t\tthis._position = {\n\t\t\tx: isRight ? vw - newLeft - rect.width : newLeft,\n\t\t\ty: isBottom ? vh - newTop - rect.height : newTop,\n\t\t}\n\t\tthis._applyContainerPosition()\n\t}\n\n\t// ============================================\n\t// CORNER SNAPPING\n\t// ============================================\n\n\tprivate _reorientToNearestCorner(skipAnimation = false): void {\n\t\t// Free position mode: skip corner snapping\n\t\tif (this.freePosition) {\n\t\t\tthis._savePosition()\n\t\t\tconst rect = this._containerRef.value?.getBoundingClientRect()\n\t\t\tif (rect) {\n\t\t\t\twindowManager.updateBounds(this.id, { left: rect.left, top: rect.top, width: rect.width, height: rect.height })\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\n\t\t// F -- record current screen position before DOM mutation\n\t\tconst rect = container.getBoundingClientRect()\n\n\t\t// L -- calculate nearest corner using head visual center\n\t\tconst currentIsBottom = this._currentCorner.includes('bottom')\n\t\tconst headCenterX = rect.left + rect.width / 2\n\t\tconst headCenterY = currentIsBottom\n\t\t\t? rect.bottom - HEAD_HEIGHT / 2\n\t\t\t: rect.top + HEAD_HEIGHT / 2\n\t\tconst side = headCenterX > window.innerWidth / 2 ? 'right' : 'left'\n\t\tconst vert = headCenterY > window.innerHeight / 2 ? 'bottom' : 'top'\n\t\tconst newCorner: SnapCorner = `${vert}-${side}` as SnapCorner\n\n\t\t// Snap corner and reset offset to standard edge gap\n\t\tthis._currentCorner = newCorner\n\t\tthis._position = { x: 16, y: 16 }\n\t\tthis._applyContainerPosition()\n\t\t// Sync clip-path to new corner\n\t\tif (!this.open) {\n\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t}\n\n\t\tif (skipAnimation || reducedMotion$.value) {\n\t\t\tthis._savePosition()\n\t\t\tconst snapRect = container.getBoundingClientRect()\n\t\t\twindowManager.updateBounds(this.id, { left: snapRect.left, top: snapRect.top, width: snapRect.width, height: snapRect.height })\n\t\t\treturn\n\t\t}\n\n\t\t// I -- invert: shift element back to its original visual position\n\t\tconst newRect = container.getBoundingClientRect()\n\t\tconst dx = rect.left - newRect.left\n\t\tconst dy = rect.top - newRect.top\n\t\tcontainer.style.translate = `${dx}px ${dy}px`\n\n\t\t// P -- play: animate from the inverse offset to natural resting position\n\t\tconst flipKeyframes: Keyframe[] = [{ translate: `${dx}px ${dy}px` }, { translate: '0px 0px' }]\n\t\tconst anim = container.animate(\n\t\t\tflipKeyframes,\n\t\t\t{\n\t\t\t\tduration: SPRING_SMOOTH.duration,\n\t\t\t\teasing: SPRING_SMOOTH.easingFallback,\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t)\n\t\tfrom(anim.finished).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tif (container.isConnected) container.style.translate = ''\n\t\t\t\t// Report final resting bounds after animation completes\n\t\t\t\tconst finalRect = container.getBoundingClientRect()\n\t\t\t\twindowManager.updateBounds(this.id, { left: finalRect.left, top: finalRect.top, width: finalRect.width, height: finalRect.height })\n\t\t\t}),\n\t\t\tcatchError(() => EMPTY),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tthis._savePosition()\n\t}\n\n\t// ============================================\n\t// DRAG PIPELINE\n\t// ============================================\n\n\tprivate _drag$(): Observable<never> {\n\t\treturn new Observable(() => {\n\t\t\tconst head = this._headRef.value\n\t\t\tconst container = this._containerRef.value\n\t\t\tif (!head || !container) return\n\n\t\t\tlet didDrag = false\n\n\t\t\tconst sub = fromEvent<PointerEvent>(head, 'pointerdown').pipe(\n\t\t\t\tfilter(e => e.button === 0),\n\t\t\t\tfilter(e => {\n\t\t\t\t\tconst tag = (e.target as HTMLElement).tagName?.toLowerCase()\n\t\t\t\t\treturn !['input', 'textarea', 'select', 'button'].includes(tag)\n\t\t\t\t\t\t&& !(e.target as HTMLElement).closest('schmancy-input, schmancy-icon-button, button, a')\n\t\t\t\t}),\n\t\t\t\ttap(e => {\n\t\t\t\t\te.preventDefault()\n\t\t\t\t\te.stopPropagation()\n\t\t\t\t}),\n\t\t\t)\n\t\t\t\t.pipe(\n\t\t\t\t\tmap(e => {\n\t\t\t\t\t\tconst rect = container.getBoundingClientRect()\n\t\t\t\t\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\t\t\t\t\tconst wasOpen = this.open\n\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tstartX: e.clientX,\n\t\t\t\t\t\t\tstartY: e.clientY,\n\t\t\t\t\t\t\toffsetX: e.clientX - rect.left,\n\t\t\t\t\t\t\toffsetY: e.clientY - rect.top,\n\t\t\t\t\t\t\trect,\n\t\t\t\t\t\t\tvw: window.innerWidth,\n\t\t\t\t\t\t\tvh: window.innerHeight,\n\t\t\t\t\t\t\tisBottom,\n\t\t\t\t\t\t\twasOpen,\n\t\t\t\t\t\t\tpointerId: e.pointerId,\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t\tswitchMap(({ startX, startY, offsetX, offsetY, rect, vw, vh, isBottom, wasOpen, pointerId }) => {\n\t\t\t\t\t\tconst move$ = fromEvent<PointerEvent>(window, 'pointermove').pipe(\n\t\t\t\t\t\t\tfilter(e => e.pointerId === pointerId),\n\t\t\t\t\t\t\tauditTime(0, animationFrameScheduler),\n\t\t\t\t\t\t\tmap(e => ({ clientX: e.clientX, clientY: e.clientY })),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst end$ = fromEvent<PointerEvent>(window, 'pointerup').pipe(\n\t\t\t\t\t\t\tfilter(e => e.pointerId === pointerId),\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\treturn move$.pipe(\n\t\t\t\t\t\t\ttap(({ clientX, clientY }) => {\n\t\t\t\t\t\t\t\tconst dx = clientX - startX\n\t\t\t\t\t\t\t\tconst dy = clientY - startY\n\t\t\t\t\t\t\t\tif (Math.sqrt(dx * dx + dy * dy) > DRAG_THRESHOLD && !didDrag) {\n\t\t\t\t\t\t\t\t\tdidDrag = true\n\t\t\t\t\t\t\t\t\tthis._applyDragVisuals(true)\n\t\t\t\t\t\t\t\t\t// Collapse on first confirmed drag move\n\t\t\t\t\t\t\t\t\tif (wasOpen) {\n\t\t\t\t\t\t\t\t\t\tthis.open = false\n\t\t\t\t\t\t\t\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t\t\t\t\t\t\t\t\tcontainer.style.overflow = 'hidden'\n\t\t\t\t\t\t\t\t\t\tconst body = this._bodyRef.value\n\t\t\t\t\t\t\t\t\t\tif (body) {\n\t\t\t\t\t\t\t\t\t\t\tbody.inert = true\n\t\t\t\t\t\t\t\t\t\t\tbody.style.visibility = 'hidden'\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (!didDrag) return\n\n\t\t\t\t\t\t\t\tconst left = Math.max(0, Math.min(clientX - offsetX, vw - rect.width))\n\t\t\t\t\t\t\t\tconst minTop = isBottom ? HEAD_HEIGHT - rect.height : 0\n\t\t\t\t\t\t\t\tconst maxTop = isBottom ? vh - rect.height : vh - HEAD_HEIGHT\n\t\t\t\t\t\t\t\tconst top = Math.max(minTop, Math.min(clientY - offsetY, maxTop))\n\n\t\t\t\t\t\t\t\tthis._position = {\n\t\t\t\t\t\t\t\t\tx: this._currentCorner.includes('right') ? vw - left - rect.width : left,\n\t\t\t\t\t\t\t\t\ty: isBottom ? vh - top - rect.height : top,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis._applyContainerPosition()\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ttakeUntil(end$),\n\t\t\t\t\t\t\tfinalize(() => {\n\t\t\t\t\t\t\t\tif (didDrag) {\n\t\t\t\t\t\t\t\t\tthis._reorientToNearestCorner()\n\t\t\t\t\t\t\t\t\tthis._applyDragVisuals(false)\n\t\t\t\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\t\t\t\tthis.toggle()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.subscribe()\n\n\t\t\treturn () => sub.unsubscribe()\n\t\t})\n\t}\n\n\t// ============================================\n\t// LIFECYCLE\n\t// ============================================\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\t// Pipeline 1: DOM setup + manager registration + drag + z-index sync\n\t\tfrom(this.updateComplete).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tthis._currentCorner = this.corner\n\t\t\t\tthis._loadPosition()\n\t\t\t\tthis._applyContainerPosition()\n\t\t\t\tthis._initDOMState()\n\t\t\t\t// Register with window manager\n\t\t\t\tconst container = this._containerRef.value\n\t\t\t\tif (container) {\n\t\t\t\t\tconst rect = container.getBoundingClientRect()\n\t\t\t\t\tconst bounds: WindowBounds = { left: rect.left, top: rect.top, width: rect.width, height: rect.height }\n\t\t\t\t\twindowManager.register(this.id, bounds, this.freePosition ? 'free' : this._currentCorner)\n\t\t\t\t}\n\t\t\t}),\n\t\t\tswitchMap(() => merge(\n\t\t\t\tthis._drag$(),\n\t\t\t\twindowManager.selectWindow(this.id).pipe(\n\t\t\t\t\ttap(record => {\n\t\t\t\t\t\tif (!record) return\n\t\t\t\t\t\tconst container = this._containerRef.value\n\t\t\t\t\t\tif (container) container.style.zIndex = String(record.zIndex)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\n\t\t// Pipeline 3: Environment -- one subscription\n\t\tmerge(\n\t\t\tfromEvent(window, 'resize').pipe(\n\t\t\t\tauditTime(0, animationFrameScheduler),\n\t\t\t\ttap(() => this._validateBounds()),\n\t\t\t),\n\t\t\ttheme.bottomOffset$.pipe(\n\t\t\t\ttap(() => this._applyContainerPosition()),\n\t\t\t),\n\t\t).pipe(takeUntil(this.disconnecting)).subscribe()\n\t}\n\n\tdisconnectedCallback() {\n\t\tsuper.disconnectedCallback()\n\t\twindowManager.unregister(this.id)\n\t}\n\n\tprivate _initDOMState() {\n\t\tconst container = this._containerRef.value\n\t\tconst body = this._bodyRef.value\n\t\tif (!container) return\n\n\t\tthis._applyContainerPosition()\n\n\t\tif (this.open) {\n\t\t\tthis._hasOpened = true\n\t\t\tcontainer.style.overflow = ''\n\t\t\tif (body) {\n\t\t\t\tbody.inert = false\n\t\t\t\tbody.style.visibility = 'visible'\n\t\t\t}\n\t\t} else {\n\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t\tcontainer.style.overflow = 'hidden'\n\t\t\tif (body) {\n\t\t\t\tbody.inert = true\n\t\t\t\tbody.style.visibility = 'hidden'\n\t\t\t}\n\t\t}\n\t}\n\n\t// ============================================\n\t// ANIMATION\n\t// ============================================\n\n\tprivate _animateOpen() {\n\t\tconst container = this._containerRef.value\n\t\tconst body = this._bodyRef.value\n\t\tif (!container) return\n\n\t\tthis._hasOpened = true\n\t\tthis.open = true\n\n\t\t// Overlap avoidance\n\t\tconst rect = container.getBoundingClientRect()\n\t\tconst projectedBounds: WindowBounds = {\n\t\t\tleft: rect.left,\n\t\t\ttop: this.isBottomCorner ? rect.top - 400 : rect.top,\n\t\t\twidth: rect.width,\n\t\t\theight: 400 + HEAD_HEIGHT,\n\t\t}\n\t\tconst overlaps = windowManager.findOverlaps(projectedBounds, this.id)\n\t\tif (overlaps.length > 0) {\n\t\t\tconst resolved = resolveOverlap(projectedBounds, overlaps, { width: window.innerWidth, height: window.innerHeight })\n\t\t\tif (Math.abs(resolved.left - projectedBounds.left) > 10 || Math.abs(resolved.top - projectedBounds.top) > 10) {\n\t\t\t\tconst isRight = this._currentCorner.includes('right')\n\t\t\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\t\t\tthis._position = {\n\t\t\t\t\tx: isRight ? window.innerWidth - resolved.left - resolved.width : resolved.left,\n\t\t\t\t\ty: isBottom ? window.innerHeight - resolved.top - resolved.height : resolved.top,\n\t\t\t\t}\n\t\t\t\tthis._applyContainerPosition()\n\t\t\t}\n\t\t}\n\n\t\tif (body) {\n\t\t\tbody.style.visibility = 'visible'\n\t\t\tbody.inert = false\n\t\t}\n\n\t\tif (reducedMotion$.value) {\n\t\t\tcontainer.style.clipPath = ''\n\t\t\tcontainer.style.overflow = ''\n\t\t\tthis.dispatchScopedEvent('window-toggle', { state: 'expanded' })\n\t\t\treturn\n\t\t}\n\n\t\tthis._currentAnimation?.cancel()\n\t\tcontainer.style.overflow = 'hidden'\n\t\tcontainer.style.willChange = 'opacity'\n\t\tconst openKeyframes: Keyframe[] = [\n\t\t\t{ clipPath: this.closedClipPath, opacity: 0.95 },\n\t\t\t{ clipPath: this.openClipPath, opacity: 1 },\n\t\t]\n\t\tconst anim = container.animate(openKeyframes, {\n\t\t\tduration: SPRING_SNAPPY.duration,\n\t\t\teasing: SPRING_SNAPPY.easingFallback,\n\t\t\tfill: 'forwards',\n\t\t})\n\t\tthis._currentAnimation = anim\n\n\t\tfrom(anim.finished).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tif (container.isConnected) {\n\t\t\t\t\tcontainer.style.clipPath = ''\n\t\t\t\t\tcontainer.style.overflow = ''\n\t\t\t\t\tcontainer.style.willChange = ''\n\t\t\t\t}\n\t\t\t}),\n\t\t\tcatchError(() => EMPTY),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tthis.dispatchScopedEvent('window-toggle', { state: 'expanded' })\n\t}\n\n\tprivate _animateClose() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\n\t\tif (reducedMotion$.value) {\n\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t\tcontainer.style.overflow = 'hidden'\n\t\t\tthis.open = false\n\t\t\tconst body = this._bodyRef.value\n\t\t\tif (body) { body.inert = true; body.style.visibility = 'hidden' }\n\t\t\tthis.dispatchScopedEvent('window-toggle', { state: 'collapsed' })\n\t\t\treturn\n\t\t}\n\n\t\tthis._currentAnimation?.cancel()\n\t\tcontainer.style.overflow = 'hidden'\n\t\tcontainer.style.willChange = 'opacity'\n\t\tconst closeKeyframes: Keyframe[] = [\n\t\t\t{ clipPath: this.openClipPath, opacity: 1 },\n\t\t\t{ clipPath: this.closedClipPath, opacity: 0.95 },\n\t\t]\n\t\tconst anim = container.animate(closeKeyframes, {\n\t\t\tduration: Math.round(SPRING_SNAPPY.duration * 0.7),\n\t\t\teasing: 'cubic-bezier(0.4, 0, 0.8, 0.15)',\n\t\t\tfill: 'forwards',\n\t\t})\n\t\tthis._currentAnimation = anim\n\n\t\tfrom(anim.finished).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tthis.open = false\n\t\t\t\tcontainer.style.willChange = ''\n\t\t\t\tconst body = this._bodyRef.value\n\t\t\t\tif (body) { body.inert = true; body.style.visibility = 'hidden' }\n\t\t\t}),\n\t\t\tcatchError(() => EMPTY),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tthis.dispatchScopedEvent('window-toggle', { state: 'collapsed' })\n\t}\n\n\t// ============================================\n\t// VISUAL STATE HELPERS\n\t// ============================================\n\n\t/** Apply drag visuals directly on DOM refs — avoids full Lit re-render for cursor + opacity */\n\tprivate _applyDragVisuals(dragging: boolean) {\n\t\tconst head = this._headRef.value\n\t\tconst container = this._containerRef.value\n\t\tif (head) {\n\t\t\thead.classList.toggle('cursor-grabbing', dragging)\n\t\t\thead.classList.toggle('cursor-move', !dragging)\n\t\t}\n\t\tif (container) {\n\t\t\tcontainer.style.opacity = dragging ? '0.95' : ''\n\t\t}\n\t}\n\n\tprivate _handleFocus = () => windowManager.focus(this.id)\n\n\tprivate _handleHeadKeydown = (e: KeyboardEvent) => {\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault()\n\t\t\tthis.toggle()\n\t\t\treturn\n\t\t}\n\t\tif (e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n\t\t\te.preventDefault()\n\t\t\tconst step = e.shiftKey ? 20 : 5\n\t\t\tconst dx = e.key === 'ArrowRight' ? step : e.key === 'ArrowLeft' ? -step : 0\n\t\t\tconst dy = e.key === 'ArrowDown' ? step : e.key === 'ArrowUp' ? -step : 0\n\t\t\tthis._position = { x: this._position.x + dx, y: this._position.y + dy }\n\t\t\tthis._applyContainerPosition()\n\t\t\tthis._savePosition()\n\t\t}\n\t}\n\n\t// ============================================\n\t// PUBLIC API\n\t// ============================================\n\n\ttoggle() {\n\t\tif (this.open) this._animateClose()\n\t\telse this._animateOpen()\n\t}\n\n\texpand() {\n\t\tif (this.open) return\n\t\tthis._animateOpen()\n\t}\n\n\tclose() {\n\t\tif (!this.open) return\n\t\tthis._animateClose()\n\t}\n\n\t// ============================================\n\t// RENDER\n\t// ============================================\n\n\tprotected render(): unknown {\n\t\tconst isBottom = this._currentCorner.startsWith('bottom')\n\n\t\tconst containerClasses = classMap({\n\t\t\tfixed: true,\n\t\t\tflex: true,\n\t\t\t'flex-col': isBottom,\n\t\t\t'flex-col-reverse': !isBottom,\n\t\t\t'z-1000': true,\n\t\t\t'rounded-2xl': this.open,\n\t\t\t'rounded-[22px]': !this.open,\n\t\t\t'overflow-hidden': true,\n\t\t})\n\n\t\tconst containerStyles = styleMap({\n\t\t\twidth: this.panelWidth,\n\t\t\t'max-height': 'calc(100vh - 32px)',\n\t\t\t'pointer-events': 'none',\n\t\t})\n\n\t\tconst bodyStyles = styleMap({\n\t\t\t'pointer-events': this.open ? 'auto' : 'none',\n\t\t})\n\n\t\tconst headClasses = classMap({\n\t\t\t'h-full': true,\n\t\t\t'px-3': true,\n\t\t\tflex: true,\n\t\t\t'items-center': true,\n\t\t\t'gap-2': true,\n\t\t\t'select-none': true,\n\t\t\t'cursor-move': true,\n\t\t})\n\n\t\treturn html`\n\t\t\t<schmancy-surface\n\t\t\t\t${ref(this._containerRef)}\n\t\t\t\ttype=\"glass\"\n\t\t\t\t.elevation=${this.elevation}\n\t\t\t\tclass=${containerClasses}\n\t\t\t\tstyle=${containerStyles}\n\t\t\t\taria-expanded=${this.open}\n\t\t\t\t@pointerdown=${this._handleFocus}\n\t\t\t>\n\t\t\t\t<!-- Details section (visually above summary for bottom corners) -->\n\t\t\t\t<section\n\t\t\t\t\t${ref(this._bodyRef)}\n\t\t\t\t\tclass=\"flex-1 min-h-0 overflow-hidden flex flex-col\"\n\t\t\t\t\tstyle=${bodyStyles}\n\t\t\t\t\trole=\"region\"\n\t\t\t\t\taria-label=\"Expandable content\"\n\t\t\t\t>\n\t\t\t\t\t${this._hasOpened ? html`<slot name=\"details\"></slot>` : nothing}\n\t\t\t\t</section>\n\n\t\t\t\t<!-- Summary section -- always interactive, always visible -->\n\t\t\t\t<section\n\t\t\t\t\tclass=\"shrink-0 bg-surface-lowest\"\n\t\t\t\t\tstyle=${styleMap({ 'pointer-events': 'auto', height: `${HEAD_HEIGHT}px` })}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\t${ref(this._headRef)}\n\t\t\t\t\t\t${cursorGlow({ radius: 200, intensity: 0.10 })}\n\t\t\t\t\t\tclass=${headClasses}\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabindex=\"0\"\n\t\t\t\t\t\ttitle=\"Drag to move, click to expand\"\n\t\t\t\t\t\taria-label=\"${this.open ? 'Collapse window' : 'Expand window'}\"\n\t\t\t\t\t\t@keydown=${this._handleHeadKeydown}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div class=\"flex-1 min-w-0\">\n\t\t\t\t\t\t\t<slot></slot>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\twidth=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n\t\t\t\t\t\t\tclass=\"shrink-0 text-surface-on/40 transition-transform duration-200 ${this.open ? 'rotate-180' : ''}\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t</schmancy-surface>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-window': SchmancyWindow\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"window-Bp7zWZpu.cjs","names":[],"sources":["../src/window/window-manager.ts","../src/window/window-position.ts","../src/window/window.ts"],"sourcesContent":["/**\n * Window Manager — singleton service for multi-window coordination.\n *\n * Tracks all schmancy-window instances: positions, z-indices, focus, visual states.\n * Components register on connectedCallback, unregister on disconnectedCallback.\n * Focus changes, position updates, and overlap queries all flow through here.\n *\n * Follows the ThemeService singleton pattern (theme/theme.service.ts).\n *\n * Example:\n * windowManager.register('chat-1', bounds, 'bottom-right')\n * windowManager.focus('chat-1') // bumps z-index, updates focusedId\n * const overlaps = windowManager.findOverlaps(projectedBounds, 'chat-1')\n */\n\nimport { BehaviorSubject, Observable, distinctUntilChanged, map } from 'rxjs'\nimport { overlayStack } from '../utils/overlay-stack.js'\nimport type { WindowBounds, WindowRecord, WindowRegistryState, SnapTarget } from './window-registry.js'\n\nconst STORAGE_PREFIX = 'schmancy-window-'\nconst LEGACY_STORAGE_PREFIX = 'schmancy-float-'\n\nclass WindowManagerService {\n\tprivate static instance: WindowManagerService\n\n\tprivate readonly _state$ = new BehaviorSubject<WindowRegistryState>({\n\t\twindows: new Map(),\n\t\tfocusedId: null,\n\t\tstackOrder: [],\n\t})\n\n\treadonly state$ = this._state$.asObservable()\n\n\tprivate constructor() {}\n\n\tstatic getInstance(): WindowManagerService {\n\t\tif (!WindowManagerService.instance) {\n\t\t\tWindowManagerService.instance = new WindowManagerService()\n\t\t}\n\t\treturn WindowManagerService.instance\n\t}\n\n\t// ── Synchronous accessors ──────────────────────────────────────────\n\n\tget windows(): Map<string, WindowRecord> {\n\t\treturn this._state$.value.windows\n\t}\n\n\tget focusedId(): string | null {\n\t\treturn this._state$.value.focusedId\n\t}\n\n\t// ── Registration ───────────────────────────────────────────────────\n\n\tregister(id: string, initialBounds: WindowBounds, snapTarget: SnapTarget): void {\n\t\tconst state = this._state$.value\n\t\tif (state.windows.has(id)) return\n\n\t\tconst zIndex = overlayStack.assignZIndex(id)\n\t\tconst record: WindowRecord = {\n\t\t\tid,\n\t\t\tbounds: initialBounds,\n\t\t\tvisualState: 'normal',\n\t\t\tzIndex,\n\t\t\topen: false,\n\t\t\tsnapTarget,\n\t\t}\n\n\t\tconst windows = new Map(state.windows)\n\t\twindows.set(id, record)\n\t\tconst stackOrder = overlayStack.getStackOrder()\n\n\t\tthis._state$.next({ ...state, windows, stackOrder })\n\t}\n\n\tunregister(id: string): void {\n\t\tconst state = this._state$.value\n\t\tif (!state.windows.has(id)) return\n\n\t\toverlayStack.releaseId(id)\n\t\tconst windows = new Map(state.windows)\n\t\twindows.delete(id)\n\t\tconst stackOrder = overlayStack.getStackOrder()\n\t\tconst focusedId = state.focusedId === id ? null : state.focusedId\n\n\t\tthis._state$.next({ ...state, windows, stackOrder, focusedId })\n\t}\n\n\t// ── State mutations ────────────────────────────────────────────────\n\n\tupdateBounds(id: string, bounds: WindowBounds): void {\n\t\tthis._updateRecord(id, { bounds })\n\t}\n\n\tupdateVisualState(id: string, visualState: WindowRecord['visualState']): void {\n\t\tthis._updateRecord(id, { visualState })\n\t}\n\n\tupdateOpen(id: string, open: boolean): void {\n\t\tthis._updateRecord(id, { open })\n\t}\n\n\tfocus(id: string): void {\n\t\tconst state = this._state$.value\n\t\tif (!state.windows.has(id)) return\n\t\tif (state.focusedId === id) return\n\n\t\tconst zIndex = overlayStack.bringToFront(id)\n\t\tconst windows = new Map(state.windows)\n\t\tconst record = windows.get(id)\n\t\tif (record) {\n\t\t\twindows.set(id, { ...record, zIndex })\n\t\t}\n\t\tconst stackOrder = overlayStack.getStackOrder()\n\n\t\tthis._state$.next({ ...state, windows, stackOrder, focusedId: id })\n\t}\n\n\t// ── Queries ────────────────────────────────────────────────────────\n\n\tfindOverlaps(bounds: WindowBounds, excludeId: string): WindowRecord[] {\n\t\tconst result: WindowRecord[] = []\n\t\tfor (const [id, record] of this._state$.value.windows) {\n\t\t\tif (id === excludeId) continue\n\t\t\tif (rectsOverlap(bounds, record.bounds)) {\n\t\t\t\tresult.push(record)\n\t\t\t}\n\t\t}\n\t\treturn result\n\t}\n\n\tgetNeighbors(id: string): WindowRecord[] {\n\t\tconst result: WindowRecord[] = []\n\t\tfor (const [otherId, record] of this._state$.value.windows) {\n\t\t\tif (otherId !== id) result.push(record)\n\t\t}\n\t\treturn result\n\t}\n\n\t// ── Selectors ──────────────────────────────────────────────────────\n\n\tselectWindow(id: string): Observable<WindowRecord | undefined> {\n\t\treturn this._state$.pipe(\n\t\t\tmap(state => state.windows.get(id)),\n\t\t\tdistinctUntilChanged(),\n\t\t)\n\t}\n\n\tselectFocused(): Observable<string | null> {\n\t\treturn this._state$.pipe(\n\t\t\tmap(state => state.focusedId),\n\t\t\tdistinctUntilChanged(),\n\t\t)\n\t}\n\n\t// ── Persistence ────────────────────────────────────────────────────\n\n\tloadPosition(id: string): { x: number; y: number; anchor: string } | null {\n\t\ttry {\n\t\t\t// Try new key first, fall back to legacy\n\t\t\tconst raw = localStorage.getItem(STORAGE_PREFIX + id) ?? localStorage.getItem(LEGACY_STORAGE_PREFIX + id)\n\t\t\tif (!raw) return null\n\t\t\treturn JSON.parse(raw) as { x: number; y: number; anchor: string }\n\t\t} catch {\n\t\t\treturn null\n\t\t}\n\t}\n\n\tsavePosition(id: string, data: { x: number; y: number; anchor: string }): void {\n\t\ttry {\n\t\t\tlocalStorage.setItem(STORAGE_PREFIX + id, JSON.stringify(data))\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\tclearPosition(id: string): void {\n\t\ttry {\n\t\t\tlocalStorage.removeItem(STORAGE_PREFIX + id)\n\t\t\tlocalStorage.removeItem(LEGACY_STORAGE_PREFIX + id)\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t}\n\n\t// ── Internal ───────────────────────────────────────────────────────\n\n\tprivate _updateRecord(id: string, updates: Partial<WindowRecord>): void {\n\t\tconst state = this._state$.value\n\t\tconst record = state.windows.get(id)\n\t\tif (!record) return\n\n\t\tconst windows = new Map(state.windows)\n\t\twindows.set(id, { ...record, ...updates })\n\t\tthis._state$.next({ ...state, windows })\n\t}\n}\n\n/** Simple rect overlap check (inline — no circular import with window-position) */\nfunction rectsOverlap(a: WindowBounds, b: WindowBounds): boolean {\n\treturn !(a.left >= b.left + b.width || a.left + a.width <= b.left || a.top >= b.top + b.height || a.top + a.height <= b.top)\n}\n\nexport const windowManager = WindowManagerService.getInstance()\n","/**\n * Window Position — pure functions for overlap resolution, cascade, and snapping.\n *\n * All functions are stateless: they take window bounds and viewport dimensions,\n * return new bounds. No side effects, no DOM access, no subscriptions.\n *\n * Example:\n * const projected = { left: 100, top: 400, width: 360, height: 500 }\n * const neighbors = windowManager.findOverlaps(projected, 'my-id')\n * const resolved = resolveOverlap(projected, neighbors, { width: 1440, height: 900 })\n * // → { left: 144, top: 444, width: 360, height: 500 } (cascaded away from conflict)\n */\n\nimport type { WindowBounds, WindowRecord } from './window-registry.js'\n\nconst HEAD_HEIGHT = 44\nconst CASCADE_OFFSET = HEAD_HEIGHT\nconst MAX_CASCADE_ATTEMPTS = 10\n\n/** Check if two rectangles overlap (edges touching does NOT count as overlap) */\nexport function rectsOverlap(a: WindowBounds, b: WindowBounds): boolean {\n\treturn !(a.left >= b.left + b.width || a.left + a.width <= b.left || a.top >= b.top + b.height || a.top + a.height <= b.top)\n}\n\n/**\n * Resolve overlap by cascading diagonally until no conflict.\n * Shifts by (HEAD_HEIGHT, HEAD_HEIGHT) per attempt, clamped to viewport.\n */\nexport function resolveOverlap(\n\tcandidate: WindowBounds,\n\texisting: WindowRecord[],\n\tviewport: { width: number; height: number },\n): WindowBounds {\n\tconst bounds = { ...candidate }\n\n\tfor (let attempt = 0; attempt < MAX_CASCADE_ATTEMPTS; attempt++) {\n\t\tconst hasOverlap = existing.some(w => rectsOverlap(bounds, w.bounds))\n\t\tif (!hasOverlap) break\n\n\t\tbounds.left += CASCADE_OFFSET\n\t\tbounds.top += CASCADE_OFFSET\n\t}\n\n\treturn clampToViewport(bounds, viewport)\n}\n\n/**\n * Clamp bounds so the window stays fully within the viewport.\n */\nexport function clampToViewport(\n\tbounds: WindowBounds,\n\tviewport: { width: number; height: number },\n): WindowBounds {\n\treturn {\n\t\twidth: bounds.width,\n\t\theight: bounds.height,\n\t\tleft: Math.max(0, Math.min(bounds.left, viewport.width - bounds.width)),\n\t\ttop: Math.max(0, Math.min(bounds.top, viewport.height - bounds.height)),\n\t}\n}\n","import { SchmancyElement } from '@mixins/index'\nimport { css, html, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { styleMap } from 'lit/directives/style-map.js'\nimport {\n\tanimationFrameScheduler,\n\tauditTime,\n\tcatchError,\n\tEMPTY,\n\tfilter,\n\tfinalize,\n\tfrom,\n\tfromEvent,\n\tmap,\n\tmerge,\n\tObservable,\n\tswitchMap,\n\ttake,\n\ttakeUntil,\n\ttap,\n} from 'rxjs'\nimport { SPRING_SMOOTH, SPRING_SNAPPY } from '../utils/animation.js'\nimport { cursorGlow } from '../directives/cursor-glow'\nimport { reducedMotion$ } from '../directives/reduced-motion'\nimport { theme } from '../theme/theme.service.js'\nimport type { SnapCorner, WindowBounds, WindowVisualState } from './window-registry.js'\nimport { windowManager } from './window-manager.js'\nimport { resolveOverlap } from './window-position.js'\n\nconst HEAD_HEIGHT = 48\nconst DRAG_THRESHOLD = 5\n\ninterface Position {\n\tx: number\n\ty: number\n}\n\n@customElement('schmancy-window')\nexport default class SchmancyWindow extends SchmancyElement {\n\tstatic styles = [css`\n\t:host {\n\t\tdisplay: contents;\n\t\tposition: relative;\n\t\tz-index: 1000;\n\t}\n\t:host([hidden]) {\n\t\tdisplay: none !important;\n\t}\n`]\n\n\t@property({ type: String }) id: string = 'default'\n\t/** Override the expanded panel width (e.g. '320px', '24rem'). Defaults to responsive sizing. */\n\t@property({ type: String }) expandedWidth?: string\n\t/** Override the expanded panel height (e.g. '400px', '50vh'). */\n\t@property({ type: String }) expandedHeight?: string\n\t/** When true, uses a lower elevation shadow in the collapsed state. */\n\t@property({ type: Boolean, reflect: true }) lowered: boolean = false\n\t/** Corner the window is anchored to. */\n\t@property({ type: String }) corner: SnapCorner = 'bottom-right'\n\t/** When true, window can be resized by the user. */\n\t@property({ type: Boolean }) resizable = false\n\t/** When true, window stays at its dragged position instead of snapping to a corner. */\n\t@property({ type: Boolean }) freePosition = false\n\t/** Visual state of the window (minimized, normal, maximized). */\n\t@property({ type: String, reflect: true }) visualState: WindowVisualState = 'normal'\n\t/** Minimum width in pixels. */\n\t@property({ type: Number }) minWidth = 280\n\t/** Minimum height in pixels. */\n\t@property({ type: Number }) minHeight = 200\n\n\t/** Whether the body is expanded. */\n\t@property({ type: Boolean, reflect: true }) open = false\n\n\tprivate _currentAnimation?: Animation\n\n\t/** Lazy rendering: body content not in DOM until first expand. */\n\t@state() private _hasOpened = false\n\n\t// Internal position -- plain fields, updated directly during drag\n\tprivate _position: Position = { x: 16, y: 16 }\n\t@state() private _currentCorner: SnapCorner = 'bottom-right'\n\n\t// Track applied corner to avoid unnecessary style.removeProperty calls during drag\n\tprivate _appliedCorner: string = ''\n\n\t// Refs\n\tprivate _containerRef = createRef<HTMLElement>()\n\tprivate _bodyRef = createRef<HTMLElement>()\n\tprivate _headRef = createRef<HTMLElement>()\n\n\t// ============================================\n\t// COMPUTED\n\t// ============================================\n\n\tprivate get panelWidth(): string {\n\t\treturn this.expandedWidth ?? 'min(360px, calc(100vw - 32px))'\n\t}\n\n\tprivate get isBottomCorner(): boolean {\n\t\treturn this._currentCorner.startsWith('bottom')\n\t}\n\n\tprivate get closedClipPath(): string {\n\t\treturn this.isBottomCorner\n\t\t\t? `inset(calc(100% - ${HEAD_HEIGHT}px) 0px 0px 0px round 22px)`\n\t\t\t: `inset(0px 0px calc(100% - ${HEAD_HEIGHT}px) 0px round 22px)`\n\t}\n\n\tprivate get openClipPath(): string {\n\t\treturn 'inset(0px 0px 0px 0px round 12px)'\n\t}\n\n\tprivate get elevation(): 0 | 1 | 2 | 3 | 4 | 5 {\n\t\tif (this.open) return 4\n\t\treturn this.lowered ? 1 : 3\n\t}\n\n\t// ============================================\n\t// POSITION MANAGEMENT\n\t// ============================================\n\n\tprivate _applyContainerPosition() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\t\t// Only clear position properties when corner changes (avoids 4 style invalidations per drag frame)\n\t\tif (this._appliedCorner !== this._currentCorner) {\n\t\t\tcontainer.style.removeProperty('left')\n\t\t\tcontainer.style.removeProperty('right')\n\t\t\tcontainer.style.removeProperty('top')\n\t\t\tcontainer.style.removeProperty('bottom')\n\t\t\tthis._appliedCorner = this._currentCorner\n\t\t}\n\t\tconst { x, y } = this._position\n\t\tif (this._currentCorner.includes('right')) {\n\t\t\tcontainer.style.right = `${x}px`\n\t\t} else {\n\t\t\tcontainer.style.left = `${x}px`\n\t\t}\n\t\tif (this._currentCorner.includes('bottom')) {\n\t\t\tcontainer.style.bottom = `${y + theme.bottomOffset}px`\n\t\t} else {\n\t\t\tcontainer.style.top = `${y}px`\n\t\t}\n\t}\n\n\tprivate static readonly VALID_CORNERS = new Set<string>(['top-left', 'top-right', 'bottom-left', 'bottom-right'])\n\n\tprivate _loadPosition() {\n\t\tconst saved = windowManager.loadPosition(this.id)\n\t\tif (saved) {\n\t\t\tthis._position = { x: saved.x, y: saved.y }\n\t\t\tif (SchmancyWindow.VALID_CORNERS.has(saved.anchor)) {\n\t\t\t\tthis._currentCorner = saved.anchor as SnapCorner\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _savePosition() {\n\t\twindowManager.savePosition(this.id, { ...this._position, anchor: this._currentCorner })\n\t}\n\n\tprivate _validateBounds() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tif (rect.width === 0) return\n\t\tconst vw = window.innerWidth\n\t\tconst vh = window.innerHeight\n\t\tconst isRight = this._currentCorner.includes('right')\n\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\tconst actualLeft = isRight ? vw - this._position.x - rect.width : this._position.x\n\t\tconst actualTop = isBottom ? vh - this._position.y - rect.height : this._position.y\n\t\tconst newLeft = Math.max(0, Math.min(actualLeft, vw - rect.width))\n\t\tconst newTop = Math.max(0, Math.min(actualTop, vh - rect.height))\n\t\tthis._position = {\n\t\t\tx: isRight ? vw - newLeft - rect.width : newLeft,\n\t\t\ty: isBottom ? vh - newTop - rect.height : newTop,\n\t\t}\n\t\tthis._applyContainerPosition()\n\t}\n\n\t// ============================================\n\t// CORNER SNAPPING\n\t// ============================================\n\n\tprivate _reorientToNearestCorner(skipAnimation = false): void {\n\t\t// Free position mode: skip corner snapping\n\t\tif (this.freePosition) {\n\t\t\tthis._savePosition()\n\t\t\tconst rect = this._containerRef.value?.getBoundingClientRect()\n\t\t\tif (rect) {\n\t\t\t\twindowManager.updateBounds(this.id, { left: rect.left, top: rect.top, width: rect.width, height: rect.height })\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\n\t\t// F -- record current screen position before DOM mutation\n\t\tconst rect = container.getBoundingClientRect()\n\n\t\t// L -- calculate nearest corner using head visual center\n\t\tconst currentIsBottom = this._currentCorner.includes('bottom')\n\t\tconst headCenterX = rect.left + rect.width / 2\n\t\tconst headCenterY = currentIsBottom\n\t\t\t? rect.bottom - HEAD_HEIGHT / 2\n\t\t\t: rect.top + HEAD_HEIGHT / 2\n\t\tconst side = headCenterX > window.innerWidth / 2 ? 'right' : 'left'\n\t\tconst vert = headCenterY > window.innerHeight / 2 ? 'bottom' : 'top'\n\t\tconst newCorner: SnapCorner = `${vert}-${side}` as SnapCorner\n\n\t\t// Snap corner and reset offset to standard edge gap\n\t\tthis._currentCorner = newCorner\n\t\tthis._position = { x: 16, y: 16 }\n\t\tthis._applyContainerPosition()\n\t\t// Sync clip-path to new corner\n\t\tif (!this.open) {\n\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t}\n\n\t\tif (skipAnimation || reducedMotion$.value) {\n\t\t\tthis._savePosition()\n\t\t\tconst snapRect = container.getBoundingClientRect()\n\t\t\twindowManager.updateBounds(this.id, { left: snapRect.left, top: snapRect.top, width: snapRect.width, height: snapRect.height })\n\t\t\treturn\n\t\t}\n\n\t\t// I -- invert: shift element back to its original visual position\n\t\tconst newRect = container.getBoundingClientRect()\n\t\tconst dx = rect.left - newRect.left\n\t\tconst dy = rect.top - newRect.top\n\t\tcontainer.style.translate = `${dx}px ${dy}px`\n\n\t\t// P -- play: animate from the inverse offset to natural resting position\n\t\tconst flipKeyframes: Keyframe[] = [{ translate: `${dx}px ${dy}px` }, { translate: '0px 0px' }]\n\t\tconst anim = container.animate(\n\t\t\tflipKeyframes,\n\t\t\t{\n\t\t\t\tduration: SPRING_SMOOTH.duration,\n\t\t\t\teasing: SPRING_SMOOTH.easingFallback,\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t)\n\t\tfrom(anim.finished).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tif (container.isConnected) container.style.translate = ''\n\t\t\t\t// Report final resting bounds after animation completes\n\t\t\t\tconst finalRect = container.getBoundingClientRect()\n\t\t\t\twindowManager.updateBounds(this.id, { left: finalRect.left, top: finalRect.top, width: finalRect.width, height: finalRect.height })\n\t\t\t}),\n\t\t\tcatchError(() => EMPTY),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tthis._savePosition()\n\t}\n\n\t// ============================================\n\t// DRAG PIPELINE\n\t// ============================================\n\n\tprivate _drag$(): Observable<never> {\n\t\treturn new Observable(() => {\n\t\t\tconst head = this._headRef.value\n\t\t\tconst container = this._containerRef.value\n\t\t\tif (!head || !container) return\n\n\t\t\tlet didDrag = false\n\n\t\t\tconst sub = fromEvent<PointerEvent>(head, 'pointerdown').pipe(\n\t\t\t\tfilter(e => e.button === 0),\n\t\t\t\tfilter(e => {\n\t\t\t\t\tconst tag = (e.target as HTMLElement).tagName?.toLowerCase()\n\t\t\t\t\treturn !['input', 'textarea', 'select', 'button'].includes(tag)\n\t\t\t\t\t\t&& !(e.target as HTMLElement).closest('schmancy-input, schmancy-icon-button, button, a')\n\t\t\t\t}),\n\t\t\t\ttap(e => {\n\t\t\t\t\te.preventDefault()\n\t\t\t\t\te.stopPropagation()\n\t\t\t\t}),\n\t\t\t)\n\t\t\t\t.pipe(\n\t\t\t\t\tmap(e => {\n\t\t\t\t\t\tconst rect = container.getBoundingClientRect()\n\t\t\t\t\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\t\t\t\t\tconst wasOpen = this.open\n\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tstartX: e.clientX,\n\t\t\t\t\t\t\tstartY: e.clientY,\n\t\t\t\t\t\t\toffsetX: e.clientX - rect.left,\n\t\t\t\t\t\t\toffsetY: e.clientY - rect.top,\n\t\t\t\t\t\t\trect,\n\t\t\t\t\t\t\tvw: window.innerWidth,\n\t\t\t\t\t\t\tvh: window.innerHeight,\n\t\t\t\t\t\t\tisBottom,\n\t\t\t\t\t\t\twasOpen,\n\t\t\t\t\t\t\tpointerId: e.pointerId,\n\t\t\t\t\t\t}\n\t\t\t\t\t}),\n\t\t\t\t\tswitchMap(({ startX, startY, offsetX, offsetY, rect, vw, vh, isBottom, wasOpen, pointerId }) => {\n\t\t\t\t\t\tconst move$ = fromEvent<PointerEvent>(window, 'pointermove').pipe(\n\t\t\t\t\t\t\tfilter(e => e.pointerId === pointerId),\n\t\t\t\t\t\t\tauditTime(0, animationFrameScheduler),\n\t\t\t\t\t\t\tmap(e => ({ clientX: e.clientX, clientY: e.clientY })),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tconst end$ = fromEvent<PointerEvent>(window, 'pointerup').pipe(\n\t\t\t\t\t\t\tfilter(e => e.pointerId === pointerId),\n\t\t\t\t\t\t)\n\n\t\t\t\t\t\treturn move$.pipe(\n\t\t\t\t\t\t\ttap(({ clientX, clientY }) => {\n\t\t\t\t\t\t\t\tconst dx = clientX - startX\n\t\t\t\t\t\t\t\tconst dy = clientY - startY\n\t\t\t\t\t\t\t\tif (Math.sqrt(dx * dx + dy * dy) > DRAG_THRESHOLD && !didDrag) {\n\t\t\t\t\t\t\t\t\tdidDrag = true\n\t\t\t\t\t\t\t\t\tthis._applyDragVisuals(true)\n\t\t\t\t\t\t\t\t\t// Collapse on first confirmed drag move\n\t\t\t\t\t\t\t\t\tif (wasOpen) {\n\t\t\t\t\t\t\t\t\t\tthis.open = false\n\t\t\t\t\t\t\t\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t\t\t\t\t\t\t\t\tcontainer.style.overflow = 'hidden'\n\t\t\t\t\t\t\t\t\t\tconst body = this._bodyRef.value\n\t\t\t\t\t\t\t\t\t\tif (body) {\n\t\t\t\t\t\t\t\t\t\t\tbody.inert = true\n\t\t\t\t\t\t\t\t\t\t\tbody.style.visibility = 'hidden'\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (!didDrag) return\n\n\t\t\t\t\t\t\t\tconst left = Math.max(0, Math.min(clientX - offsetX, vw - rect.width))\n\t\t\t\t\t\t\t\tconst minTop = isBottom ? HEAD_HEIGHT - rect.height : 0\n\t\t\t\t\t\t\t\tconst maxTop = isBottom ? vh - rect.height : vh - HEAD_HEIGHT\n\t\t\t\t\t\t\t\tconst top = Math.max(minTop, Math.min(clientY - offsetY, maxTop))\n\n\t\t\t\t\t\t\t\tthis._position = {\n\t\t\t\t\t\t\t\t\tx: this._currentCorner.includes('right') ? vw - left - rect.width : left,\n\t\t\t\t\t\t\t\t\ty: isBottom ? vh - top - rect.height : top,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis._applyContainerPosition()\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\ttakeUntil(end$),\n\t\t\t\t\t\t\tfinalize(() => {\n\t\t\t\t\t\t\t\tif (didDrag) {\n\t\t\t\t\t\t\t\t\tthis._reorientToNearestCorner()\n\t\t\t\t\t\t\t\t\tthis._applyDragVisuals(false)\n\t\t\t\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\t\t\t\tthis.toggle()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.subscribe()\n\n\t\t\treturn () => sub.unsubscribe()\n\t\t})\n\t}\n\n\t// ============================================\n\t// LIFECYCLE\n\t// ============================================\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\t// Pipeline 1: DOM setup + manager registration + drag + z-index sync\n\t\tfrom(this.updateComplete).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tthis._currentCorner = this.corner\n\t\t\t\tthis._loadPosition()\n\t\t\t\tthis._applyContainerPosition()\n\t\t\t\tthis._initDOMState()\n\t\t\t\t// Register with window manager\n\t\t\t\tconst container = this._containerRef.value\n\t\t\t\tif (container) {\n\t\t\t\t\tconst rect = container.getBoundingClientRect()\n\t\t\t\t\tconst bounds: WindowBounds = { left: rect.left, top: rect.top, width: rect.width, height: rect.height }\n\t\t\t\t\twindowManager.register(this.id, bounds, this.freePosition ? 'free' : this._currentCorner)\n\t\t\t\t}\n\t\t\t}),\n\t\t\tswitchMap(() => merge(\n\t\t\t\tthis._drag$(),\n\t\t\t\twindowManager.selectWindow(this.id).pipe(\n\t\t\t\t\ttap(record => {\n\t\t\t\t\t\tif (!record) return\n\t\t\t\t\t\tconst container = this._containerRef.value\n\t\t\t\t\t\tif (container) container.style.zIndex = String(record.zIndex)\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t)),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\n\t\t// Pipeline 3: Environment -- one subscription\n\t\tmerge(\n\t\t\tfromEvent(window, 'resize').pipe(\n\t\t\t\tauditTime(0, animationFrameScheduler),\n\t\t\t\ttap(() => this._validateBounds()),\n\t\t\t),\n\t\t\ttheme.bottomOffset$.pipe(\n\t\t\t\ttap(() => this._applyContainerPosition()),\n\t\t\t),\n\t\t).pipe(takeUntil(this.disconnecting)).subscribe()\n\t}\n\n\tdisconnectedCallback() {\n\t\tsuper.disconnectedCallback()\n\t\twindowManager.unregister(this.id)\n\t}\n\n\tprivate _initDOMState() {\n\t\tconst container = this._containerRef.value\n\t\tconst body = this._bodyRef.value\n\t\tif (!container) return\n\n\t\tthis._applyContainerPosition()\n\n\t\tif (this.open) {\n\t\t\tthis._hasOpened = true\n\t\t\tcontainer.style.overflow = ''\n\t\t\tif (body) {\n\t\t\t\tbody.inert = false\n\t\t\t\tbody.style.visibility = 'visible'\n\t\t\t}\n\t\t} else {\n\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t\tcontainer.style.overflow = 'hidden'\n\t\t\tif (body) {\n\t\t\t\tbody.inert = true\n\t\t\t\tbody.style.visibility = 'hidden'\n\t\t\t}\n\t\t}\n\t}\n\n\t// ============================================\n\t// ANIMATION\n\t// ============================================\n\n\tprivate _animateOpen() {\n\t\tconst container = this._containerRef.value\n\t\tconst body = this._bodyRef.value\n\t\tif (!container) return\n\n\t\tthis._hasOpened = true\n\t\tthis.open = true\n\n\t\t// Overlap avoidance\n\t\tconst rect = container.getBoundingClientRect()\n\t\tconst projectedBounds: WindowBounds = {\n\t\t\tleft: rect.left,\n\t\t\ttop: this.isBottomCorner ? rect.top - 400 : rect.top,\n\t\t\twidth: rect.width,\n\t\t\theight: 400 + HEAD_HEIGHT,\n\t\t}\n\t\tconst overlaps = windowManager.findOverlaps(projectedBounds, this.id)\n\t\tif (overlaps.length > 0) {\n\t\t\tconst resolved = resolveOverlap(projectedBounds, overlaps, { width: window.innerWidth, height: window.innerHeight })\n\t\t\tif (Math.abs(resolved.left - projectedBounds.left) > 10 || Math.abs(resolved.top - projectedBounds.top) > 10) {\n\t\t\t\tconst isRight = this._currentCorner.includes('right')\n\t\t\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\t\t\tthis._position = {\n\t\t\t\t\tx: isRight ? window.innerWidth - resolved.left - resolved.width : resolved.left,\n\t\t\t\t\ty: isBottom ? window.innerHeight - resolved.top - resolved.height : resolved.top,\n\t\t\t\t}\n\t\t\t\tthis._applyContainerPosition()\n\t\t\t}\n\t\t}\n\n\t\tif (body) {\n\t\t\tbody.style.visibility = 'visible'\n\t\t\tbody.inert = false\n\t\t}\n\n\t\tif (reducedMotion$.value) {\n\t\t\tcontainer.style.clipPath = ''\n\t\t\tcontainer.style.overflow = ''\n\t\t\tthis.dispatchScopedEvent('window-toggle', { state: 'expanded' })\n\t\t\treturn\n\t\t}\n\n\t\tthis._currentAnimation?.cancel()\n\t\tcontainer.style.overflow = 'hidden'\n\t\tcontainer.style.willChange = 'opacity'\n\t\tconst openKeyframes: Keyframe[] = [\n\t\t\t{ clipPath: this.closedClipPath, opacity: 0.95 },\n\t\t\t{ clipPath: this.openClipPath, opacity: 1 },\n\t\t]\n\t\tconst anim = container.animate(openKeyframes, {\n\t\t\tduration: SPRING_SNAPPY.duration,\n\t\t\teasing: SPRING_SNAPPY.easingFallback,\n\t\t\tfill: 'forwards',\n\t\t})\n\t\tthis._currentAnimation = anim\n\n\t\tfrom(anim.finished).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tif (container.isConnected) {\n\t\t\t\t\tcontainer.style.clipPath = ''\n\t\t\t\t\tcontainer.style.overflow = ''\n\t\t\t\t\tcontainer.style.willChange = ''\n\t\t\t\t}\n\t\t\t}),\n\t\t\tcatchError(() => EMPTY),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tthis.dispatchScopedEvent('window-toggle', { state: 'expanded' })\n\t}\n\n\tprivate _animateClose() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\n\t\tif (reducedMotion$.value) {\n\t\t\tcontainer.style.clipPath = this.closedClipPath\n\t\t\tcontainer.style.overflow = 'hidden'\n\t\t\tthis.open = false\n\t\t\tconst body = this._bodyRef.value\n\t\t\tif (body) { body.inert = true; body.style.visibility = 'hidden' }\n\t\t\tthis.dispatchScopedEvent('window-toggle', { state: 'collapsed' })\n\t\t\treturn\n\t\t}\n\n\t\tthis._currentAnimation?.cancel()\n\t\tcontainer.style.overflow = 'hidden'\n\t\tcontainer.style.willChange = 'opacity'\n\t\tconst closeKeyframes: Keyframe[] = [\n\t\t\t{ clipPath: this.openClipPath, opacity: 1 },\n\t\t\t{ clipPath: this.closedClipPath, opacity: 0.95 },\n\t\t]\n\t\tconst anim = container.animate(closeKeyframes, {\n\t\t\tduration: Math.round(SPRING_SNAPPY.duration * 0.7),\n\t\t\teasing: 'cubic-bezier(0.4, 0, 0.8, 0.15)',\n\t\t\tfill: 'forwards',\n\t\t})\n\t\tthis._currentAnimation = anim\n\n\t\tfrom(anim.finished).pipe(\n\t\t\ttake(1),\n\t\t\ttap(() => {\n\t\t\t\tthis.open = false\n\t\t\t\tcontainer.style.willChange = ''\n\t\t\t\tconst body = this._bodyRef.value\n\t\t\t\tif (body) { body.inert = true; body.style.visibility = 'hidden' }\n\t\t\t}),\n\t\t\tcatchError(() => EMPTY),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\n\t\tthis.dispatchScopedEvent('window-toggle', { state: 'collapsed' })\n\t}\n\n\t// ============================================\n\t// VISUAL STATE HELPERS\n\t// ============================================\n\n\t/** Apply drag visuals directly on DOM refs — avoids full Lit re-render for cursor + opacity */\n\tprivate _applyDragVisuals(dragging: boolean) {\n\t\tconst head = this._headRef.value\n\t\tconst container = this._containerRef.value\n\t\tif (head) {\n\t\t\thead.classList.toggle('cursor-grabbing', dragging)\n\t\t\thead.classList.toggle('cursor-move', !dragging)\n\t\t}\n\t\tif (container) {\n\t\t\tcontainer.style.opacity = dragging ? '0.95' : ''\n\t\t}\n\t}\n\n\tprivate _handleFocus = () => windowManager.focus(this.id)\n\n\tprivate _handleHeadKeydown = (e: KeyboardEvent) => {\n\t\tif (e.key === 'Enter' || e.key === ' ') {\n\t\t\te.preventDefault()\n\t\t\tthis.toggle()\n\t\t\treturn\n\t\t}\n\t\tif (e.key === 'ArrowUp' || e.key === 'ArrowDown' || e.key === 'ArrowLeft' || e.key === 'ArrowRight') {\n\t\t\te.preventDefault()\n\t\t\tconst step = e.shiftKey ? 20 : 5\n\t\t\tconst dx = e.key === 'ArrowRight' ? step : e.key === 'ArrowLeft' ? -step : 0\n\t\t\tconst dy = e.key === 'ArrowDown' ? step : e.key === 'ArrowUp' ? -step : 0\n\t\t\tthis._position = { x: this._position.x + dx, y: this._position.y + dy }\n\t\t\tthis._applyContainerPosition()\n\t\t\tthis._savePosition()\n\t\t}\n\t}\n\n\t// ============================================\n\t// PUBLIC API\n\t// ============================================\n\n\ttoggle() {\n\t\tif (this.open) this._animateClose()\n\t\telse this._animateOpen()\n\t}\n\n\texpand() {\n\t\tif (this.open) return\n\t\tthis._animateOpen()\n\t}\n\n\tclose() {\n\t\tif (!this.open) return\n\t\tthis._animateClose()\n\t}\n\n\t// ============================================\n\t// RENDER\n\t// ============================================\n\n\tprotected render(): unknown {\n\t\tconst isBottom = this._currentCorner.startsWith('bottom')\n\n\t\tconst containerClasses = classMap({\n\t\t\tfixed: true,\n\t\t\tflex: true,\n\t\t\t'flex-col': isBottom,\n\t\t\t'flex-col-reverse': !isBottom,\n\t\t\t'z-1000': true,\n\t\t\t'rounded-2xl': this.open,\n\t\t\t'rounded-[22px]': !this.open,\n\t\t\t'overflow-hidden': true,\n\t\t})\n\n\t\tconst containerStyles = styleMap({\n\t\t\twidth: this.panelWidth,\n\t\t\t'max-height': 'calc(100vh - 32px)',\n\t\t\t'pointer-events': 'none',\n\t\t})\n\n\t\tconst bodyStyles = styleMap({\n\t\t\t'pointer-events': this.open ? 'auto' : 'none',\n\t\t})\n\n\t\tconst headClasses = classMap({\n\t\t\t'h-full': true,\n\t\t\t'px-3': true,\n\t\t\tflex: true,\n\t\t\t'items-center': true,\n\t\t\t'gap-2': true,\n\t\t\t'select-none': true,\n\t\t\t'cursor-move': true,\n\t\t})\n\n\t\treturn html`\n\t\t\t<schmancy-surface\n\t\t\t\t${ref(this._containerRef)}\n\t\t\t\ttype=\"glass\"\n\t\t\t\t.elevation=${this.elevation}\n\t\t\t\tclass=${containerClasses}\n\t\t\t\tstyle=${containerStyles}\n\t\t\t\taria-expanded=${this.open}\n\t\t\t\t@pointerdown=${this._handleFocus}\n\t\t\t>\n\t\t\t\t<!-- Details section (visually above summary for bottom corners) -->\n\t\t\t\t<section\n\t\t\t\t\t${ref(this._bodyRef)}\n\t\t\t\t\tclass=\"flex-1 min-h-0 overflow-hidden flex flex-col\"\n\t\t\t\t\tstyle=${bodyStyles}\n\t\t\t\t\trole=\"region\"\n\t\t\t\t\taria-label=\"Expandable content\"\n\t\t\t\t>\n\t\t\t\t\t${this._hasOpened ? html`<slot name=\"details\"></slot>` : nothing}\n\t\t\t\t</section>\n\n\t\t\t\t<!-- Summary section -- always interactive, always visible -->\n\t\t\t\t<section\n\t\t\t\t\tclass=\"shrink-0 bg-surface-lowest\"\n\t\t\t\t\tstyle=${styleMap({ 'pointer-events': 'auto', height: `${HEAD_HEIGHT}px` })}\n\t\t\t\t>\n\t\t\t\t\t<div\n\t\t\t\t\t\t${ref(this._headRef)}\n\t\t\t\t\t\t${cursorGlow({ radius: 200, intensity: 0.10 })}\n\t\t\t\t\t\tclass=${headClasses}\n\t\t\t\t\t\trole=\"button\"\n\t\t\t\t\t\ttabindex=\"0\"\n\t\t\t\t\t\ttitle=\"Drag to move, click to expand\"\n\t\t\t\t\t\taria-label=\"${this.open ? 'Collapse window' : 'Expand window'}\"\n\t\t\t\t\t\t@keydown=${this._handleHeadKeydown}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div class=\"flex-1 min-w-0\">\n\t\t\t\t\t\t\t<slot></slot>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\twidth=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\"\n\t\t\t\t\t\t\tclass=\"shrink-0 text-surface-on/40 transition-transform duration-200 ${this.open ? 'rotate-180' : ''}\"\n\t\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<path d=\"M6 9L12 15L18 9\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t</schmancy-surface>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-window': SchmancyWindow\n\t}\n}\n"],"mappings":"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"}
package/dist/window.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./window-BbWlaPZv.cjs`);exports.SchmancyWindow=e.t,exports.windowManager=e.n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./window-Bp7zWZpu.cjs`);exports.SchmancyWindow=e.t,exports.windowManager=e.n;
package/dist/window.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as e, t } from "./window-DuDAQa6y.js";
1
+ import { n as e, t } from "./window-BT9JecWy.js";
2
2
  export { t as SchmancyWindow, e as windowManager };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhmo91/schmancy",
3
- "version": "0.10.23",
3
+ "version": "0.10.25",
4
4
  "description": "UI library build with web components",
5
5
  "main": "./dist/index.js",
6
6
  "customElements": "custom-elements.json",
@@ -11,6 +11,7 @@ The framework pieces — touch before components.
11
11
  - [Mixins](./mixins.md) — `SchmancyElement` base class.
12
12
  - [Theme](./theme.md) — `<schmancy-theme>`, color scheme, CSS variables.
13
13
  - [Directives](./directives.md) — Lit directives for physics, effects, text, visibility, interaction.
14
+ - [Layout](./layout.md) — `fill()` + `overflowWithin()` directives for app-shell sizing (replaces `<schmancy-page>`).
14
15
  - [Animation](./animation.md) — Spring presets (`SPRING_SMOOTH`, etc.), `createAnimation`.
15
16
 
16
17
  ## Components by job
@@ -21,7 +22,7 @@ The framework pieces — touch before components.
21
22
  > Lab: [Map](../../lab/skills/map.md) · [Charts](../../lab/skills/charts.md) — install `@mhmo91/schmancy-lab`
22
23
 
23
24
  ### Surfaces & layout
24
- [Surface](./surface.md) · [Card](./card.md) · [Scroll / Grid / Flex](./layout.md) · [Page](./page.md) · [Content Drawer](./content-drawer.md) · [Window](./window.md) · [Boat](./boat.md) · [Float](./float.md) · [Splash Screen](./splash-screen.md)
25
+ [Surface](./surface.md) · [Card](./card.md) · [Scroll / Grid / Flex](./layout.md) · [Content Drawer](./content-drawer.md) · [Window](./window.md) · [Boat](./boat.md) · [Float](./float.md) · [Splash Screen](./splash-screen.md)
25
26
 
26
27
  ### Forms
27
28
  [Form](./form.md) · [Input](./input.md) · [Textarea](./textarea.md) · [Select](./select.md) · [Autocomplete](./autocomplete.md) · [Option](./option.md) · [Checkbox](./checkbox.md) · [Switch](./switch.md) · [Radio Group](./radio-group.md) · [Chips](./chips.md) · [Date Range](./date-range.md) · [Date Range Inline](./date-range-inline.md) · [Range](./range.md)
@@ -25,6 +25,7 @@ All reference files live in this directory. Read by filename.
25
25
  | Base class (`SchmancyElement`) | `mixins.md` |
26
26
  | Theme (`<schmancy-theme>`, `theme` service) | `theme.md` |
27
27
  | Directives (`magnetic`, `cursorGlow`, `gravity`, `reveal`, `animateText`, …) | `directives.md` |
28
+ | Layout (`fill()`, `overflowWithin()` — viewport-anchored shell sizing) | `layout.md` |
28
29
  | Spring physics presets | `animation.md` |
29
30
 
30
31
  ## Overlay services (prefer over tags)
@@ -78,6 +79,11 @@ State signals are the integration layer between co-located Schmancy view compone
78
79
  - Detection signals: a view component with `.property=${value}` inputs from a parent; a view component dispatching `CustomEvent`s that a sibling or parent handles; an orchestrator file co-located with a view where routing complexity does not exceed schmancy's `.guard`+`@redirect` capability (i.e., the flow is a linear sequence with no branching or cross-route hand-off).
79
80
  - Remediation: move shared state into schmancy state signals; have each component read/write signals directly in render() and connectedCallback(); delete the orchestrator if its only job was to pass data down and receive events up.
80
81
 
82
+ **TYPOGRAPHY_NO_REDUNDANT_COLOR** (`TYPOGRAPHY_NO_REDUNDANT_COLOR`). `schmancy-typography` color classes override the component's default rendering color.
83
+
84
+ - Detection signals: `class` attributes on `<schmancy-typography>` containing `text-on-surface`, `text-surface-on`, `text-surface-on-variant`, or any other color utility that matches the component's default — these restate what the component already renders and add no information.
85
+ - Remediation: remove the redundant color class from the `class` attribute. Keep a color class only when it intentionally overrides the default (e.g. `text-primary-default`, `text-error`, a custom accent). The test: if removing the class produces no visual change, it is redundant.
86
+
81
87
  **EVENTS_UP_PROPS_DOWN** (cross-component communication when signals don't cover it)
82
88
  When two components genuinely cannot share a signal (e.g., a generic reusable component that must not import app state), user actions travel upward via `CustomEvent` dispatch and data travels downward via Lit property bindings — not via callable property bindings (`onXxx`, `handleXxx`) set on child elements.
83
89
 
@@ -125,31 +131,35 @@ Plus a live region: `<div id="live-status" role="status" aria-live="polite" clas
125
131
  ## Minimal app skeleton
126
132
 
127
133
  ```typescript
128
- <schmancy-theme root scheme="dark">
129
- <schmancy-surface type="solid" fill="all">
130
- <schmancy-scroll>
131
- <schmancy-area
132
- name="root"
133
- .default=${lazy(() => import('./home.page'))}
134
- >
135
- <schmancy-route when="home-page"
136
- .component=${lazy(() => import('./home.page'))}></schmancy-route>
137
-
138
- <schmancy-route when="app-index"
139
- .component=${lazy(() => import('./app.page'))}
140
- .guard=${authState$.pipe(
141
- map(u => !!u),
142
- takeUntil(this.disconnecting),
143
- )}
144
- @redirect=${() => area.push({
145
- component: 'home-page', area: 'root', historyStrategy: 'replace',
146
- })}></schmancy-route>
147
- </schmancy-area>
148
- </schmancy-scroll>
149
- </schmancy-surface>
150
- </schmancy-theme>
134
+ // styles.css: html, body { margin: 0; padding: 0; overflow: hidden; }
135
+ import { fill } from '@mhmo91/schmancy/directives'
136
+
137
+ html`
138
+ <schmancy-theme root scheme="dark">
139
+ <schmancy-area
140
+ ${fill()}
141
+ name="root"
142
+ .default=${lazy(() => import('./home.page'))}
143
+ >
144
+ <schmancy-route when="home-page"
145
+ .component=${lazy(() => import('./home.page'))}></schmancy-route>
146
+
147
+ <schmancy-route when="app-index"
148
+ .component=${lazy(() => import('./app.page'))}
149
+ .guard=${authState$.pipe(
150
+ map(u => !!u),
151
+ takeUntil(this.disconnecting),
152
+ )}
153
+ @redirect=${() => area.push({
154
+ component: 'home-page', area: 'root', historyStrategy: 'replace',
155
+ })}></schmancy-route>
156
+ </schmancy-area>
157
+ </schmancy-theme>
158
+ `
151
159
  ```
152
160
 
161
+ See `layout.md` for the full shell pattern with rail + content area.
162
+
153
163
  ## Workflow
154
164
 
155
165
  1. User describes a UI task.
@@ -14,9 +14,10 @@ Areas can be nested to compose shell-plus-sub-view layouts.
14
14
 
15
15
  `<schmancy-area>` is the routing leaf in the layout cascade. Its shadow CSS guarantees:
16
16
 
17
- 1. **Stretch the mounted component.** The routed view fills the area (`min-height: 100%; width: 100%`). The area itself is `height: 100%; width: 100%` so it consumes whatever cell its parent gave it (typically a `<schmancy-page>` slot or a grid `1fr` row / column).
18
- 2. **Scroll by default.** The host is `overflow: auto` when the mounted component grows past the area's box, the area scrolls. Pages that need a custom scroll strategy (virtualized lists, multi-pane scroll) declare `<schmancy-area no-scroll>` and own their scroll.
19
- 3. **Reset scroll on route change.** The area sets `scrollTop = 0` after every route swap so a new view starts at the top.
17
+ 1. **Stretch the mounted component.** `::slotted(:not(schmancy-route))` gives every mounted view `min-height: 100%; width: 100%; min-width: 0` so it fills the area cell.
18
+ 2. **Area sizing.** The host is `height: 100%; width: 100%; min-height: 0; min-width: 0` it fills whatever grid cell or `fill()` box its parent gave it.
19
+ 3. **No built-in scroll.** Scroll is opt-in via `${overflowWithin()}` at the use site. Put `overflowWithin()` on the element that should scroll (the area itself, or a wrapper around it), not on the routed component.
20
+ 4. **Reset scroll on route change.** The area sets `scrollTop = 0` after every route swap so a new view starts at the top.
20
21
 
21
22
  Consumers do not write `h-full`, `w-full`, or `:host { height: 100% }` on routed components. The area's `::slotted` rule sizes them.
22
23
 
@@ -57,7 +58,7 @@ Consumers do not write `h-full`, `w-full`, or `:host { height: 100% }` on routed
57
58
  | `guard` | `Observable<boolean>` | When emits `false`, blocks and dispatches `redirect` event |
58
59
  | `exact` | boolean | Strict-equality matching |
59
60
 
60
- `<schmancy-area>` also accepts the `no-scroll` boolean attribute to opt out of default `overflow: auto` (for virtualized lists or custom scroll containers).
61
+ Scroll is opt-in: apply `${overflowWithin()}` to the element (or a wrapper) that should scroll. The area has no `no-scroll` attribute that concept is gone.
61
62
 
62
63
  ## `area` service
63
64
 
@@ -26,9 +26,7 @@ Place it once at the root — typically just inside your main `schmancy-theme` o
26
26
  ```html
27
27
  <schmancy-theme>
28
28
  <schmancy-connectivity-status></schmancy-connectivity-status>
29
- <schmancy-page>
30
- <!-- rest of app -->
31
- </schmancy-page>
29
+ <schmancy-area ${fill()} name="root" .default=${...}>...</schmancy-area>
32
30
  </schmancy-theme>
33
31
  ```
34
32
 
@@ -5,11 +5,47 @@
5
5
  Lit directives that snap onto any element to add behavior. No components to wrap, no CSS to write — just `${directiveName()}` in your template.
6
6
 
7
7
  ```typescript
8
+ import { fill, overflowWithin } from '@mhmo91/schmancy/directives'
8
9
  import { magnetic, cursorGlow, gravity, reveal } from '@mhmo91/schmancy/directives'
9
10
  ```
10
11
 
11
12
  ---
12
13
 
14
+ ## Layout (2 directives — use these for every app shell)
15
+
16
+ > These replace the deleted `<schmancy-page>` primitive. See `layout.md` for the full paradigm.
17
+
18
+ ### `fill()` — Viewport-anchor a container
19
+
20
+ Measures the element's position against `visualViewport` and applies an exact `height` (and `width`) in pixels — cascade-independent. Tracks `visualViewport` resize/scroll, orientation change, iOS soft-keyboard (via `focusout`), and `theme.bottomOffset$` for safe-area padding.
21
+
22
+ ```html
23
+ <!-- Root area — anchored to the full viewport -->
24
+ <schmancy-area ${fill()} name="root" .default=${...}>...</schmancy-area>
25
+
26
+ <!-- Custom element shell — fill() bypasses display:inline collapse -->
27
+ <my-shell class="grid grid-cols-[auto_1fr]" ${fill()}>...</my-shell>
28
+ ```
29
+
30
+ **Sets:** `height: Npx`, `width: Npx`, `overflow: hidden`, `min-height/width: 0`, `box-sizing: border-box`, `padding-bottom` (safe area).
31
+ **Does NOT set:** `display`, `grid-template-*` — put Tailwind layout classes on the same element.
32
+
33
+ ### `overflowWithin()` — Contained scroll region
34
+
35
+ Turns a grid cell or flex child into a scroll container with `overscroll-behavior: contain`.
36
+
37
+ ```html
38
+ <div ${overflowWithin()} class="grid grid-rows-[auto_1fr] min-h-0">
39
+ <header>...</header>
40
+ <schmancy-area name="app">...</schmancy-area>
41
+ </div>
42
+ ```
43
+
44
+ **Sets:** `overflow-y/x: auto`, `overscroll-behavior: contain`, `scroll-behavior: smooth`, `min-height/width: 0`, `box-sizing: border-box`.
45
+ Dispatches debounced `schmancy:scroll` event; listens for `@schmancy:scrollTo` command.
46
+
47
+ ---
48
+
13
49
  ## Physics & Interaction (6 directives)
14
50
 
15
51
  ### `magnetic` — Elements lean toward the cursor
@@ -1,44 +1,108 @@
1
1
  # schmancy-icon
2
2
 
3
- > Material Symbols icon with configurable fill, weight, grade, variant, and size tokens.
3
+ Renders a Material Symbol as an inline SVG. Path data is supplied at build
4
+ time by the `schmancy-icons` Vite plugin — no font file, no network request,
5
+ works offline from first byte.
4
6
 
5
7
  ## Usage
8
+
9
+ ```html
10
+ <schmancy-icon>home</schmancy-icon>
11
+ <schmancy-icon>delete</schmancy-icon>
12
+ ```
13
+
14
+ Slot text IS the icon name (Material Symbols ligature name). No properties needed.
15
+
16
+ ## Sizing
17
+
18
+ Size is set with Tailwind `text-*` on the host. Default is `24px` (`text-2xl`).
19
+ `width` and `height` track `font-size` via `1em`.
20
+
6
21
  ```html
7
- <schmancy-icon>settings</schmancy-icon>
22
+ <schmancy-icon class="text-base">close</schmancy-icon> <!-- 16px -->
23
+ <schmancy-icon class="text-xl">search</schmancy-icon> <!-- 20px -->
24
+ <schmancy-icon class="text-2xl">home</schmancy-icon> <!-- 24px (default) -->
25
+ <schmancy-icon class="text-4xl">check_circle</schmancy-icon> <!-- 36px -->
8
26
  ```
9
27
 
10
- ## Properties
11
- | Property | Type | Default | Description |
12
- |----------|------|---------|-------------|
13
- | icon | string | `undefined` | Icon name (alternative to slot content, translation-safe) |
14
- | size | `'xxs'\|'xs'\|'sm'\|'md'\|'lg'\|string` | `'md'` | Icon size (12/16/20/24/32px or custom) |
15
- | fill | number (0-1) | `0` | Fill level (0=outlined, 1=filled) |
16
- | weight | number (100-700) | `400` | Stroke thickness |
17
- | grade | number (-50 to 200) | `0` | Visual weight adjustment |
18
- | variant | `'outlined'\|'rounded'\|'sharp'` | `'outlined'` | Icon style variant |
19
-
20
- ## Size Tokens
21
- | Token | Size | Optical Size | Best For |
22
- |-------|------|-------------|----------|
23
- | xxs | 12px | 20 | Ultra-compact UIs |
24
- | xs | 16px | 20 | 32px buttons |
25
- | sm | 20px | 20 | 40px buttons |
26
- | md | 24px | 24 | Default (48px buttons) |
27
- | lg | 32px | 40 | 56px buttons |
28
-
29
- ## Examples
28
+ ## Color
29
+
30
+ Inherits `currentColor`. Override with Tailwind color utilities:
31
+
32
+ ```html
33
+ <schmancy-icon class="text-primary-default">star</schmancy-icon>
34
+ <schmancy-icon class="opacity-50">info</schmancy-icon>
35
+ ```
36
+
37
+ ## Fill variant (active states)
38
+
39
+ Append `-fill` to the icon name for the filled variant. No CSS animation —
40
+ a clean swap between outlined and filled symbols:
41
+
30
42
  ```html
31
- <!-- Filled icon -->
32
- <schmancy-icon .fill=${1}>favorite</schmancy-icon>
43
+ <!-- Static filled -->
44
+ <schmancy-icon>favorite-fill</schmancy-icon>
33
45
 
34
- <!-- Large rounded icon -->
35
- <schmancy-icon size="lg" variant="rounded">home</schmancy-icon>
46
+ <!-- Dynamic active state -->
47
+ <schmancy-icon>${active ? 'home-fill' : 'home'}</schmancy-icon>
48
+ ```
49
+
50
+ The plugin auto-includes `-fill` variants for every detected base icon.
51
+
52
+ ## Vite plugin setup (web workspace)
53
+
54
+ The plugin scans all `.ts` source files at build start and injects
55
+ `window.__siIcons = { name: 'svgPathData', ... }` inline in `<head>`.
56
+
57
+ ```typescript
58
+ // web/vite.config.ts
59
+ import { schmancyIcons } from './plugins/schmancy-icons.ts'
60
+
61
+ export default defineConfig({
62
+ plugins: [
63
+ schmancyIcons({
64
+ // Icon names used in runtime variables (not statically detectable).
65
+ // Type them as SchmancyIconName in consuming code.
66
+ additional: ['widgets', 'inventory_2', 'description'],
67
+ }),
68
+ ],
69
+ })
70
+ ```
36
71
 
37
- <!-- Custom size -->
38
- <schmancy-icon size="48px" .weight=${300}>search</schmancy-icon>
72
+ ### Adding icons for dynamic usage
39
73
 
40
- <!-- Translation-safe (use icon property instead of slot) -->
41
- <schmancy-icon icon="delete"></schmancy-icon>
74
+ Any icon name carried in a variable at runtime must be declared in `additional`.
75
+ TypeScript enforcement: the plugin generates `src/types/icon-name.d.ts` with
76
+ a `SchmancyIconName` union of every icon in the bundle. Type dynamic icon props
77
+ as `SchmancyIconName` to get compile-time coverage.
78
+
79
+ ```typescript
80
+ import type { SchmancyIconName } from './types/icon-name'
81
+
82
+ @property({ type: String }) icon: SchmancyIconName = 'home'
42
83
  ```
43
84
 
44
- Auto-loads Google Fonts on first use. Translation-protected via `translate="no"` and `notranslate` class.
85
+ ## What was removed
86
+
87
+ The following properties are **gone** — the component has no public API beyond
88
+ slot text content:
89
+
90
+ | Removed | Replacement |
91
+ |---------|-------------|
92
+ | `size="lg"` | `class="text-4xl"` (Tailwind) |
93
+ | `fill`, `weight`, `grade`, `variant` | n/a — use `-fill` suffix for filled, rest unsupported |
94
+ | `icon="name"` prop | slot text: `<schmancy-icon>name</schmancy-icon>` |
95
+ | Google Fonts auto-load | n/a — self-contained inline SVG |
96
+
97
+ ## How it works
98
+
99
+ 1. Vite plugin walks `web/src/**/*.ts`, extracts icon names from
100
+ `<schmancy-icon>name</schmancy-icon>` and `icon="name"` patterns.
101
+ 2. Reads `@material-symbols/svg-400/outlined/{name}.svg`, extracts the `d`
102
+ attribute from each `<path>`.
103
+ 3. Injects `<script>window.__siIcons={...}</script>` before `</head>`.
104
+ 4. `schmancy-icon.connectedCallback` reads `this.textContent`, looks up
105
+ `window.__siIcons[name]`, and renders `<svg><path d="..."/></svg>` inside
106
+ its shadow DOM.
107
+
108
+ No `<use>` references — those can't cross shadow DOM boundaries.