@mhmo91/schmancy 0.10.26 → 0.10.28

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 (394) hide show
  1. package/custom-elements.json +14 -18
  2. package/dist/agent/overlay.confirm-body-BZoUgkdK.js +4574 -0
  3. package/dist/agent/overlay.confirm-body-BZoUgkdK.js.map +1 -0
  4. package/dist/agent/schmancy.agent.js +3121 -4893
  5. package/dist/agent/schmancy.agent.js.map +1 -1
  6. package/dist/agent/schmancy.manifest.json +68 -24
  7. package/dist/{area-DkvO_oiO.cjs → area-BSVOYQDA.cjs} +1 -1
  8. package/dist/{area-DkvO_oiO.cjs.map → area-BSVOYQDA.cjs.map} +1 -1
  9. package/dist/{area-fC1_kvAW.js → area-C_Yvjmad.js} +1 -1
  10. package/dist/{area-fC1_kvAW.js.map → area-C_Yvjmad.js.map} +1 -1
  11. package/dist/area.cjs +1 -1
  12. package/dist/area.js +1 -1
  13. package/dist/{autocomplete-Aa2IstyX.cjs → autocomplete-B50VXUzw.cjs} +1 -1
  14. package/dist/{autocomplete-Aa2IstyX.cjs.map → autocomplete-B50VXUzw.cjs.map} +1 -1
  15. package/dist/{autocomplete-Hb-C11a3.js → autocomplete-C6I1mfOT.js} +2 -2
  16. package/dist/{autocomplete-Hb-C11a3.js.map → autocomplete-C6I1mfOT.js.map} +1 -1
  17. package/dist/autocomplete.cjs +1 -1
  18. package/dist/autocomplete.js +1 -1
  19. package/dist/avatar.cjs +2 -2
  20. package/dist/avatar.js +3 -3
  21. package/dist/badge.cjs +1 -1
  22. package/dist/badge.js +1 -1
  23. package/dist/{boat-BW6aRcdY.js → boat-C94QZ4Zt.js} +1 -1
  24. package/dist/{boat-BW6aRcdY.js.map → boat-C94QZ4Zt.js.map} +1 -1
  25. package/dist/{boat-BEq-AHmL.cjs → boat-DVQBNkk5.cjs} +1 -1
  26. package/dist/{boat-BEq-AHmL.cjs.map → boat-DVQBNkk5.cjs.map} +1 -1
  27. package/dist/boat.cjs +1 -1
  28. package/dist/boat.js +1 -1
  29. package/dist/breadcrumb.cjs +1 -1
  30. package/dist/breadcrumb.js +1 -1
  31. package/dist/{busy-D-ucQFSB.js → busy--bNb42rM.js} +1 -1
  32. package/dist/{busy-D-ucQFSB.js.map → busy--bNb42rM.js.map} +1 -1
  33. package/dist/{busy-CKpIblIO.cjs → busy-DuxFvEkY.cjs} +1 -1
  34. package/dist/{busy-CKpIblIO.cjs.map → busy-DuxFvEkY.cjs.map} +1 -1
  35. package/dist/busy.cjs +1 -1
  36. package/dist/busy.js +1 -1
  37. package/dist/{button-BU-X0a0S.js → button-B7b9L_h5.js} +26 -187
  38. package/dist/button-B7b9L_h5.js.map +1 -0
  39. package/dist/{button-HzLpB3NP.cjs → button-DAFZ5A4O.cjs} +2 -60
  40. package/dist/button-DAFZ5A4O.cjs.map +1 -0
  41. package/dist/button.cjs +59 -1
  42. package/dist/button.cjs.map +1 -0
  43. package/dist/button.js +170 -2
  44. package/dist/button.js.map +1 -0
  45. package/dist/{card-CcrUlgd3.cjs → card-DZPd24Sn.cjs} +1 -1
  46. package/dist/{card-CcrUlgd3.cjs.map → card-DZPd24Sn.cjs.map} +1 -1
  47. package/dist/{card-ueXBeJ6q.js → card-ixzxOW-Q.js} +1 -1
  48. package/dist/{card-ueXBeJ6q.js.map → card-ixzxOW-Q.js.map} +1 -1
  49. package/dist/card.cjs +1 -1
  50. package/dist/card.js +1 -1
  51. package/dist/{checkbox-qsp-I5C6.cjs → checkbox-Bi_Fm2mf.cjs} +1 -1
  52. package/dist/{checkbox-qsp-I5C6.cjs.map → checkbox-Bi_Fm2mf.cjs.map} +1 -1
  53. package/dist/{checkbox-CW1kk4Tu.js → checkbox-DdGpepTh.js} +1 -1
  54. package/dist/{checkbox-CW1kk4Tu.js.map → checkbox-DdGpepTh.js.map} +1 -1
  55. package/dist/checkbox.cjs +1 -1
  56. package/dist/checkbox.js +1 -1
  57. package/dist/{chips-C_F6-gfe.js → chips-DLTynyVB.js} +3 -3
  58. package/dist/{chips-C_F6-gfe.js.map → chips-DLTynyVB.js.map} +1 -1
  59. package/dist/{chips-Dluk6RV4.cjs → chips-DWQMZErr.cjs} +1 -1
  60. package/dist/{chips-Dluk6RV4.cjs.map → chips-DWQMZErr.cjs.map} +1 -1
  61. package/dist/chips.cjs +1 -1
  62. package/dist/chips.js +2 -2
  63. package/dist/connectivity.cjs +1 -1
  64. package/dist/connectivity.js +1 -1
  65. package/dist/content-drawer.cjs +1 -1
  66. package/dist/content-drawer.js +1 -1
  67. package/dist/{date-range-ASZ8h_Il.js → date-range-CJ6MiTpF.js} +90 -82
  68. package/dist/date-range-CJ6MiTpF.js.map +1 -0
  69. package/dist/{date-range-BFOqXAI2.cjs → date-range-DQpmMJH-.cjs} +6 -1
  70. package/dist/date-range-DQpmMJH-.cjs.map +1 -0
  71. package/dist/{date-range-inline-DHrgolLn.js → date-range-inline-Ho3CENTh.js} +1 -1
  72. package/dist/{date-range-inline-DHrgolLn.js.map → date-range-inline-Ho3CENTh.js.map} +1 -1
  73. package/dist/{date-range-inline-BNmNOpL0.cjs → date-range-inline-nPWIs-3C.cjs} +1 -1
  74. package/dist/{date-range-inline-BNmNOpL0.cjs.map → date-range-inline-nPWIs-3C.cjs.map} +1 -1
  75. package/dist/date-range-inline.cjs +1 -1
  76. package/dist/date-range-inline.js +1 -1
  77. package/dist/date-range.cjs +1 -1
  78. package/dist/date-range.js +1 -1
  79. package/dist/delay.cjs +1 -1
  80. package/dist/delay.js +2 -2
  81. package/dist/{details-Bx9c4XQR.cjs → details-BnRWMZdt.cjs} +1 -1
  82. package/dist/{details-Bx9c4XQR.cjs.map → details-BnRWMZdt.cjs.map} +1 -1
  83. package/dist/{details-B9RgRw6c.js → details-CcMTvYo7.js} +2 -2
  84. package/dist/{details-B9RgRw6c.js.map → details-CcMTvYo7.js.map} +1 -1
  85. package/dist/details.cjs +1 -1
  86. package/dist/details.js +1 -1
  87. package/dist/{directives-Dq0zi2KR.cjs → directives-BkSqmLBV.cjs} +11 -11
  88. package/dist/directives-BkSqmLBV.cjs.map +1 -0
  89. package/dist/{directives-sWKTEJDb.js → directives-DgPbz0lQ.js} +116 -153
  90. package/dist/directives-DgPbz0lQ.js.map +1 -0
  91. package/dist/directives.cjs +1 -1
  92. package/dist/directives.js +7 -6
  93. package/dist/discovery.cjs +1 -1
  94. package/dist/discovery.js +1 -1
  95. package/dist/{discovery.service-CVDXO9rH.cjs.map → discovery.service-CIa3Eeuk.cjs.map} +1 -1
  96. package/dist/{discovery.service-COmbHaoI.js.map → discovery.service-DZFxtRwW.js.map} +1 -1
  97. package/dist/{divider-DH0BvTOv.cjs → divider-C6yJSL1c.cjs} +1 -1
  98. package/dist/{divider-DH0BvTOv.cjs.map → divider-C6yJSL1c.cjs.map} +1 -1
  99. package/dist/{divider-C7BtzDcK.js → divider-CZCj0ioH.js} +1 -1
  100. package/dist/{divider-C7BtzDcK.js.map → divider-CZCj0ioH.js.map} +1 -1
  101. package/dist/divider.cjs +1 -1
  102. package/dist/divider.js +1 -1
  103. package/dist/dropdown.cjs +1 -1
  104. package/dist/dropdown.js +1 -1
  105. package/dist/{expand-DcMx9dHY.js → expand-Cc6ogXsR.js} +2 -2
  106. package/dist/{expand-DcMx9dHY.js.map → expand-Cc6ogXsR.js.map} +1 -1
  107. package/dist/{expand-CPMF44eL.cjs → expand-D4EhwOYh.cjs} +1 -1
  108. package/dist/{expand-CPMF44eL.cjs.map → expand-D4EhwOYh.cjs.map} +1 -1
  109. package/dist/expand.cjs +1 -1
  110. package/dist/expand.js +1 -1
  111. package/dist/{float-CgBN4H3g.cjs → float-B8EPc_OG.cjs} +1 -1
  112. package/dist/{float-CgBN4H3g.cjs.map → float-B8EPc_OG.cjs.map} +1 -1
  113. package/dist/{float-DkUw5TN4.js → float-BvI3HTtB.js} +1 -1
  114. package/dist/{float-DkUw5TN4.js.map → float-BvI3HTtB.js.map} +1 -1
  115. package/dist/float.cjs +1 -1
  116. package/dist/float.js +1 -1
  117. package/dist/{form-kSgJf_h4.js → form-FtYtZScl.js} +8 -8
  118. package/dist/{form-kSgJf_h4.js.map → form-FtYtZScl.js.map} +1 -1
  119. package/dist/form-SHg5FLsd.cjs +42 -0
  120. package/dist/{form-DxApnyVx.cjs.map → form-SHg5FLsd.cjs.map} +1 -1
  121. package/dist/form.cjs +1 -1
  122. package/dist/form.js +6 -6
  123. package/dist/gravity-6pL6CfIr.cjs +1 -0
  124. package/dist/gravity-6pL6CfIr.cjs.map +1 -0
  125. package/dist/gravity-sVK3zGBF.js +46 -0
  126. package/dist/gravity-sVK3zGBF.js.map +1 -0
  127. package/dist/handover/agent-runtime-followups.md +1 -1
  128. package/dist/handover/agent-runtime-v1.md +3 -3
  129. package/dist/{hashContent-Dgmzc32o.js.map → hashContent-BqU6v1Xr.js.map} +1 -1
  130. package/dist/{hashContent-Dh1VzIAb.cjs.map → hashContent-iRZJJWtE.cjs.map} +1 -1
  131. package/dist/{icons-DsfpmrVO.js → icon-B1eZr2ZL.js} +1 -1
  132. package/dist/icon-B1eZr2ZL.js.map +1 -0
  133. package/dist/{icons-3F1nQAn_.cjs → icon-CgIXAvKI.cjs} +1 -1
  134. package/dist/{icons-DsfpmrVO.js.map → icon-CgIXAvKI.cjs.map} +1 -1
  135. package/dist/icons.cjs +1 -1
  136. package/dist/icons.js +1 -1
  137. package/dist/{iframe-sTXBw6zB.cjs → iframe-BO3BpRLH.cjs} +1 -1
  138. package/dist/{iframe-sTXBw6zB.cjs.map → iframe-BO3BpRLH.cjs.map} +1 -1
  139. package/dist/{iframe-KrV4Cak-.js → iframe-CmpAZc61.js} +1 -1
  140. package/dist/{iframe-KrV4Cak-.js.map → iframe-CmpAZc61.js.map} +1 -1
  141. package/dist/iframe.cjs +1 -1
  142. package/dist/iframe.js +1 -1
  143. package/dist/index.cjs +1 -1
  144. package/dist/index.js +49 -47
  145. package/dist/{input-DMoggdSN.cjs → input-5YL2oUBr.cjs} +1 -1
  146. package/dist/{input-DMoggdSN.cjs.map → input-5YL2oUBr.cjs.map} +1 -1
  147. package/dist/{input-zj3eaZM_.js → input-_Hft9vov.js} +1 -1
  148. package/dist/{input-zj3eaZM_.js.map → input-_Hft9vov.js.map} +1 -1
  149. package/dist/{input-chip-DHbfUatc.js → input-chip-BNTojQT6.js} +1 -1
  150. package/dist/{input-chip-DHbfUatc.js.map → input-chip-BNTojQT6.js.map} +1 -1
  151. package/dist/{input-chip-B1iNQW2m.cjs → input-chip-DKMNpcED.cjs} +1 -1
  152. package/dist/{input-chip-B1iNQW2m.cjs.map → input-chip-DKMNpcED.cjs.map} +1 -1
  153. package/dist/input.cjs +1 -1
  154. package/dist/input.js +1 -1
  155. package/dist/json.cjs +1 -1
  156. package/dist/json.js +2 -2
  157. package/dist/kbd.cjs +1 -1
  158. package/dist/kbd.js +1 -1
  159. package/dist/layout.cjs +1 -1
  160. package/dist/layout.js +1 -1
  161. package/dist/{lightbox-CAcXlJlv.js → lightbox-CKlYcnHV.js} +1 -1
  162. package/dist/{lightbox-CAcXlJlv.js.map → lightbox-CKlYcnHV.js.map} +1 -1
  163. package/dist/{lightbox-86F2RgXy.cjs → lightbox-t4dvb8_A.cjs} +1 -1
  164. package/dist/{lightbox-86F2RgXy.cjs.map → lightbox-t4dvb8_A.cjs.map} +1 -1
  165. package/dist/lightbox.cjs +1 -1
  166. package/dist/lightbox.js +1 -1
  167. package/dist/{list-CUbI0RM6.cjs → list-21mWtDKg.cjs} +4 -4
  168. package/dist/list-21mWtDKg.cjs.map +1 -0
  169. package/dist/{list-BIjJ6T1c.js → list-B6QhxgRJ.js} +4 -7
  170. package/dist/list-B6QhxgRJ.js.map +1 -0
  171. package/dist/list.cjs +1 -1
  172. package/dist/list.js +1 -1
  173. package/dist/{magnetic-mHXl54Z8.js.map → magnetic-B2VKNfDu.js.map} +1 -1
  174. package/dist/{magnetic-D-ph029G.cjs.map → magnetic-MQ3HMHJi.cjs.map} +1 -1
  175. package/dist/{menu-CtFcvxgU.js → menu-C5qcgMnw.js} +3 -3
  176. package/dist/{menu-CtFcvxgU.js.map → menu-C5qcgMnw.js.map} +1 -1
  177. package/dist/{menu-DGMrjR_a.cjs → menu-Cuxt5K4Y.cjs} +2 -2
  178. package/dist/{menu-DGMrjR_a.cjs.map → menu-Cuxt5K4Y.cjs.map} +1 -1
  179. package/dist/menu.cjs +1 -1
  180. package/dist/menu.js +1 -1
  181. package/dist/mixins-8dT5j6CS.js +627 -0
  182. package/dist/mixins-8dT5j6CS.js.map +1 -0
  183. package/dist/mixins-BF3Vj8_c.cjs +242 -0
  184. package/dist/mixins-BF3Vj8_c.cjs.map +1 -0
  185. package/dist/mixins.cjs +1 -1
  186. package/dist/mixins.js +1 -1
  187. package/dist/nav-drawer.cjs +1 -1
  188. package/dist/nav-drawer.js +1 -1
  189. package/dist/navigation-bar.cjs +1 -1
  190. package/dist/navigation-bar.js +1 -1
  191. package/dist/navigation-rail.cjs +7 -5
  192. package/dist/navigation-rail.cjs.map +1 -1
  193. package/dist/navigation-rail.js +52 -38
  194. package/dist/navigation-rail.js.map +1 -1
  195. package/dist/notification-CDKBKh63.js +243 -0
  196. package/dist/notification-CDKBKh63.js.map +1 -0
  197. package/dist/notification-CcNoBFEJ.cjs +24 -0
  198. package/dist/notification-CcNoBFEJ.cjs.map +1 -0
  199. package/dist/notification.cjs +1 -1
  200. package/dist/notification.js +1 -1
  201. package/dist/{option-C3UyYQi_.js → option-BWfmDJvm.js} +1 -1
  202. package/dist/{option-C3UyYQi_.js.map → option-BWfmDJvm.js.map} +1 -1
  203. package/dist/{option-DJ3R-2Wn.cjs → option-DejeqOad.cjs} +1 -1
  204. package/dist/{option-DJ3R-2Wn.cjs.map → option-DejeqOad.cjs.map} +1 -1
  205. package/dist/option.cjs +1 -1
  206. package/dist/option.js +1 -1
  207. package/dist/{overlay-D1hFkcFA.js → overlay-D3c_NY18.js} +214 -265
  208. package/dist/overlay-D3c_NY18.js.map +1 -0
  209. package/dist/overlay-Dv2utO4C.cjs +43 -0
  210. package/dist/overlay-Dv2utO4C.cjs.map +1 -0
  211. package/dist/overlay.cjs +1 -1
  212. package/dist/overlay.confirm-body-B2ntyquG.cjs +79 -0
  213. package/dist/overlay.confirm-body-B2ntyquG.cjs.map +1 -0
  214. package/dist/overlay.confirm-body-B_v0ivkn.js +159 -0
  215. package/dist/overlay.confirm-body-B_v0ivkn.js.map +1 -0
  216. package/dist/overlay.js +3 -3
  217. package/dist/overlay.service-B3FjXCqc.js +143 -0
  218. package/dist/overlay.service-B3FjXCqc.js.map +1 -0
  219. package/dist/overlay.service-BkSeqXIv.cjs +1 -0
  220. package/dist/overlay.service-BkSeqXIv.cjs.map +1 -0
  221. package/dist/{progress-CY-UbvOB.cjs → progress-6_rb3Ah9.cjs} +1 -1
  222. package/dist/{progress-CY-UbvOB.cjs.map → progress-6_rb3Ah9.cjs.map} +1 -1
  223. package/dist/{progress-YjdEWDI5.js → progress-CFcmO0wv.js} +1 -1
  224. package/dist/{progress-YjdEWDI5.js.map → progress-CFcmO0wv.js.map} +1 -1
  225. package/dist/progress.cjs +1 -1
  226. package/dist/progress.js +1 -1
  227. package/dist/{radio-group-aKXKHqUp.js → radio-group-Bd8y9QpX.js} +1 -1
  228. package/dist/{radio-group-aKXKHqUp.js.map → radio-group-Bd8y9QpX.js.map} +1 -1
  229. package/dist/{radio-group--UamzqAm.cjs → radio-group-_WZg8EKM.cjs} +1 -1
  230. package/dist/{radio-group--UamzqAm.cjs.map → radio-group-_WZg8EKM.cjs.map} +1 -1
  231. package/dist/radio-group.cjs +1 -1
  232. package/dist/radio-group.js +1 -1
  233. package/dist/range.cjs +1 -1
  234. package/dist/range.js +1 -1
  235. package/dist/{rxjs-utils-CaC-tdot.cjs.map → rxjs-utils-Csnks202.cjs.map} +1 -1
  236. package/dist/{rxjs-utils-BXpvHN4-.js.map → rxjs-utils-d-ivVN84.js.map} +1 -1
  237. package/dist/rxjs-utils.cjs +1 -1
  238. package/dist/rxjs-utils.js +1 -1
  239. package/dist/{select-CIquL8LY.cjs → select-BaioT3yY.cjs} +2 -2
  240. package/dist/{select-CIquL8LY.cjs.map → select-BaioT3yY.cjs.map} +1 -1
  241. package/dist/{select-B0Qk4PfT.js → select-Czpl1ztD.js} +3 -3
  242. package/dist/{select-B0Qk4PfT.js.map → select-Czpl1ztD.js.map} +1 -1
  243. package/dist/select.cjs +1 -1
  244. package/dist/select.js +1 -1
  245. package/dist/skeleton.cjs +1 -1
  246. package/dist/skeleton.js +1 -1
  247. package/dist/skills/SKILL.md +1 -1
  248. package/dist/skills/list.md +0 -1
  249. package/dist/skills/schmancy/SKILL.md +1 -1
  250. package/dist/skills/schmancy/list.md +0 -1
  251. package/dist/slider.cjs +1 -1
  252. package/dist/slider.js +1 -1
  253. package/dist/{splash-screen-rg56AXCf.cjs → splash-screen-3FtgdVy3.cjs} +1 -1
  254. package/dist/{splash-screen-rg56AXCf.cjs.map → splash-screen-3FtgdVy3.cjs.map} +1 -1
  255. package/dist/{splash-screen-CP_Idse2.js → splash-screen-YtTVkJg8.js} +1 -1
  256. package/dist/{splash-screen-CP_Idse2.js.map → splash-screen-YtTVkJg8.js.map} +1 -1
  257. package/dist/splash-screen.cjs +1 -1
  258. package/dist/splash-screen.js +1 -1
  259. package/dist/{src-BAaNnqwc.cjs → src-AYRNg63f.cjs} +8 -8
  260. package/dist/{src-BAaNnqwc.cjs.map → src-AYRNg63f.cjs.map} +1 -1
  261. package/dist/{src-Do0IGupa.js → src-DKMEgT2z.js} +37 -37
  262. package/dist/{src-Do0IGupa.js.map → src-DKMEgT2z.js.map} +1 -1
  263. package/dist/steps.cjs +1 -1
  264. package/dist/steps.js +1 -1
  265. package/dist/{surface-B7a2O5-9.cjs → surface-BNvxLEDN.cjs} +1 -1
  266. package/dist/surface-BNvxLEDN.cjs.map +1 -0
  267. package/dist/{surface-DGewe6IV.js → surface-CVxyQPln.js} +1 -1
  268. package/dist/surface-CVxyQPln.js.map +1 -0
  269. package/dist/surface.cjs +1 -1
  270. package/dist/surface.js +1 -1
  271. package/dist/switch.cjs +1 -1
  272. package/dist/switch.js +1 -1
  273. package/dist/table.cjs +1 -1
  274. package/dist/table.js +1 -1
  275. package/dist/{tabs-g2aM43TH.js → tabs-CnPXvZuZ.js} +1 -1
  276. package/dist/{tabs-g2aM43TH.js.map → tabs-CnPXvZuZ.js.map} +1 -1
  277. package/dist/{tabs-n4dO5fo1.cjs → tabs-DTU7748z.cjs} +1 -1
  278. package/dist/{tabs-n4dO5fo1.cjs.map → tabs-DTU7748z.cjs.map} +1 -1
  279. package/dist/tabs.cjs +1 -1
  280. package/dist/tabs.js +1 -1
  281. package/dist/teleport.cjs +1 -1
  282. package/dist/teleport.js +1 -1
  283. package/dist/{textarea-DDx_7AfQ.cjs → textarea-Bqth6Q8P.cjs} +1 -1
  284. package/dist/{textarea-DDx_7AfQ.cjs.map → textarea-Bqth6Q8P.cjs.map} +1 -1
  285. package/dist/{textarea-D5hw4jsP.js → textarea-mQPsppmd.js} +1 -1
  286. package/dist/{textarea-D5hw4jsP.js.map → textarea-mQPsppmd.js.map} +1 -1
  287. package/dist/textarea.cjs +1 -1
  288. package/dist/textarea.js +1 -1
  289. package/dist/{theme-BMYkheaA.js → theme-BJqpv4cG.js} +2 -2
  290. package/dist/{theme-BMYkheaA.js.map → theme-BJqpv4cG.js.map} +1 -1
  291. package/dist/{theme-BdZAj0CO.cjs → theme-D4HGKt7N.cjs} +1 -1
  292. package/dist/{theme-BdZAj0CO.cjs.map → theme-D4HGKt7N.cjs.map} +1 -1
  293. package/dist/{theme-button-DdI6kxY3.js → theme-button-Jap7G_IH.js} +1 -1
  294. package/dist/{theme-button-DdI6kxY3.js.map → theme-button-Jap7G_IH.js.map} +1 -1
  295. package/dist/{theme-button-R2f_kLEl.cjs → theme-button-LP-Dgr17.cjs} +1 -1
  296. package/dist/{theme-button-R2f_kLEl.cjs.map → theme-button-LP-Dgr17.cjs.map} +1 -1
  297. package/dist/theme-button.cjs +1 -1
  298. package/dist/theme-button.js +1 -1
  299. package/dist/theme.cjs +1 -1
  300. package/dist/{theme.interface-B5xjEk74.cjs.map → theme.interface-CSt7JUBD.cjs.map} +1 -1
  301. package/dist/{theme.interface-DVEw3s8m.js.map → theme.interface-odQEpZZH.js.map} +1 -1
  302. package/dist/theme.js +3 -3
  303. package/dist/tree.cjs +1 -1
  304. package/dist/tree.js +1 -1
  305. package/dist/typography-BJMm6b0b.js +358 -0
  306. package/dist/typography-BJMm6b0b.js.map +1 -0
  307. package/dist/typography-Bc4MmSal.cjs +282 -0
  308. package/dist/typography-Bc4MmSal.cjs.map +1 -0
  309. package/dist/typography.cjs +1 -282
  310. package/dist/typography.js +2 -358
  311. package/dist/{utils-CVWUrECT.cjs.map → utils-DTa3QHxk.cjs.map} +1 -1
  312. package/dist/{utils-578eFTx4.js.map → utils-H8wNknWC.js.map} +1 -1
  313. package/dist/utils.cjs +1 -1
  314. package/dist/utils.js +1 -1
  315. package/dist/visually-hidden.cjs +1 -1
  316. package/dist/visually-hidden.js +1 -1
  317. package/dist/{window-LOGPpN8K.cjs → window-CNu_WnsY.cjs} +1 -1
  318. package/dist/{window-LOGPpN8K.cjs.map → window-CNu_WnsY.cjs.map} +1 -1
  319. package/dist/{window-MQxhTodp.js → window-DZTjkE24.js} +1 -1
  320. package/dist/{window-MQxhTodp.js.map → window-DZTjkE24.js.map} +1 -1
  321. package/dist/window.cjs +1 -1
  322. package/dist/window.js +1 -1
  323. package/package.json +1 -1
  324. package/skills/schmancy/SKILL.md +1 -1
  325. package/skills/schmancy/list.md +0 -1
  326. package/src/form/fields/date-range/date-range-dialog.ts +8 -1
  327. package/src/list/list.ts +1 -12
  328. package/src/menu/menu.ts +4 -1
  329. package/src/navigation-rail/navigation-rail.ts +558 -490
  330. package/src/notification/notification-service.ts +81 -263
  331. package/src/notification/notification.scss +93 -50
  332. package/src/notification/notification.ts +32 -69
  333. package/src/overlay/overlay.component.ts +99 -158
  334. package/src/overlay/overlay.confirm-body.ts +106 -61
  335. package/src/overlay/overlay.service.ts +81 -108
  336. package/src/surface/surface.styles.ts +0 -17
  337. package/src/surface/surface.ts +5 -7
  338. package/types/mixins/surface.mixin.d.ts +0 -3
  339. package/types/src/form/fields/date-range/date-range-dialog.d.ts +1 -0
  340. package/types/src/list/list.d.ts +0 -9
  341. package/types/src/navigation-rail/navigation-rail.d.ts +21 -1
  342. package/types/src/notification/notification-service.d.ts +3 -86
  343. package/types/src/notification/notification.d.ts +1 -1
  344. package/types/src/overlay/overlay.component.d.ts +1 -2
  345. package/types/src/overlay/overlay.confirm-body.d.ts +8 -4
  346. package/types/src/surface/surface.d.ts +5 -6
  347. package/types/src/surface/surface.styles.d.ts +0 -4
  348. package/dist/agent/overlay.confirm-body-DJrL6tio.js +0 -2859
  349. package/dist/agent/overlay.confirm-body-DJrL6tio.js.map +0 -1
  350. package/dist/button-BU-X0a0S.js.map +0 -1
  351. package/dist/button-HzLpB3NP.cjs.map +0 -1
  352. package/dist/date-range-ASZ8h_Il.js.map +0 -1
  353. package/dist/date-range-BFOqXAI2.cjs.map +0 -1
  354. package/dist/directives-Dq0zi2KR.cjs.map +0 -1
  355. package/dist/directives-sWKTEJDb.js.map +0 -1
  356. package/dist/form-DxApnyVx.cjs +0 -42
  357. package/dist/icons-3F1nQAn_.cjs.map +0 -1
  358. package/dist/list-BIjJ6T1c.js.map +0 -1
  359. package/dist/list-CUbI0RM6.cjs.map +0 -1
  360. package/dist/mixins-CKbQ6BJo.js +0 -642
  361. package/dist/mixins-CKbQ6BJo.js.map +0 -1
  362. package/dist/mixins-DSy-enUd.cjs +0 -254
  363. package/dist/mixins-DSy-enUd.cjs.map +0 -1
  364. package/dist/notification-BqyMYtP7.js +0 -306
  365. package/dist/notification-BqyMYtP7.js.map +0 -1
  366. package/dist/notification-D5eOdsMT.cjs +0 -23
  367. package/dist/notification-D5eOdsMT.cjs.map +0 -1
  368. package/dist/overlay-D1hFkcFA.js.map +0 -1
  369. package/dist/overlay-D7nQaT5U.cjs +0 -81
  370. package/dist/overlay-D7nQaT5U.cjs.map +0 -1
  371. package/dist/overlay.confirm-body-B4eCDLmU.js +0 -100
  372. package/dist/overlay.confirm-body-B4eCDLmU.js.map +0 -1
  373. package/dist/overlay.confirm-body-P18SmJL2.cjs +0 -45
  374. package/dist/overlay.confirm-body-P18SmJL2.cjs.map +0 -1
  375. package/dist/overlay.service-02ZLZ8Ib.js +0 -146
  376. package/dist/overlay.service-02ZLZ8Ib.js.map +0 -1
  377. package/dist/overlay.service-m-8omCA-.cjs +0 -1
  378. package/dist/overlay.service-m-8omCA-.cjs.map +0 -1
  379. package/dist/surface-B7a2O5-9.cjs.map +0 -1
  380. package/dist/surface-DGewe6IV.js.map +0 -1
  381. package/dist/typography.cjs.map +0 -1
  382. package/dist/typography.js.map +0 -1
  383. /package/dist/{discovery.service-CVDXO9rH.cjs → discovery.service-CIa3Eeuk.cjs} +0 -0
  384. /package/dist/{discovery.service-COmbHaoI.js → discovery.service-DZFxtRwW.js} +0 -0
  385. /package/dist/{hashContent-Dgmzc32o.js → hashContent-BqU6v1Xr.js} +0 -0
  386. /package/dist/{hashContent-Dh1VzIAb.cjs → hashContent-iRZJJWtE.cjs} +0 -0
  387. /package/dist/{magnetic-mHXl54Z8.js → magnetic-B2VKNfDu.js} +0 -0
  388. /package/dist/{magnetic-D-ph029G.cjs → magnetic-MQ3HMHJi.cjs} +0 -0
  389. /package/dist/{rxjs-utils-CaC-tdot.cjs → rxjs-utils-Csnks202.cjs} +0 -0
  390. /package/dist/{rxjs-utils-BXpvHN4-.js → rxjs-utils-d-ivVN84.js} +0 -0
  391. /package/dist/{theme.interface-B5xjEk74.cjs → theme.interface-CSt7JUBD.cjs} +0 -0
  392. /package/dist/{theme.interface-DVEw3s8m.js → theme.interface-odQEpZZH.js} +0 -0
  393. /package/dist/{utils-CVWUrECT.cjs → utils-DTa3QHxk.cjs} +0 -0
  394. /package/dist/{utils-578eFTx4.js → utils-H8wNknWC.js} +0 -0
@@ -1,490 +1,558 @@
1
- import { SchmancyElement } from '@mixins/index'
2
- import { html, PropertyValues } from 'lit'
3
- import { customElement, property, queryAssignedElements, state } from 'lit/decorators.js'
4
- import { BehaviorSubject, fromEvent, takeUntil } from 'rxjs'
5
- import { distinctUntilChanged, tap } from 'rxjs/operators'
6
- import { SchmancyNavigationRailItem } from './navigation-rail-item'
7
-
8
- export type NavigateEvent = CustomEvent<string>
9
-
10
- export type NavigationRailMenuClickEvent = CustomEvent<void>
11
-
12
- export type NavigationRailFabClickEvent = CustomEvent<void>
13
-
14
-
15
- export type LabelVisibility = 'all' | 'selected' | 'none'
16
-
17
- /**
18
- * Material Design 3 Navigation Rail Component
19
- * @see https://m3.material.io/components/navigation-rail/overview
20
- *
21
- * `<schmancy-navigation-rail>` component
22
- *
23
- * A Material Design 3 vertical navigation component positioned on the left side of an application.
24
- * Navigation rails provide access to between 3-7 primary destinations with a compact footprint.
25
- * Automatically hides in fullscreen mode when triggered via schmancyTheme.next({ fullscreen: true }).
26
- *
27
- * @element schmancy-navigation-rail
28
- * @slot fab - Slot for a floating action button at the top
29
- * @slot menu - Slot for a menu icon or button below the FAB
30
- * @slot header - Custom header content slot
31
- * @slot footer - Custom footer content slot
32
- * @slot - Default slot for navigation rail items
33
- *
34
- * @fires navigate - When a navigation item is selected
35
- * @fires menu-click - When the menu button is clicked
36
- * @fires fab-click - When the FAB is clicked
37
- *
38
- * @csspart rail - The main rail container
39
- * @csspart header - The header section
40
- * @csspart nav - The navigation items container
41
- * @csspart footer - The footer section
42
- *
43
- * @example
44
- * <schmancy-navigation-rail activeIndex="0">
45
- * <schmancy-button slot="fab" variant="filled" aria-label="Compose">
46
- * <schmancy-icon>add</schmancy-icon>
47
- * </schmancy-button>
48
- * <schmancy-button slot="menu" variant="text" aria-label="Menu">
49
- * <schmancy-icon>menu</schmancy-icon>
50
- * </schmancy-button>
51
- * <schmancy-navigation-rail-item icon="home" label="Home"></schmancy-navigation-rail-item>
52
- * <schmancy-navigation-rail-item icon="search" label="Search"></schmancy-navigation-rail-item>
53
- * <schmancy-navigation-rail-item icon="favorite" label="Favorites" badge="3"></schmancy-navigation-rail-item>
54
- * <schmancy-navigation-rail-item icon="settings" label="Settings"></schmancy-navigation-rail-item>
55
- * </schmancy-navigation-rail>
56
- */
57
- @customElement('schmancy-navigation-rail')
58
- export class SchmancyNavigationRail extends SchmancyElement {
59
- // Observable state
60
- private activeIndex$ = new BehaviorSubject<number>(-1)
61
-
62
- // Properties
63
- /**
64
- * The currently active item index
65
- * @default -1
66
- */
67
- @property({ type: Number })
68
- get activeIndex() {
69
- return this.activeIndex$.value
70
- }
71
- set activeIndex(value: number) {
72
- this.activeIndex$.next(value)
73
- }
74
-
75
- /**
76
- * The currently active item value (for programmatic selection)
77
- */
78
- @property({ type: String })
79
- get activeValue() {
80
- return this._activeValue
81
- }
82
- set activeValue(value: string) {
83
- this._activeValue = value
84
- this.updateActiveByValue(value)
85
- }
86
- private _activeValue = ''
87
-
88
- /**
89
- * When to show labels for navigation items
90
- * 'all' - Always show labels for all items
91
- * 'selected' - Only show label for selected item
92
- * 'none' - Never show labels
93
- * @default 'all'
94
- */
95
- @property({ type: String, attribute: 'label-visibility', reflect: true })
96
- labelVisibility: LabelVisibility = 'all'
97
-
98
- /**
99
- * Alignment of navigation items
100
- * @default 'top'
101
- */
102
- @property({ type: String, reflect: true })
103
- alignment: 'top' | 'center' | 'bottom' = 'top'
104
-
105
- /**
106
- * Show tooltips when labels are hidden
107
- * @default true
108
- */
109
- @property({ type: Boolean })
110
- showTooltips = true
111
-
112
- /**
113
- * Enable keyboard navigation
114
- * @default true
115
- */
116
- @property({ type: Boolean })
117
- keyboardNavigation = true
118
-
119
- /**
120
- * Whether the navigation rail is expanded
121
- * @default false
122
- */
123
- @property({ type: Boolean, reflect: true })
124
- expanded = false
125
-
126
-
127
- // State
128
- @state()
129
- private focusedIndex = -1
130
-
131
- @state()
132
- private hasHeaderContent = false
133
-
134
- @state()
135
- private isFullscreen = false
136
-
137
- // Queries
138
-
139
- @queryAssignedElements({ flatten: true })
140
- private allElements!: Element[]
141
-
142
- private get navigationItems(): SchmancyNavigationRailItem[] {
143
- return this.allElements.filter(el => el.tagName === 'SCHMANCY-NAVIGATION-RAIL-ITEM') as SchmancyNavigationRailItem[]
144
- }
145
-
146
- connectedCallback() {
147
- super.connectedCallback()
148
-
149
- // Set up keyboard navigation if enabled
150
- if (this.keyboardNavigation) {
151
- this.addEventListener('keydown', this.handleKeyDown)
152
- }
153
-
154
- // Subscribe to active index changes with distinct values only
155
- this.activeIndex$
156
- .pipe(
157
- distinctUntilChanged(),
158
- tap(index => this.updateActiveStates(index)),
159
- takeUntil(this.disconnecting),
160
- )
161
- .subscribe()
162
-
163
- // Listen to fullscreen events
164
- fromEvent(window, 'fullscreen').pipe(
165
- tap((event: Event) => {
166
- const customEvent = event as CustomEvent
167
- this.isFullscreen = customEvent.detail
168
- }),
169
- takeUntil(this.disconnecting)
170
- ).subscribe()
171
-
172
- // Listen for navigate events from child items
173
- this.setupNavigateListener()
174
-
175
- // Set up label visibility
176
- this.updateLabelVisibility()
177
-
178
- // Update ARIA attributes
179
- this.setAttribute('role', 'navigation')
180
- this.setAttribute('aria-label', 'Main navigation')
181
- }
182
-
183
- updated(changedProperties: PropertyValues) {
184
- super.updated(changedProperties)
185
-
186
- if (changedProperties.has('labelVisibility')) {
187
- this.updateLabelVisibility()
188
- }
189
-
190
- if (changedProperties.has('activeValue')) {
191
- this.updateActiveByValue(this.activeValue)
192
- }
193
-
194
- if (changedProperties.has('expanded')) {
195
- this.updateLabelVisibility()
196
- }
197
- }
198
-
199
- private updateActiveStates(index: number) {
200
- this.navigationItems.forEach((item, i) => {
201
- const isActive = i === index
202
- item.active = isActive
203
- item.setAttribute('aria-selected', String(isActive))
204
- item.setAttribute('tabindex', isActive ? '0' : '-1')
205
-
206
- // Update activeValue when index changes
207
- if (isActive) {
208
- this._activeValue = item.value || item.label || ''
209
- }
210
- })
211
- }
212
-
213
- private updateActiveByValue(value: string) {
214
- const index = this.navigationItems.findIndex(item => item.getAttribute('value') === value || item.label === value)
215
- if (index >= 0) {
216
- this.activeIndex = index
217
- }
218
- }
219
-
220
- private updateLabelVisibility() {
221
- this.navigationItems.forEach((item, i) => {
222
- let shouldShowLabel = false
223
-
224
- // M3 Spec: In expanded state, always show all labels
225
- if (this.expanded) {
226
- shouldShowLabel = true
227
- } else {
228
- // In collapsed state, respect labelVisibility setting
229
- shouldShowLabel =
230
- this.labelVisibility === 'all' || (this.labelVisibility === 'selected' && i === this.activeIndex)
231
- }
232
-
233
- item.showLabel = shouldShowLabel
234
-
235
- // Add tooltips when labels are hidden (only in collapsed state)
236
- if (this.showTooltips && !shouldShowLabel && !this.expanded && item.label) {
237
- item.setAttribute('title', item.label)
238
- } else {
239
- item.removeAttribute('title')
240
- }
241
- })
242
- }
243
-
244
- // Note: Hover-based label showing removed for M3 compliance
245
- // Labels are now controlled via labelVisibility property and expanded state
246
-
247
- /**
248
- * Programmatically expand the navigation rail
249
- */
250
- expand() {
251
- this.expanded = true
252
- }
253
-
254
- /**
255
- * Programmatically collapse the navigation rail
256
- */
257
- collapse() {
258
- this.expanded = false
259
- }
260
-
261
- /**
262
- * Add a boat item to the navigation rail
263
- * @param config Configuration for the boat item
264
- * @returns The created or existing navigation rail item element
265
- */
266
- public addBoatItem(config: { id: string; title: string; icon?: string }) {
267
- // Check if item already exists
268
- const existingItem = this.querySelector(`[value="${config.id}"]`) as HTMLElement
269
- if (existingItem) {
270
- // Item already exists, just return it
271
- return existingItem
272
- }
273
-
274
- // Create new item
275
- const item = document.createElement('schmancy-navigation-rail-item')
276
- item.setAttribute('value', config.id)
277
- item.innerHTML = `
278
- <schmancy-icon slot="icon">${config.icon || 'widgets'}</schmancy-icon>
279
- ${config.title}
280
- `
281
- // Add to the rail before any footer content
282
- const footer = this.querySelector('[slot="footer"]')
283
- if (footer) {
284
- this.insertBefore(item, footer)
285
- } else {
286
- this.appendChild(item)
287
- }
288
- return item
289
- }
290
-
291
- /**
292
- * Toggle the navigation rail between expanded and collapsed states
293
- */
294
- toggle() {
295
- this.expanded = !this.expanded
296
- }
297
-
298
-
299
- private handleKeyDown(event: KeyboardEvent) {
300
- const items = this.navigationItems
301
- if (items.length === 0) return
302
-
303
- let newIndex = this.focusedIndex >= 0 ? this.focusedIndex : this.activeIndex
304
-
305
- switch (event.key) {
306
- case 'ArrowDown':
307
- event.preventDefault()
308
- newIndex = (newIndex + 1) % items.length
309
- break
310
- case 'ArrowUp':
311
- event.preventDefault()
312
- newIndex = newIndex <= 0 ? items.length - 1 : newIndex - 1
313
- break
314
- case 'Home':
315
- event.preventDefault()
316
- newIndex = 0
317
- break
318
- case 'End':
319
- event.preventDefault()
320
- newIndex = items.length - 1
321
- break
322
- case 'Enter':
323
- case ' ':
324
- event.preventDefault()
325
- if (newIndex >= 0) {
326
- items[newIndex].click()
327
- }
328
- return
329
- default:
330
- return
331
- }
332
-
333
- this.focusedIndex = newIndex
334
- items[newIndex].focus()
335
- }
336
-
337
- private handleFabClick(event: Event) {
338
- event.stopPropagation()
339
- this.dispatchEvent(
340
- new CustomEvent('fab-click', {
341
- bubbles: true,
342
- composed: true,
343
- }),
344
- )
345
- }
346
-
347
- private handleMenuClick(event: Event) {
348
- event.stopPropagation()
349
- this.dispatchEvent(
350
- new CustomEvent('menu-click', {
351
- bubbles: true,
352
- composed: true,
353
- }),
354
- )
355
- }
356
-
357
- protected render() {
358
- // Host-level classes for the navigation rail
359
- const hostClasses = this.classMap({
360
- // Layout & Structure - Fixed width to prevent layout shift
361
- 'flex flex-col': true,
362
- 'h-full': true,
363
- 'box-border relative overflow-visible': true,
364
- 'z-10 hover:z-[100]': true, // Base z-index, elevated on hover for overlay
365
-
366
- // Width - collapses to 0 when fullscreen
367
- 'w-20': !this.isFullscreen, // w-20 = 80px fixed width (M3 spec: 80dp)
368
- 'w-0': this.isFullscreen, // Collapse width to 0 in fullscreen
369
-
370
- // Visibility and transition
371
- 'transition-all duration-300 ease-emphasized': true,
372
- 'opacity-100': !this.isFullscreen,
373
- 'opacity-0 pointer-events-none': this.isFullscreen,
374
- 'overflow-hidden': this.isFullscreen, // Hide overflow when collapsed
375
- })
376
-
377
- // Rail container - programmatically controlled width
378
- const railClasses = this.classMap({
379
- // Layout & Structure
380
- 'flex flex-col h-full': true,
381
- 'box-border relative': true,
382
-
383
- // M3 Colors & Theme
384
- 'bg-container-lowest text-surface-on': true,
385
-
386
- // M3 Motion - smooth transitions for width and shadow
387
- 'transition-all duration-300 ease-emphasized': true,
388
-
389
- // Collapsed state (default) - M3 standard 80px width
390
- 'w-20': !this.expanded, // w-20 = 80px (M3 spec: 80dp)
391
- 'px-3': !this.expanded, // px-3 = 12px (M3 spec: 12px to center 56px items)
392
-
393
- // Expanded state - M3 expanded width with shadow
394
- 'w-60': this.expanded, // w-60 = 240px expanded width
395
- 'px-4': this.expanded, // Larger padding when expanded
396
- 'shadow-lg': this.expanded, // M3 elevation 3 shadow when expanded
397
- })
398
-
399
- // Header section classes - hidden when no content
400
- const headerClasses = this.classMap({
401
- 'flex flex-col items-center gap-1': true,
402
- 'hidden': !this.hasHeaderContent,
403
- })
404
-
405
- // Navigation container classes with alignment
406
- const navClasses = this.classMap({
407
- 'flex-1 flex flex-col gap-3': true, // gap-3 = 12px (M3 spec: 12px item spacing)
408
- 'min-h-0': true, // Allow flex shrinking and proper scroll container height calculation
409
- // Alignment variants
410
- 'justify-start': this.alignment === 'top',
411
- 'justify-center': this.alignment === 'center',
412
- 'justify-end': this.alignment === 'bottom',
413
- })
414
-
415
- // Footer section classes
416
- const footerClasses = this.classMap({
417
- 'flex flex-col items-center gap-1 mt-auto pt-2': true,
418
- })
419
-
420
- return html`
421
- <div
422
- class=${hostClasses}
423
- >
424
- <div class=${railClasses} part="rail">
425
- <div class=${headerClasses} part="header">
426
- <slot name="fab" @click=${this.handleFabClick} @slotchange=${this.handleHeaderSlotChange}></slot>
427
- <slot name="menu" @click=${this.handleMenuClick} @slotchange=${this.handleHeaderSlotChange}></slot>
428
- <slot name="header" @slotchange=${this.handleHeaderSlotChange}></slot>
429
- </div>
430
-
431
- <nav class=${navClasses} part="nav" role="list">
432
- <schmancy-scroll hide direction="vertical">
433
- <slot @slotchange=${this.handleSlotChange}></slot>
434
- </schmancy-scroll>
435
- </nav>
436
-
437
- <div class=${footerClasses} part="footer">
438
- <slot name="footer"></slot>
439
- </div>
440
- </div>
441
- </div>
442
- `
443
- }
444
-
445
- private setupNavigateListener() {
446
- // Listen for navigate events from child items
447
- this.addEventListener('navigate', (e: Event) => {
448
- if (e instanceof CustomEvent) {
449
- const value = e.detail
450
- // Find the item that dispatched the event and update active state
451
- const itemIndex = this.navigationItems.findIndex(item => item.value === value || item.label === value)
452
- if (itemIndex >= 0) {
453
- this.activeIndex = itemIndex
454
- this._activeValue = value
455
- }
456
- }
457
- })
458
- }
459
-
460
- private handleHeaderSlotChange() {
461
- // Check if any header slot has content
462
- const headerDiv = this.shadowRoot?.querySelector('[part="header"]')
463
- if (headerDiv) {
464
- const allSlots = headerDiv.querySelectorAll('slot')
465
- this.hasHeaderContent = Array.from(allSlots).some(s =>
466
- s.assignedNodes({ flatten: true }).length > 0
467
- )
468
- }
469
- }
470
-
471
- private handleSlotChange() {
472
- // Update items when slot content changes
473
- this.updateLabelVisibility()
474
- this.updateActiveStates(this.activeIndex)
475
-
476
- // Set ARIA attributes on items
477
- this.navigationItems.forEach((item, index) => {
478
- item.setAttribute('role', 'listitem')
479
- if (!item.hasAttribute('tabindex')) {
480
- item.setAttribute('tabindex', index === this.activeIndex ? '0' : '-1')
481
- }
482
- })
483
- }
484
- }
485
-
486
- declare global {
487
- interface HTMLElementTagNameMap {
488
- 'schmancy-navigation-rail': SchmancyNavigationRail
489
- }
490
- }
1
+ import { SchmancyElement } from '@mixins/index'
2
+ import { html, PropertyValues } from 'lit'
3
+ import { customElement, property, queryAssignedElements, state } from 'lit/decorators.js'
4
+ import { BehaviorSubject, fromEvent, Observable, takeUntil } from 'rxjs'
5
+ import { distinctUntilChanged, tap } from 'rxjs/operators'
6
+ import { SchmancyNavigationRailItem } from './navigation-rail-item'
7
+
8
+ /**
9
+ * Regex matching Tailwind utility prefixes that control items-container layout.
10
+ * Classes matching this are forwarded from the host's `class` attribute to the
11
+ * inner `<nav>` element so authors can write e.g. `class="grid gap-2"` on the
12
+ * host and have the items container adopt that layout.
13
+ * Classes NOT matching (bg-*, text-*, shadow-*, etc.) stay on the host only.
14
+ */
15
+ const LAYOUT_CLASS_RE =
16
+ /^(grid($|-)|flex($|-)|gap-|col-|row-|justify-|items-|content-|place-|auto-|grid-cols-|grid-rows-)/
17
+
18
+ export type NavigateEvent = CustomEvent<string>
19
+
20
+ export type NavigationRailMenuClickEvent = CustomEvent<void>
21
+
22
+ export type NavigationRailFabClickEvent = CustomEvent<void>
23
+
24
+
25
+ export type LabelVisibility = 'all' | 'selected' | 'none'
26
+
27
+ /**
28
+ * Material Design 3 Navigation Rail Component
29
+ * @see https://m3.material.io/components/navigation-rail/overview
30
+ *
31
+ * `<schmancy-navigation-rail>` component
32
+ *
33
+ * A Material Design 3 vertical navigation component positioned on the left side of an application.
34
+ * Navigation rails provide access to between 3-7 primary destinations with a compact footprint.
35
+ * Automatically hides in fullscreen mode when triggered via schmancyTheme.next({ fullscreen: true }).
36
+ *
37
+ * ## Layout composition
38
+ * Place layout utilities directly on the host element. They are forwarded to the
39
+ * items container `<div part="items">` (the direct flat-tree parent of slotted items,
40
+ * placed inside `<schmancy-scroll>`). When no layout utilities are present on the host,
41
+ * the items container defaults to `flex flex-col gap-3` plus the `justify-*` class
42
+ * driven by the `alignment` property.
43
+ *
44
+ * <schmancy-navigation-rail class="grid gap-2">…</schmancy-navigation-rail>
45
+ * → items container <div>: `grid gap-2`
46
+ *
47
+ * <schmancy-navigation-rail>…</schmancy-navigation-rail>
48
+ * → items container <div>: `flex flex-col gap-3 justify-start`
49
+ *
50
+ * @element schmancy-navigation-rail
51
+ * @slot fab - Slot for a floating action button at the top
52
+ * @slot menu - Slot for a menu icon or button below the FAB
53
+ * @slot header - Custom header content slot
54
+ * @slot footer - Custom footer content slot
55
+ * @slot - Default slot for navigation rail items
56
+ *
57
+ * @fires navigate - When a navigation item is selected
58
+ * @fires menu-click - When the menu button is clicked
59
+ * @fires fab-click - When the FAB is clicked
60
+ *
61
+ * @csspart rail - The main rail container
62
+ * @csspart header - The header section
63
+ * @csspart nav - The navigation scroll region (contains items)
64
+ * @csspart items - The direct layout container for slotted items (inside schmancy-scroll)
65
+ * @csspart footer - The footer section
66
+ *
67
+ * @example
68
+ * <schmancy-navigation-rail activeIndex="0">
69
+ * <schmancy-button slot="fab" variant="filled" aria-label="Compose">
70
+ * <schmancy-icon>add</schmancy-icon>
71
+ * </schmancy-button>
72
+ * <schmancy-button slot="menu" variant="text" aria-label="Menu">
73
+ * <schmancy-icon>menu</schmancy-icon>
74
+ * </schmancy-button>
75
+ * <schmancy-navigation-rail-item icon="home" label="Home"></schmancy-navigation-rail-item>
76
+ * <schmancy-navigation-rail-item icon="search" label="Search"></schmancy-navigation-rail-item>
77
+ * <schmancy-navigation-rail-item icon="favorite" label="Favorites" badge="3"></schmancy-navigation-rail-item>
78
+ * <schmancy-navigation-rail-item icon="settings" label="Settings"></schmancy-navigation-rail-item>
79
+ * </schmancy-navigation-rail>
80
+ */
81
+ @customElement('schmancy-navigation-rail')
82
+ export class SchmancyNavigationRail extends SchmancyElement {
83
+ // Observable state
84
+ private activeIndex$ = new BehaviorSubject<number>(-1)
85
+
86
+ // Properties
87
+ /**
88
+ * The currently active item index
89
+ * @default -1
90
+ */
91
+ @property({ type: Number })
92
+ get activeIndex() {
93
+ return this.activeIndex$.value
94
+ }
95
+ set activeIndex(value: number) {
96
+ this.activeIndex$.next(value)
97
+ }
98
+
99
+ /**
100
+ * The currently active item value (for programmatic selection)
101
+ */
102
+ @property({ type: String })
103
+ get activeValue() {
104
+ return this._activeValue
105
+ }
106
+ set activeValue(value: string) {
107
+ this._activeValue = value
108
+ this.updateActiveByValue(value)
109
+ }
110
+ private _activeValue = ''
111
+
112
+ /**
113
+ * When to show labels for navigation items
114
+ * 'all' - Always show labels for all items
115
+ * 'selected' - Only show label for selected item
116
+ * 'none' - Never show labels
117
+ * @default 'all'
118
+ */
119
+ @property({ type: String, attribute: 'label-visibility', reflect: true })
120
+ labelVisibility: LabelVisibility = 'all'
121
+
122
+ /**
123
+ * Alignment of navigation items
124
+ * @default 'top'
125
+ */
126
+ @property({ type: String, reflect: true })
127
+ alignment: 'top' | 'center' | 'bottom' = 'top'
128
+
129
+ /**
130
+ * Show tooltips when labels are hidden
131
+ * @default true
132
+ */
133
+ @property({ type: Boolean })
134
+ showTooltips = true
135
+
136
+ /**
137
+ * Enable keyboard navigation
138
+ * @default true
139
+ */
140
+ @property({ type: Boolean })
141
+ keyboardNavigation = true
142
+
143
+ /**
144
+ * Whether the navigation rail is expanded
145
+ * @default false
146
+ */
147
+ @property({ type: Boolean, reflect: true })
148
+ expanded = false
149
+
150
+
151
+ // State
152
+ @state()
153
+ private focusedIndex = -1
154
+
155
+ @state()
156
+ private hasHeaderContent = false
157
+
158
+ @state()
159
+ private isFullscreen = false
160
+
161
+ /**
162
+ * Layout-related classes extracted from the host's `class` attribute.
163
+ * Forwarded verbatim to the inner `<nav>` element.
164
+ * When empty, the nav falls back to the M3 default: `flex flex-col gap-3`.
165
+ */
166
+ @state()
167
+ private _hostLayoutClasses = ''
168
+
169
+ // Queries
170
+
171
+ @queryAssignedElements({ flatten: true })
172
+ private allElements!: Element[]
173
+
174
+ private get navigationItems(): SchmancyNavigationRailItem[] {
175
+ return this.allElements.filter(el => el.tagName === 'SCHMANCY-NAVIGATION-RAIL-ITEM') as SchmancyNavigationRailItem[]
176
+ }
177
+
178
+ connectedCallback() {
179
+ super.connectedCallback()
180
+
181
+ // Set up keyboard navigation if enabled
182
+ if (this.keyboardNavigation) {
183
+ this.addEventListener('keydown', this.handleKeyDown)
184
+ }
185
+
186
+ // Subscribe to active index changes with distinct values only
187
+ this.activeIndex$
188
+ .pipe(
189
+ distinctUntilChanged(),
190
+ tap(index => this.updateActiveStates(index)),
191
+ takeUntil(this.disconnecting),
192
+ )
193
+ .subscribe()
194
+
195
+ // Listen to fullscreen events
196
+ fromEvent(window, 'fullscreen').pipe(
197
+ tap((event: Event) => {
198
+ const customEvent = event as CustomEvent
199
+ this.isFullscreen = customEvent.detail
200
+ }),
201
+ takeUntil(this.disconnecting)
202
+ ).subscribe()
203
+
204
+ // Watch the host's `class` attribute for layout utilities and forward them
205
+ // to the inner <nav>. The Observable wraps MutationObserver so teardown is
206
+ // handled by the existing takeUntil(this.disconnecting) pattern.
207
+ new Observable<string>(subscriber => {
208
+ const extract = () =>
209
+ Array.from(this.classList)
210
+ .filter(c => LAYOUT_CLASS_RE.test(c))
211
+ .join(' ')
212
+
213
+ subscriber.next(extract())
214
+
215
+ const mo = new MutationObserver(() => subscriber.next(extract()))
216
+ mo.observe(this, { attributes: true, attributeFilter: ['class'] })
217
+ return () => mo.disconnect()
218
+ }).pipe(
219
+ distinctUntilChanged(),
220
+ tap(layoutClasses => { this._hostLayoutClasses = layoutClasses }),
221
+ takeUntil(this.disconnecting),
222
+ ).subscribe()
223
+
224
+ // Listen for navigate events from child items
225
+ this.setupNavigateListener()
226
+
227
+ // Set up label visibility
228
+ this.updateLabelVisibility()
229
+
230
+ // Update ARIA attributes
231
+ this.setAttribute('role', 'navigation')
232
+ this.setAttribute('aria-label', 'Main navigation')
233
+ }
234
+
235
+ updated(changedProperties: PropertyValues) {
236
+ super.updated(changedProperties)
237
+
238
+ if (changedProperties.has('labelVisibility')) {
239
+ this.updateLabelVisibility()
240
+ }
241
+
242
+ if (changedProperties.has('activeValue')) {
243
+ this.updateActiveByValue(this.activeValue)
244
+ }
245
+
246
+ if (changedProperties.has('expanded')) {
247
+ this.updateLabelVisibility()
248
+ }
249
+ }
250
+
251
+ private updateActiveStates(index: number) {
252
+ this.navigationItems.forEach((item, i) => {
253
+ const isActive = i === index
254
+ item.active = isActive
255
+ item.setAttribute('aria-selected', String(isActive))
256
+ item.setAttribute('tabindex', isActive ? '0' : '-1')
257
+
258
+ // Update activeValue when index changes
259
+ if (isActive) {
260
+ this._activeValue = item.value || item.label || ''
261
+ }
262
+ })
263
+ }
264
+
265
+ private updateActiveByValue(value: string) {
266
+ const index = this.navigationItems.findIndex(item => item.getAttribute('value') === value || item.label === value)
267
+ if (index >= 0) {
268
+ this.activeIndex = index
269
+ }
270
+ }
271
+
272
+ private updateLabelVisibility() {
273
+ this.navigationItems.forEach((item, i) => {
274
+ let shouldShowLabel = false
275
+
276
+ // M3 Spec: In expanded state, always show all labels
277
+ if (this.expanded) {
278
+ shouldShowLabel = true
279
+ } else {
280
+ // In collapsed state, respect labelVisibility setting
281
+ shouldShowLabel =
282
+ this.labelVisibility === 'all' || (this.labelVisibility === 'selected' && i === this.activeIndex)
283
+ }
284
+
285
+ item.showLabel = shouldShowLabel
286
+
287
+ // Add tooltips when labels are hidden (only in collapsed state)
288
+ if (this.showTooltips && !shouldShowLabel && !this.expanded && item.label) {
289
+ item.setAttribute('title', item.label)
290
+ } else {
291
+ item.removeAttribute('title')
292
+ }
293
+ })
294
+ }
295
+
296
+ // Note: Hover-based label showing removed for M3 compliance
297
+ // Labels are now controlled via labelVisibility property and expanded state
298
+
299
+ /**
300
+ * Programmatically expand the navigation rail
301
+ */
302
+ expand() {
303
+ this.expanded = true
304
+ }
305
+
306
+ /**
307
+ * Programmatically collapse the navigation rail
308
+ */
309
+ collapse() {
310
+ this.expanded = false
311
+ }
312
+
313
+ /**
314
+ * Add a boat item to the navigation rail
315
+ * @param config Configuration for the boat item
316
+ * @returns The created or existing navigation rail item element
317
+ */
318
+ public addBoatItem(config: { id: string; title: string; icon?: string }) {
319
+ // Check if item already exists
320
+ const existingItem = this.querySelector(`[value="${config.id}"]`) as HTMLElement
321
+ if (existingItem) {
322
+ // Item already exists, just return it
323
+ return existingItem
324
+ }
325
+
326
+ // Create new item
327
+ const item = document.createElement('schmancy-navigation-rail-item')
328
+ item.setAttribute('value', config.id)
329
+ item.innerHTML = `
330
+ <schmancy-icon slot="icon">${config.icon || 'widgets'}</schmancy-icon>
331
+ ${config.title}
332
+ `
333
+ // Add to the rail before any footer content
334
+ const footer = this.querySelector('[slot="footer"]')
335
+ if (footer) {
336
+ this.insertBefore(item, footer)
337
+ } else {
338
+ this.appendChild(item)
339
+ }
340
+ return item
341
+ }
342
+
343
+ /**
344
+ * Toggle the navigation rail between expanded and collapsed states
345
+ */
346
+ toggle() {
347
+ this.expanded = !this.expanded
348
+ }
349
+
350
+
351
+ private handleKeyDown(event: KeyboardEvent) {
352
+ const items = this.navigationItems
353
+ if (items.length === 0) return
354
+
355
+ let newIndex = this.focusedIndex >= 0 ? this.focusedIndex : this.activeIndex
356
+
357
+ switch (event.key) {
358
+ case 'ArrowDown':
359
+ event.preventDefault()
360
+ newIndex = (newIndex + 1) % items.length
361
+ break
362
+ case 'ArrowUp':
363
+ event.preventDefault()
364
+ newIndex = newIndex <= 0 ? items.length - 1 : newIndex - 1
365
+ break
366
+ case 'Home':
367
+ event.preventDefault()
368
+ newIndex = 0
369
+ break
370
+ case 'End':
371
+ event.preventDefault()
372
+ newIndex = items.length - 1
373
+ break
374
+ case 'Enter':
375
+ case ' ':
376
+ event.preventDefault()
377
+ if (newIndex >= 0) {
378
+ items[newIndex].click()
379
+ }
380
+ return
381
+ default:
382
+ return
383
+ }
384
+
385
+ this.focusedIndex = newIndex
386
+ items[newIndex].focus()
387
+ }
388
+
389
+ private handleFabClick(event: Event) {
390
+ event.stopPropagation()
391
+ this.dispatchEvent(
392
+ new CustomEvent('fab-click', {
393
+ bubbles: true,
394
+ composed: true,
395
+ }),
396
+ )
397
+ }
398
+
399
+ private handleMenuClick(event: Event) {
400
+ event.stopPropagation()
401
+ this.dispatchEvent(
402
+ new CustomEvent('menu-click', {
403
+ bubbles: true,
404
+ composed: true,
405
+ }),
406
+ )
407
+ }
408
+
409
+ protected render() {
410
+ // Host-level classes for the navigation rail (width, visibility, z-index).
411
+ // Layout utilities the author placed on the host are NOT included here —
412
+ // they are forwarded to the inner <nav> via _hostLayoutClasses instead.
413
+ const hostClasses = this.classMap({
414
+ // Layout & Structure - Fixed width to prevent layout shift
415
+ 'flex flex-col': true,
416
+ 'h-full': true,
417
+ 'box-border relative overflow-visible': true,
418
+ 'z-10 hover:z-[100]': true, // Base z-index, elevated on hover for overlay
419
+
420
+ // Width - collapses to 0 when fullscreen
421
+ 'w-20': !this.isFullscreen, // w-20 = 80px fixed width (M3 spec: 80dp)
422
+ 'w-0': this.isFullscreen, // Collapse width to 0 in fullscreen
423
+
424
+ // Visibility and transition
425
+ 'transition-all duration-300 ease-emphasized': true,
426
+ 'opacity-100': !this.isFullscreen,
427
+ 'opacity-0 pointer-events-none': this.isFullscreen,
428
+ 'overflow-hidden': this.isFullscreen, // Hide overflow when collapsed
429
+ })
430
+
431
+ // Rail container - programmatically controlled width
432
+ const railClasses = this.classMap({
433
+ // Layout & Structure
434
+ 'flex flex-col h-full': true,
435
+ 'box-border relative': true,
436
+
437
+ // M3 Colors & Theme
438
+ 'bg-container-lowest text-surface-on': true,
439
+
440
+ // M3 Motion - smooth transitions for width and shadow
441
+ 'transition-all duration-300 ease-emphasized': true,
442
+
443
+ // Collapsed state (default) - M3 standard 80px width
444
+ 'w-20': !this.expanded, // w-20 = 80px (M3 spec: 80dp)
445
+ 'px-3': !this.expanded, // px-3 = 12px (M3 spec: 12px to center 56px items)
446
+
447
+ // Expanded state - M3 expanded width with shadow
448
+ 'w-60': this.expanded, // w-60 = 240px expanded width
449
+ 'px-4': this.expanded, // Larger padding when expanded
450
+ 'shadow-lg': this.expanded, // M3 elevation 3 shadow when expanded
451
+ })
452
+
453
+ // Header section classes - hidden when no content
454
+ const headerClasses = this.classMap({
455
+ 'flex flex-col items-center gap-1': true,
456
+ 'hidden': !this.hasHeaderContent,
457
+ })
458
+
459
+ // Navigation container <nav> — holds a single <schmancy-scroll> child, so only
460
+ // vertical fill classes belong here. Layout of the items themselves lives on the
461
+ // inner <div part="items"> so that the items' flat-tree parent is that div, not nav.
462
+ const navClasses = this.classMap({
463
+ 'flex-1': true,
464
+ 'min-h-0': true, // Allow flex shrinking and proper scroll container height calculation
465
+ })
466
+
467
+ // Items container <div> — the direct flat-tree parent of slotted navigation items
468
+ // after re-slotting through <schmancy-scroll>. Layout utilities forwarded from the
469
+ // host land here so that `grid gap-2` (or any other layout) actually shapes items.
470
+ // When the host carries no layout classes, default to M3 flex-column + alignment.
471
+ const hasHostLayout = this._hostLayoutClasses.length > 0
472
+ const itemsContainerClasses = hasHostLayout
473
+ ? this._hostLayoutClasses
474
+ : this.classMap({
475
+ 'flex flex-col gap-3': true,
476
+ 'justify-start': this.alignment === 'top',
477
+ 'justify-center': this.alignment === 'center',
478
+ 'justify-end': this.alignment === 'bottom',
479
+ })
480
+
481
+ // Footer section classes
482
+ const footerClasses = this.classMap({
483
+ 'flex flex-col items-center gap-1 mt-auto pt-2': true,
484
+ })
485
+
486
+ return html`
487
+ <div
488
+ class=${hostClasses}
489
+ >
490
+ <div class=${railClasses} part="rail">
491
+ <div class=${headerClasses} part="header">
492
+ <slot name="fab" @click=${this.handleFabClick} @slotchange=${this.handleHeaderSlotChange}></slot>
493
+ <slot name="menu" @click=${this.handleMenuClick} @slotchange=${this.handleHeaderSlotChange}></slot>
494
+ <slot name="header" @slotchange=${this.handleHeaderSlotChange}></slot>
495
+ </div>
496
+
497
+ <nav class=${navClasses} part="nav" role="list">
498
+ <schmancy-scroll hide direction="vertical">
499
+ <div class=${itemsContainerClasses} part="items">
500
+ <slot @slotchange=${this.handleSlotChange}></slot>
501
+ </div>
502
+ </schmancy-scroll>
503
+ </nav>
504
+
505
+ <div class=${footerClasses} part="footer">
506
+ <slot name="footer"></slot>
507
+ </div>
508
+ </div>
509
+ </div>
510
+ `
511
+ }
512
+
513
+ private setupNavigateListener() {
514
+ // Listen for navigate events from child items
515
+ this.addEventListener('navigate', (e: Event) => {
516
+ if (e instanceof CustomEvent) {
517
+ const value = e.detail
518
+ // Find the item that dispatched the event and update active state
519
+ const itemIndex = this.navigationItems.findIndex(item => item.value === value || item.label === value)
520
+ if (itemIndex >= 0) {
521
+ this.activeIndex = itemIndex
522
+ this._activeValue = value
523
+ }
524
+ }
525
+ })
526
+ }
527
+
528
+ private handleHeaderSlotChange() {
529
+ // Check if any header slot has content
530
+ const headerDiv = this.shadowRoot?.querySelector('[part="header"]')
531
+ if (headerDiv) {
532
+ const allSlots = headerDiv.querySelectorAll('slot')
533
+ this.hasHeaderContent = Array.from(allSlots).some(s =>
534
+ s.assignedNodes({ flatten: true }).length > 0
535
+ )
536
+ }
537
+ }
538
+
539
+ private handleSlotChange() {
540
+ // Update items when slot content changes
541
+ this.updateLabelVisibility()
542
+ this.updateActiveStates(this.activeIndex)
543
+
544
+ // Set ARIA attributes on items
545
+ this.navigationItems.forEach((item, index) => {
546
+ item.setAttribute('role', 'listitem')
547
+ if (!item.hasAttribute('tabindex')) {
548
+ item.setAttribute('tabindex', index === this.activeIndex ? '0' : '-1')
549
+ }
550
+ })
551
+ }
552
+ }
553
+
554
+ declare global {
555
+ interface HTMLElementTagNameMap {
556
+ 'schmancy-navigation-rail': SchmancyNavigationRail
557
+ }
558
+ }