@mhmo91/schmancy 0.10.15 → 0.10.17
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.
- package/custom-elements.json +2554 -3086
- package/dist/active-host-BP0zy_Y9.js +63 -0
- package/dist/{active-host-CvNYoprt.js.map → active-host-BP0zy_Y9.js.map} +1 -1
- package/dist/active-host-jH3iloCR.cjs +1 -0
- package/dist/{active-host-CcIa2tmW.cjs.map → active-host-jH3iloCR.cjs.map} +1 -1
- package/dist/agent/flow-CvG1fLW5.js.map +1 -1
- package/dist/agent/schmancy.agent.js +5694 -5500
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/agent/schmancy.manifest.json +971 -1189
- package/dist/agent/vendor-material-color-DcL7ZPxx.js.map +1 -1
- package/dist/{animation-CO_Csq84.cjs.map → animation-CCOIW4wJ.cjs.map} +1 -1
- package/dist/{animation-BK-8BwY8.js.map → animation-DCznELuT.js.map} +1 -1
- package/dist/{area-C_kgZZhN.js → area-ChxsDTu_.js} +2 -2
- package/dist/{area-C_kgZZhN.js.map → area-ChxsDTu_.js.map} +1 -1
- package/dist/{area-DFPtKzWy.cjs → area-Qt6yUnuA.cjs} +3 -3
- package/dist/{area-DFPtKzWy.cjs.map → area-Qt6yUnuA.cjs.map} +1 -1
- package/dist/area.cjs +1 -1
- package/dist/area.js +2 -2
- package/dist/{audio-CluX8Qpq.cjs → audio-D-TZzpXF.cjs} +1 -1
- package/dist/{audio-CluX8Qpq.cjs.map → audio-D-TZzpXF.cjs.map} +1 -1
- package/dist/{audio-DcXphulJ.js → audio-DS43uoRA.js} +1 -1
- package/dist/{audio-DcXphulJ.js.map → audio-DS43uoRA.js.map} +1 -1
- package/dist/audio.cjs +1 -1
- package/dist/audio.js +2 -2
- package/dist/{autocomplete-DWSuwSRS.js → autocomplete-CXvUjMD-.js} +46 -71
- package/dist/autocomplete-CXvUjMD-.js.map +1 -0
- package/dist/autocomplete-Ck2zbdF9.cjs +115 -0
- package/dist/autocomplete-Ck2zbdF9.cjs.map +1 -0
- package/dist/autocomplete.cjs +1 -1
- package/dist/autocomplete.js +1 -1
- package/dist/avatar.cjs +2 -2
- package/dist/avatar.cjs.map +1 -1
- package/dist/avatar.js +3 -3
- package/dist/avatar.js.map +1 -1
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/{boat-CZma2ojF.js → boat-Bj0wVcZi.js} +5 -5
- package/dist/{boat-CZma2ojF.js.map → boat-Bj0wVcZi.js.map} +1 -1
- package/dist/{boat-Dy6cc3hB.cjs → boat-DpFkILFF.cjs} +2 -2
- package/dist/{boat-Dy6cc3hB.cjs.map → boat-DpFkILFF.cjs.map} +1 -1
- package/dist/boat.cjs +1 -1
- package/dist/boat.js +1 -1
- package/dist/breadcrumb.cjs +3 -3
- package/dist/breadcrumb.cjs.map +1 -1
- package/dist/breadcrumb.js +2 -2
- package/dist/breadcrumb.js.map +1 -1
- package/dist/{busy-DCsqryvq.cjs → busy-CtcnclA3.cjs} +3 -3
- package/dist/{busy-DCsqryvq.cjs.map → busy-CtcnclA3.cjs.map} +1 -1
- package/dist/{busy-DeV2ByMw.js → busy-CyZSBnZP.js} +2 -2
- package/dist/{busy-DeV2ByMw.js.map → busy-CyZSBnZP.js.map} +1 -1
- package/dist/busy.cjs +1 -1
- package/dist/busy.js +1 -1
- package/dist/button.cjs +4 -4
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +19 -4
- package/dist/button.js.map +1 -1
- package/dist/{card--GgSX4X5.cjs → card-Cl6jp1yX.cjs} +5 -5
- package/dist/{card--GgSX4X5.cjs.map → card-Cl6jp1yX.cjs.map} +1 -1
- package/dist/{card-BTTsHzJJ.js → card-nYZCKmOO.js} +3 -3
- package/dist/{card-BTTsHzJJ.js.map → card-nYZCKmOO.js.map} +1 -1
- package/dist/card.cjs +1 -1
- package/dist/card.js +1 -1
- package/dist/{checkbox-NNReP9s_.cjs → checkbox-BeNo0ZGt.cjs} +4 -4
- package/dist/{checkbox-Cj5j-ppk.js.map → checkbox-BeNo0ZGt.cjs.map} +1 -1
- package/dist/{checkbox-Cj5j-ppk.js → checkbox-DiUrZiyc.js} +17 -30
- package/dist/checkbox-DiUrZiyc.js.map +1 -0
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/{chips-CP-CbfoZ.js → chips-CfPFXv7Z.js} +5 -5
- package/dist/{chips-CP-CbfoZ.js.map → chips-CfPFXv7Z.js.map} +1 -1
- package/dist/{chips-iporOXxK.cjs → chips-DK6m-VCM.cjs} +5 -5
- package/dist/{chips-iporOXxK.cjs.map → chips-DK6m-VCM.cjs.map} +1 -1
- package/dist/chips.cjs +1 -1
- package/dist/chips.js +2 -2
- package/dist/connectivity.cjs +2 -2
- package/dist/connectivity.cjs.map +1 -1
- package/dist/connectivity.js +3 -3
- package/dist/connectivity.js.map +1 -1
- package/dist/content-drawer.cjs +1 -1
- package/dist/content-drawer.js +1 -1
- package/dist/{context-DJTJnSK4.js.map → context-6oXCZmZN.js.map} +1 -1
- package/dist/{context-BpCETidA.cjs.map → context-CRZeiCqq.cjs.map} +1 -1
- package/dist/{cursor-glow-Bulq-38P.cjs → cursor-glow-C8LgCxpI.cjs} +1 -1
- package/dist/{cursor-glow-Bulq-38P.cjs.map → cursor-glow-C8LgCxpI.cjs.map} +1 -1
- package/dist/{cursor-glow-Ah7VXSj7.js → cursor-glow-Cs2XLDB9.js} +1 -1
- package/dist/{cursor-glow-Ah7VXSj7.js.map → cursor-glow-Cs2XLDB9.js.map} +1 -1
- package/dist/date-range-DA6anfcF.cjs +131 -0
- package/dist/date-range-DA6anfcF.cjs.map +1 -0
- package/dist/{date-range-CgNujP8r.js → date-range-DjlF2u7o.js} +124 -89
- package/dist/date-range-DjlF2u7o.js.map +1 -0
- package/dist/date-range-inline-BfYK795W.cjs +43 -0
- package/dist/{date-range-inline-D4IjOOO0.cjs.map → date-range-inline-BfYK795W.cjs.map} +1 -1
- package/dist/{date-range-inline-C2PXX_GY.js → date-range-inline-n7y_H6PJ.js} +2 -2
- package/dist/{date-range-inline-C2PXX_GY.js.map → date-range-inline-n7y_H6PJ.js.map} +1 -1
- package/dist/date-range-inline.cjs +1 -1
- package/dist/date-range-inline.js +1 -1
- package/dist/date-range.cjs +1 -1
- package/dist/date-range.js +1 -1
- package/dist/delay.cjs +2 -2
- package/dist/delay.cjs.map +1 -1
- package/dist/delay.js +3 -3
- package/dist/delay.js.map +1 -1
- package/dist/{details-DT2b3xOn.cjs → details-BdAVsLl-.cjs} +2 -2
- package/dist/{details-DT2b3xOn.cjs.map → details-BdAVsLl-.cjs.map} +1 -1
- package/dist/{details-VjaNwtfd.js → details-CS_ToAOj.js} +6 -6
- package/dist/{details-VjaNwtfd.js.map → details-CS_ToAOj.js.map} +1 -1
- package/dist/details.cjs +1 -1
- package/dist/details.js +1 -1
- package/dist/directives.cjs +1 -1
- package/dist/directives.cjs.map +1 -1
- package/dist/directives.js +5 -5
- package/dist/directives.js.map +1 -1
- package/dist/discovery.js.map +1 -1
- package/dist/{divider-BMO8pzEO.js → divider-COLK0RbT.js} +2 -2
- package/dist/{divider-BMO8pzEO.js.map → divider-COLK0RbT.js.map} +1 -1
- package/dist/{divider-BW33TZ-X.cjs → divider-CvWAnvdO.cjs} +2 -2
- package/dist/{divider-BW33TZ-X.cjs.map → divider-CvWAnvdO.cjs.map} +1 -1
- package/dist/divider.cjs +1 -1
- package/dist/divider.js +1 -1
- package/dist/dropdown.cjs +3 -3
- package/dist/dropdown.cjs.map +1 -1
- package/dist/dropdown.js +2 -2
- package/dist/dropdown.js.map +1 -1
- package/dist/{expand-DbELKKOt.js → expand-D9LzmpoV.js} +5 -5
- package/dist/{expand-DbELKKOt.js.map → expand-D9LzmpoV.js.map} +1 -1
- package/dist/{expand-_f5EUKWB.cjs → expand-r2sATPUJ.cjs} +3 -3
- package/dist/{expand-_f5EUKWB.cjs.map → expand-r2sATPUJ.cjs.map} +1 -1
- package/dist/expand.cjs +1 -1
- package/dist/expand.js +1 -1
- package/dist/float-2nHYuBx-.cjs +1 -0
- package/dist/{float-CKmd-0-t.cjs.map → float-2nHYuBx-.cjs.map} +1 -1
- package/dist/{float-B6RBb2dN.js → float-BWy39CXr.js} +2 -2
- package/dist/{float-B6RBb2dN.js.map → float-BWy39CXr.js.map} +1 -1
- package/dist/float.cjs +1 -1
- package/dist/float.js +1 -1
- package/dist/form-D1iJOLVb.js +267 -0
- package/dist/form-D1iJOLVb.js.map +1 -0
- package/dist/form-D9K1GhlP.cjs +42 -0
- package/dist/form-D9K1GhlP.cjs.map +1 -0
- package/dist/form.cjs +1 -1
- package/dist/form.js +9 -2
- package/dist/handover/agent-runtime-followups.md +1 -1
- package/dist/handover/agent-runtime-v1.md +3 -3
- package/dist/{hashContent-Bobsobip.cjs.map → hashContent-Ck6laKlk.cjs.map} +1 -1
- package/dist/{hashContent-BU6jl5ih.js.map → hashContent-dJrI-9sc.js.map} +1 -1
- package/dist/{icons-r-S17M8U.cjs → icons-BXp4vbnW.cjs} +2 -2
- package/dist/{icons-r-S17M8U.cjs.map → icons-BXp4vbnW.cjs.map} +1 -1
- package/dist/{icons-CoDo95Cu.js → icons-COrlmBPB.js} +3 -3
- package/dist/{icons-CoDo95Cu.js.map → icons-COrlmBPB.js.map} +1 -1
- package/dist/icons.cjs +1 -1
- package/dist/icons.js +1 -1
- package/dist/{iframe-P9c_qg1-.cjs → iframe-BwXj6mLp.cjs} +2 -2
- package/dist/{iframe-P9c_qg1-.cjs.map → iframe-BwXj6mLp.cjs.map} +1 -1
- package/dist/{iframe-k4oI-TIj.js → iframe-CPNsIy7k.js} +2 -2
- package/dist/{iframe-k4oI-TIj.js.map → iframe-CPNsIy7k.js.map} +1 -1
- package/dist/iframe.cjs +1 -1
- package/dist/iframe.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +60 -60
- package/dist/input-BGrF2qVq.cjs +52 -0
- package/dist/input-BGrF2qVq.cjs.map +1 -0
- package/dist/{input-D95GjINh.js → input-C1SnMNuQ.js} +103 -104
- package/dist/input-C1SnMNuQ.js.map +1 -0
- package/dist/{input-chip-DpC_XEKN.js → input-chip-CtQ0pH5b.js} +2 -2
- package/dist/{input-chip-DpC_XEKN.js.map → input-chip-CtQ0pH5b.js.map} +1 -1
- package/dist/{input-chip-D0ZXqTt5.cjs → input-chip-DZktYohr.cjs} +2 -2
- package/dist/{input-chip-D0ZXqTt5.cjs.map → input-chip-DZktYohr.cjs.map} +1 -1
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/json.cjs +2 -2
- package/dist/json.cjs.map +1 -1
- package/dist/json.js +3 -3
- package/dist/json.js.map +1 -1
- package/dist/kbd.cjs +2 -2
- package/dist/kbd.cjs.map +1 -1
- package/dist/kbd.js +2 -2
- package/dist/kbd.js.map +1 -1
- package/dist/{layout-CXPNsUIo.js → layout-BH28sKGc.js} +1 -1
- package/dist/{layout-CXPNsUIo.js.map → layout-BH28sKGc.js.map} +1 -1
- package/dist/{layout-Zhe7wSZ_.cjs → layout-Delq-QvR.cjs} +1 -1
- package/dist/{layout-Zhe7wSZ_.cjs.map → layout-Delq-QvR.cjs.map} +1 -1
- package/dist/layout.cjs +1 -1
- package/dist/layout.js +1 -1
- package/dist/{lazy-Dq9mRRjT.cjs.map → lazy-CayEFyC3.cjs.map} +1 -1
- package/dist/{lazy-B0ia54tT.js.map → lazy-D-bO2r4m.js.map} +1 -1
- package/dist/{lightbox-CovQtmyn.js → lightbox-CLwpaiai.js} +9 -9
- package/dist/{lightbox-CovQtmyn.js.map → lightbox-CLwpaiai.js.map} +1 -1
- package/dist/{lightbox-C-yHeoK0.cjs → lightbox-Ck6BpN5u.cjs} +3 -3
- package/dist/{lightbox-C-yHeoK0.cjs.map → lightbox-Ck6BpN5u.cjs.map} +1 -1
- package/dist/lightbox.cjs +1 -1
- package/dist/lightbox.js +1 -1
- package/dist/{list-C1pR9vhu.js → list-Bmce1Rb8.js} +2 -2
- package/dist/{list-C1pR9vhu.js.map → list-Bmce1Rb8.js.map} +1 -1
- package/dist/{list-CAijuky4.cjs → list-EmRwSpTU.cjs} +3 -3
- package/dist/{list-CAijuky4.cjs.map → list-EmRwSpTU.cjs.map} +1 -1
- package/dist/list.cjs +1 -1
- package/dist/list.js +1 -1
- package/dist/{magnetic-BJgB1dVi.cjs → magnetic-Bgh7aHHI.cjs} +1 -1
- package/dist/{magnetic-BJgB1dVi.cjs.map → magnetic-Bgh7aHHI.cjs.map} +1 -1
- package/dist/{magnetic-YwCNvtbB.js → magnetic-DxvoEz8_.js} +2 -2
- package/dist/{magnetic-YwCNvtbB.js.map → magnetic-DxvoEz8_.js.map} +1 -1
- package/dist/{menu-B59vZv9n.js → menu-BA_B7QOG.js} +3 -3
- package/dist/{menu-B59vZv9n.js.map → menu-BA_B7QOG.js.map} +1 -1
- package/dist/{menu-BaHO3Cip.cjs → menu-BTU3wGP6.cjs} +3 -3
- package/dist/{menu-BaHO3Cip.cjs.map → menu-BTU3wGP6.cjs.map} +1 -1
- package/dist/menu.cjs +1 -1
- package/dist/menu.js +1 -1
- package/dist/mixins-BOOu6q2n.cjs +298 -0
- package/dist/mixins-BOOu6q2n.cjs.map +1 -0
- package/dist/mixins-BWb9_e1s.js +680 -0
- package/dist/mixins-BWb9_e1s.js.map +1 -0
- package/dist/mixins.cjs +1 -1
- package/dist/mixins.js +2 -2
- package/dist/nav-drawer.cjs +1 -1
- package/dist/nav-drawer.js +1 -1
- package/dist/navigation-bar.cjs +1 -1
- package/dist/navigation-bar.js +1 -1
- package/dist/navigation-rail.cjs +3 -3
- package/dist/navigation-rail.cjs.map +1 -1
- package/dist/navigation-rail.js +2 -2
- package/dist/navigation-rail.js.map +1 -1
- package/dist/notification-CliGbcfU.cjs +23 -0
- package/dist/{notification-BC9nG8Sr.cjs.map → notification-CliGbcfU.cjs.map} +1 -1
- package/dist/{notification-BeLoVa47.js → notification-R2_Mf1HR.js} +4 -4
- package/dist/{notification-BeLoVa47.js.map → notification-R2_Mf1HR.js.map} +1 -1
- package/dist/notification.cjs +1 -1
- package/dist/notification.js +1 -1
- package/dist/{option-UvlSAcC4.js → option-DU1X4SDu.js} +2 -2
- package/dist/{option-UvlSAcC4.js.map → option-DU1X4SDu.js.map} +1 -1
- package/dist/{option-BWF4GBp-.cjs → option-Db98Ndzv.cjs} +2 -2
- package/dist/{option-BWF4GBp-.cjs.map → option-Db98Ndzv.cjs.map} +1 -1
- package/dist/option.cjs +1 -1
- package/dist/option.js +1 -1
- package/dist/{overlay-stack-DCDS17uj.js.map → overlay-stack-BR4iYivO.js.map} +1 -1
- package/dist/{overlay-stack-DPIe_aYv.cjs.map → overlay-stack-Dk0xETTy.cjs.map} +1 -1
- package/dist/overlay.cjs +2 -2
- package/dist/overlay.cjs.map +1 -1
- package/dist/{overlay.confirm-body-URtE1gI3.cjs → overlay.confirm-body-BkhNvr0c.cjs} +2 -2
- package/dist/{overlay.confirm-body-URtE1gI3.cjs.map → overlay.confirm-body-BkhNvr0c.cjs.map} +1 -1
- package/dist/{overlay.confirm-body-9W0B5QGv.js → overlay.confirm-body-uFp-0Zfh.js} +2 -2
- package/dist/{overlay.confirm-body-9W0B5QGv.js.map → overlay.confirm-body-uFp-0Zfh.js.map} +1 -1
- package/dist/overlay.js +8 -8
- package/dist/overlay.js.map +1 -1
- package/dist/{overlay.service-DnZTcKyJ.cjs → overlay.service-1YWfUD2S.cjs} +1 -1
- package/dist/{overlay.service-DnZTcKyJ.cjs.map → overlay.service-1YWfUD2S.cjs.map} +1 -1
- package/dist/{overlay.service-CVqs2Gu1.js → overlay.service-BcF12kGb.js} +2 -2
- package/dist/{overlay.service-CVqs2Gu1.js.map → overlay.service-BcF12kGb.js.map} +1 -1
- package/dist/page.cjs +2 -2
- package/dist/page.cjs.map +1 -1
- package/dist/page.js +5 -5
- package/dist/page.js.map +1 -1
- package/dist/{progress-C29Uw-WJ.js → progress-C9Y2D5cm.js} +2 -2
- package/dist/{progress-C29Uw-WJ.js.map → progress-C9Y2D5cm.js.map} +1 -1
- package/dist/{progress-CwzwY8Oe.cjs → progress-DiVTGAXa.cjs} +2 -2
- package/dist/{progress-CwzwY8Oe.cjs.map → progress-DiVTGAXa.cjs.map} +1 -1
- package/dist/progress.cjs +1 -1
- package/dist/progress.js +1 -1
- package/dist/{radio-group-CW8airhZ.js → radio-group-CAzjBI2n.js} +4 -4
- package/dist/radio-group-CAzjBI2n.js.map +1 -0
- package/dist/radio-group-DIRJyYv6.cjs +40 -0
- package/dist/radio-group-DIRJyYv6.cjs.map +1 -0
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/range.cjs +6 -4
- package/dist/range.cjs.map +1 -1
- package/dist/range.js +19 -15
- package/dist/range.js.map +1 -1
- package/dist/{reduced-motion-D-L12p7G.js.map → reduced-motion-D7LqTUMn.js.map} +1 -1
- package/dist/{reduced-motion-Ds-HjMzn.cjs.map → reduced-motion-Dzfp_w5x.cjs.map} +1 -1
- package/dist/{rxjs-utils-DCUHg_Ml.cjs.map → rxjs-utils-BKB2UM_j.cjs.map} +1 -1
- package/dist/{rxjs-utils-CVeJQ9KG.js.map → rxjs-utils-Dv9T9IpA.js.map} +1 -1
- package/dist/rxjs-utils.cjs +1 -1
- package/dist/rxjs-utils.js +1 -1
- package/dist/{scroll-BotoGcMU.js → scroll-BFHUtZOa.js} +2 -2
- package/dist/{scroll-BotoGcMU.js.map → scroll-BFHUtZOa.js.map} +1 -1
- package/dist/{scroll-CmhmUebp.cjs → scroll-nIZyoEMt.cjs} +2 -2
- package/dist/{scroll-CmhmUebp.cjs.map → scroll-nIZyoEMt.cjs.map} +1 -1
- package/dist/{search-BLCRsxIC.cjs.map → search-DPKoC-dT.cjs.map} +1 -1
- package/dist/{search-BTz7-Rev.js.map → search-MvIBA93K.js.map} +1 -1
- package/dist/{select-Dbn-CImU.js → select-7WqaUWBU.js} +52 -73
- package/dist/select-7WqaUWBU.js.map +1 -0
- package/dist/select-DTuf6p6T.cjs +56 -0
- package/dist/select-DTuf6p6T.cjs.map +1 -0
- package/dist/select.cjs +1 -1
- package/dist/select.js +1 -1
- package/dist/skeleton.cjs +2 -2
- package/dist/skeleton.cjs.map +1 -1
- package/dist/skeleton.js +2 -2
- package/dist/skeleton.js.map +1 -1
- package/dist/skills/SKILL.md +3 -0
- package/dist/skills/autocomplete.md +16 -3
- package/dist/skills/button.md +19 -0
- package/dist/skills/checkbox.md +19 -0
- package/dist/skills/date-range.md +19 -0
- package/dist/skills/form-ux-rules.md +55 -0
- package/dist/skills/form.md +121 -25
- package/dist/skills/input.md +19 -4
- package/dist/skills/range.md +15 -1
- package/dist/skills/schmancy/SKILL.md +3 -0
- package/dist/skills/schmancy/autocomplete.md +16 -3
- package/dist/skills/schmancy/button.md +19 -0
- package/dist/skills/schmancy/checkbox.md +19 -0
- package/dist/skills/schmancy/date-range.md +19 -0
- package/dist/skills/schmancy/form-ux-rules.md +55 -0
- package/dist/skills/schmancy/form.md +121 -25
- package/dist/skills/schmancy/input.md +19 -4
- package/dist/skills/schmancy/range.md +15 -1
- package/dist/skills/schmancy/select.md +13 -1
- package/dist/skills/schmancy/switch.md +21 -2
- package/dist/skills/schmancy/textarea.md +13 -0
- package/dist/skills/select.md +13 -1
- package/dist/skills/switch.md +21 -2
- package/dist/skills/textarea.md +13 -0
- package/dist/slider.cjs +3 -3
- package/dist/slider.cjs.map +1 -1
- package/dist/slider.js +2 -2
- package/dist/slider.js.map +1 -1
- package/dist/{sound.service-kKfsN0m-.js → sound.service-BIN2W7Rv.js} +1 -1
- package/dist/{sound.service-kKfsN0m-.js.map → sound.service-BIN2W7Rv.js.map} +1 -1
- package/dist/{sound.service-BGs6m0Cm.cjs → sound.service-DyY78ukR.cjs} +1 -1
- package/dist/{sound.service-BGs6m0Cm.cjs.map → sound.service-DyY78ukR.cjs.map} +1 -1
- package/dist/{splash-screen-DtkjCJYo.js → splash-screen-BcjjJSlK.js} +2 -2
- package/dist/{splash-screen-DtkjCJYo.js.map → splash-screen-BcjjJSlK.js.map} +1 -1
- package/dist/{splash-screen-DlQUv-kV.cjs → splash-screen-Kr1sPtME.cjs} +2 -2
- package/dist/{splash-screen-DlQUv-kV.cjs.map → splash-screen-Kr1sPtME.cjs.map} +1 -1
- package/dist/splash-screen.cjs +1 -1
- package/dist/splash-screen.js +1 -1
- package/dist/{src-DEUjlTsX.cjs → src-BbMJeLk9.cjs} +11 -11
- package/dist/{src-DEUjlTsX.cjs.map → src-BbMJeLk9.cjs.map} +1 -1
- package/dist/{src-D6e0adHi.js → src-DCu_mEk4.js} +40 -40
- package/dist/{src-D6e0adHi.js.map → src-DCu_mEk4.js.map} +1 -1
- package/dist/state-avic94Ft.cjs +1 -0
- package/dist/{state-DNdCPITt.cjs.map → state-avic94Ft.cjs.map} +1 -1
- package/dist/{state-BusMG6sM.js → state-nm8yzMPp.js} +1 -2
- package/dist/{state-BusMG6sM.js.map → state-nm8yzMPp.js.map} +1 -1
- package/dist/state.cjs +1 -1
- package/dist/state.js +2 -2
- package/dist/steps.cjs +3 -3
- package/dist/steps.cjs.map +1 -1
- package/dist/steps.js +2 -2
- package/dist/steps.js.map +1 -1
- package/dist/{surface-A82O1kgu.js → surface-BtMMHKol.js} +2 -2
- package/dist/{surface-A82O1kgu.js.map → surface-BtMMHKol.js.map} +1 -1
- package/dist/surface-CgXeKdGL.cjs +7 -0
- package/dist/{surface-BpppoNXN.cjs.map → surface-CgXeKdGL.cjs.map} +1 -1
- package/dist/surface.cjs +1 -1
- package/dist/surface.js +1 -1
- package/dist/switch.cjs +3 -3
- package/dist/switch.cjs.map +1 -1
- package/dist/switch.js +27 -43
- package/dist/switch.js.map +1 -1
- package/dist/table.cjs +3 -3
- package/dist/table.cjs.map +1 -1
- package/dist/table.js +2 -2
- package/dist/table.js.map +1 -1
- package/dist/{tabs-cVHHd1dY.js → tabs-81ADWQqa.js} +2 -2
- package/dist/{tabs-cVHHd1dY.js.map → tabs-81ADWQqa.js.map} +1 -1
- package/dist/{tabs-TO3UiBsm.cjs → tabs-DnG3K0bu.cjs} +2 -2
- package/dist/{tabs-TO3UiBsm.cjs.map → tabs-DnG3K0bu.cjs.map} +1 -1
- package/dist/tabs.cjs +1 -1
- package/dist/tabs.js +1 -1
- package/dist/teleport.cjs +1 -1
- package/dist/teleport.js +1 -1
- package/dist/textarea-3mWewuAf.js +186 -0
- package/dist/textarea-3mWewuAf.js.map +1 -0
- package/dist/textarea-BenjiTXB.cjs +43 -0
- package/dist/textarea-BenjiTXB.cjs.map +1 -0
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.js +1 -1
- package/dist/{theme-CT408FqH.js → theme-CFPJW933.js} +9 -9
- package/dist/{theme-CT408FqH.js.map → theme-CFPJW933.js.map} +1 -1
- package/dist/theme-DNymrucy.cjs +181 -0
- package/dist/{theme-CpuF3D3q.cjs.map → theme-DNymrucy.cjs.map} +1 -1
- package/dist/{theme-button-pTb5-Wxx.js → theme-button-DC_shZ_7.js} +2 -2
- package/dist/{theme-button-pTb5-Wxx.js.map → theme-button-DC_shZ_7.js.map} +1 -1
- package/dist/theme-button-ENKa3TPT.cjs +8 -0
- package/dist/{theme-button-B6Xf-EiH.cjs.map → theme-button-ENKa3TPT.cjs.map} +1 -1
- package/dist/theme-button.cjs +1 -1
- package/dist/theme-button.js +1 -1
- package/dist/theme.cjs +1 -1
- package/dist/{theme.interface-B9TjbSBF.js.map → theme.interface-C2XNgsLB.js.map} +1 -1
- package/dist/{theme.interface-BujperTo.cjs.map → theme.interface-D4NeufQA.cjs.map} +1 -1
- package/dist/theme.js +4 -4
- package/dist/{theme.service-DIUo1mBP.js → theme.service-BOWIT_5k.js} +1 -1
- package/dist/{theme.service-DIUo1mBP.js.map → theme.service-BOWIT_5k.js.map} +1 -1
- package/dist/{theme.service-Cfk88qHK.cjs → theme.service-DkdH1t60.cjs} +1 -1
- package/dist/{theme.service-Cfk88qHK.cjs.map → theme.service-DkdH1t60.cjs.map} +1 -1
- package/dist/tooltip.js.map +1 -1
- package/dist/tree.cjs +2 -2
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.js +2 -2
- package/dist/tree.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/typewriter.cjs.map +1 -1
- package/dist/typewriter.js.map +1 -1
- package/dist/typography.cjs +2 -2
- package/dist/typography.cjs.map +1 -1
- package/dist/typography.js +2 -2
- package/dist/typography.js.map +1 -1
- package/dist/{utils-kND2Z9Xg.js → utils-Cj_nRRyx.js} +2 -2
- package/dist/{utils-kND2Z9Xg.js.map → utils-Cj_nRRyx.js.map} +1 -1
- package/dist/{utils-Dt5PpmaQ.cjs → utils-D2QUu4-g.cjs} +1 -1
- package/dist/{utils-Dt5PpmaQ.cjs.map → utils-D2QUu4-g.cjs.map} +1 -1
- package/dist/utils.cjs +1 -1
- package/dist/utils.js +4 -4
- package/dist/visually-hidden.cjs +2 -2
- package/dist/visually-hidden.cjs.map +1 -1
- package/dist/visually-hidden.js +2 -2
- package/dist/visually-hidden.js.map +1 -1
- package/dist/{window-CuBcOxbc.js → window-BTecgE_U.js} +7 -7
- package/dist/{window-CuBcOxbc.js.map → window-BTecgE_U.js.map} +1 -1
- package/dist/{window-CSKvv4Ts.cjs → window-DGydMS0g.cjs} +2 -2
- package/dist/{window-CSKvv4Ts.cjs.map → window-DGydMS0g.cjs.map} +1 -1
- package/dist/window.cjs +1 -1
- package/dist/window.js +1 -1
- package/package.json +1 -1
- package/skills/schmancy/SKILL.md +3 -0
- package/skills/schmancy/autocomplete.md +16 -3
- package/skills/schmancy/button.md +19 -0
- package/skills/schmancy/checkbox.md +19 -0
- package/skills/schmancy/date-range.md +19 -0
- package/skills/schmancy/form-ux-rules.md +55 -0
- package/skills/schmancy/form.md +121 -25
- package/skills/schmancy/input.md +19 -4
- package/skills/schmancy/range.md +15 -1
- package/skills/schmancy/select.md +13 -1
- package/skills/schmancy/switch.md +21 -2
- package/skills/schmancy/textarea.md +13 -0
- package/src/button/button.test.ts +122 -0
- package/src/button/button.ts +36 -0
- package/src/{autocomplete → form/fields/autocomplete}/autocomplete.ts +48 -75
- package/src/{checkbox → form/fields/checkbox}/checkbox.test.ts +1 -1
- package/src/form/fields/checkbox/checkbox.ts +126 -0
- package/src/form/fields/date-range/date-range.test.ts +102 -0
- package/src/{date-range → form/fields/date-range}/date-range.ts +90 -7
- package/src/form/fields/index.ts +9 -0
- package/src/form/fields/input/input.test.ts +201 -0
- package/src/{input → form/fields/input}/input.ts +153 -238
- package/src/{radio-group → form/fields/radio-group}/radio-button.ts +1 -1
- package/src/{radio-group → form/fields/radio-group}/radio-group.ts +1 -1
- package/src/form/fields/range/range.test.ts +90 -0
- package/src/{range → form/fields/range}/range.ts +34 -13
- package/src/{select → form/fields/select}/select.ts +77 -108
- package/src/{switch → form/fields/switch}/switch.test.ts +1 -1
- package/src/{switch → form/fields/switch}/switch.ts +71 -51
- package/src/form/fields/textarea/textarea.test.ts +54 -0
- package/src/{textarea → form/fields/textarea}/textarea.ts +33 -72
- package/src/form/form-state.ts +31 -0
- package/src/form/form-summary.test.ts +105 -0
- package/src/form/form-summary.ts +171 -0
- package/src/form/form.test.ts +218 -35
- package/src/form/form.ts +330 -99
- package/src/form/index.ts +3 -0
- package/src/index.ts +9 -9
- package/types/mixins/formField.mixin.d.ts +90 -0
- package/types/src/button/button.d.ts +9 -0
- package/types/src/button/button.test.d.ts +3 -0
- package/types/src/{autocomplete → form/fields/autocomplete}/autocomplete.d.ts +6 -15
- package/types/src/form/fields/checkbox/checkbox.d.ts +47 -0
- package/types/src/{date-range → form/fields/date-range}/date-range.d.ts +22 -4
- package/types/src/form/fields/date-range/date-range.test.d.ts +1 -0
- package/types/src/form/fields/index.d.ts +9 -0
- package/types/src/{input → form/fields/input}/input.d.ts +20 -45
- package/types/src/form/fields/input/input.test.d.ts +1 -0
- package/types/src/{radio-group → form/fields/radio-group}/radio-button.d.ts +1 -1
- package/types/src/{radio-group → form/fields/radio-group}/radio-group.d.ts +1 -1
- package/types/src/form/fields/range/range.d.ts +28 -0
- package/types/src/form/fields/range/range.test.d.ts +1 -0
- package/types/src/{select → form/fields/select}/select.d.ts +23 -24
- package/types/src/form/fields/switch/switch.d.ts +57 -0
- package/types/src/{textarea → form/fields/textarea}/textarea.d.ts +6 -39
- package/types/src/form/fields/textarea/textarea.test.d.ts +1 -0
- package/types/src/form/form-state.d.ts +22 -0
- package/types/src/form/form-summary.d.ts +42 -0
- package/types/src/form/form-summary.test.d.ts +4 -0
- package/types/src/form/form.d.ts +79 -34
- package/types/src/form/form.test.d.ts +2 -2
- package/types/src/form/index.d.ts +3 -0
- package/types/src/index.d.ts +9 -9
- package/dist/active-host-CcIa2tmW.cjs +0 -1
- package/dist/active-host-CvNYoprt.js +0 -57
- package/dist/autocomplete-DWSuwSRS.js.map +0 -1
- package/dist/autocomplete-iCJOia-q.cjs +0 -115
- package/dist/autocomplete-iCJOia-q.cjs.map +0 -1
- package/dist/checkbox-NNReP9s_.cjs.map +0 -1
- package/dist/date-range-CaOxwZDq.cjs +0 -131
- package/dist/date-range-CaOxwZDq.cjs.map +0 -1
- package/dist/date-range-CgNujP8r.js.map +0 -1
- package/dist/date-range-inline-D4IjOOO0.cjs +0 -43
- package/dist/decorate-23nYs4Le.js +0 -7
- package/dist/decorate-DpFmy0nm.cjs +0 -1
- package/dist/float-CKmd-0-t.cjs +0 -1
- package/dist/form-CFvwnfuJ.js +0 -68
- package/dist/form-CFvwnfuJ.js.map +0 -1
- package/dist/form-Ceijw1aA.cjs +0 -1
- package/dist/form-Ceijw1aA.cjs.map +0 -1
- package/dist/input-D95GjINh.js.map +0 -1
- package/dist/input-D9s4jDAb.cjs +0 -51
- package/dist/input-D9s4jDAb.cjs.map +0 -1
- package/dist/mixins-BV0w2yIE.js +0 -627
- package/dist/mixins-BV0w2yIE.js.map +0 -1
- package/dist/mixins-DvAYa-F7.cjs +0 -298
- package/dist/mixins-DvAYa-F7.cjs.map +0 -1
- package/dist/notification-BC9nG8Sr.cjs +0 -23
- package/dist/radio-group-ByMD6Lsj.cjs +0 -40
- package/dist/radio-group-ByMD6Lsj.cjs.map +0 -1
- package/dist/radio-group-CW8airhZ.js.map +0 -1
- package/dist/select-BdBThja4.cjs +0 -56
- package/dist/select-BdBThja4.cjs.map +0 -1
- package/dist/select-Dbn-CImU.js.map +0 -1
- package/dist/state-DNdCPITt.cjs +0 -1
- package/dist/surface-BpppoNXN.cjs +0 -7
- package/dist/textarea-B9dy-yec.js +0 -211
- package/dist/textarea-B9dy-yec.js.map +0 -1
- package/dist/textarea-DFY0Flgv.cjs +0 -39
- package/dist/textarea-DFY0Flgv.cjs.map +0 -1
- package/dist/theme-CpuF3D3q.cjs +0 -181
- package/dist/theme-button-B6Xf-EiH.cjs +0 -8
- package/src/checkbox/checkbox.ts +0 -162
- package/types/src/checkbox/checkbox.d.ts +0 -71
- package/types/src/range/range.d.ts +0 -25
- package/types/src/switch/switch.d.ts +0 -53
- /package/dist/{animation-CO_Csq84.cjs → animation-CCOIW4wJ.cjs} +0 -0
- /package/dist/{animation-BK-8BwY8.js → animation-DCznELuT.js} +0 -0
- /package/dist/{context-DJTJnSK4.js → context-6oXCZmZN.js} +0 -0
- /package/dist/{context-BpCETidA.cjs → context-CRZeiCqq.cjs} +0 -0
- /package/dist/{hashContent-Bobsobip.cjs → hashContent-Ck6laKlk.cjs} +0 -0
- /package/dist/{hashContent-BU6jl5ih.js → hashContent-dJrI-9sc.js} +0 -0
- /package/dist/{lazy-Dq9mRRjT.cjs → lazy-CayEFyC3.cjs} +0 -0
- /package/dist/{lazy-B0ia54tT.js → lazy-D-bO2r4m.js} +0 -0
- /package/dist/{overlay-stack-DCDS17uj.js → overlay-stack-BR4iYivO.js} +0 -0
- /package/dist/{overlay-stack-DPIe_aYv.cjs → overlay-stack-Dk0xETTy.cjs} +0 -0
- /package/dist/{reduced-motion-D-L12p7G.js → reduced-motion-D7LqTUMn.js} +0 -0
- /package/dist/{reduced-motion-Ds-HjMzn.cjs → reduced-motion-Dzfp_w5x.cjs} +0 -0
- /package/dist/{rxjs-utils-DCUHg_Ml.cjs → rxjs-utils-BKB2UM_j.cjs} +0 -0
- /package/dist/{rxjs-utils-CVeJQ9KG.js → rxjs-utils-Dv9T9IpA.js} +0 -0
- /package/dist/{search-BLCRsxIC.cjs → search-DPKoC-dT.cjs} +0 -0
- /package/dist/{search-BTz7-Rev.js → search-MvIBA93K.js} +0 -0
- /package/dist/{theme.interface-B9TjbSBF.js → theme.interface-C2XNgsLB.js} +0 -0
- /package/dist/{theme.interface-BujperTo.cjs → theme.interface-D4NeufQA.cjs} +0 -0
- /package/src/{autocomplete → form/fields/autocomplete}/autocomplete.scss +0 -0
- /package/src/{autocomplete → form/fields/autocomplete}/index.ts +0 -0
- /package/src/{checkbox → form/fields/checkbox}/index.ts +0 -0
- /package/src/{date-range → form/fields/date-range}/date-range-dialog.ts +0 -0
- /package/src/{date-range → form/fields/date-range}/date-range-helpers.ts +0 -0
- /package/src/{date-range → form/fields/date-range}/date-range-presets.ts +0 -0
- /package/src/{date-range → form/fields/date-range}/date-utils.ts +0 -0
- /package/src/{date-range → form/fields/date-range}/index.ts +0 -0
- /package/src/{input → form/fields/input}/index.ts +0 -0
- /package/src/{input → form/fields/input}/input.scss +0 -0
- /package/src/{radio-group → form/fields/radio-group}/index.ts +0 -0
- /package/src/{radio-group → form/fields/radio-group}/radio-group.scss +0 -0
- /package/src/{range → form/fields/range}/index.ts +0 -0
- /package/src/{select → form/fields/select}/index.ts +0 -0
- /package/src/{switch → form/fields/switch}/index.ts +0 -0
- /package/src/{textarea → form/fields/textarea}/index.ts +0 -0
- /package/src/{textarea → form/fields/textarea}/textarea.scss +0 -0
- /package/types/src/{autocomplete → form/fields/autocomplete}/index.d.ts +0 -0
- /package/types/src/{checkbox → form/fields/checkbox}/checkbox.test.d.ts +0 -0
- /package/types/src/{checkbox → form/fields/checkbox}/index.d.ts +0 -0
- /package/types/src/{date-range → form/fields/date-range}/date-range-dialog.d.ts +0 -0
- /package/types/src/{date-range → form/fields/date-range}/date-range-helpers.d.ts +0 -0
- /package/types/src/{date-range → form/fields/date-range}/date-range-presets.d.ts +0 -0
- /package/types/src/{date-range → form/fields/date-range}/date-utils.d.ts +0 -0
- /package/types/src/{date-range → form/fields/date-range}/index.d.ts +0 -0
- /package/types/src/{input → form/fields/input}/index.d.ts +0 -0
- /package/types/src/{radio-group → form/fields/radio-group}/index.d.ts +0 -0
- /package/types/src/{range → form/fields/range}/index.d.ts +0 -0
- /package/types/src/{select → form/fields/select}/index.d.ts +0 -0
- /package/types/src/{switch → form/fields/switch}/index.d.ts +0 -0
- /package/types/src/{switch → form/fields/switch}/switch.test.d.ts +0 -0
- /package/types/src/{textarea → form/fields/textarea}/index.d.ts +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require(`./chunk-CncqDLb2.cjs`);const e=require(`./mixins-
|
|
1
|
+
require(`./chunk-CncqDLb2.cjs`);const e=require(`./mixins-BOOu6q2n.cjs`),t=require(`./active-host-jH3iloCR.cjs`),n=require(`./animation-CCOIW4wJ.cjs`),r=require(`./reduced-motion-Dzfp_w5x.cjs`),i=require(`./cursor-glow-C8LgCxpI.cjs`),a=require(`./theme.service-DkdH1t60.cjs`),o=require(`./overlay-stack-Dk0xETTy.cjs`);let s=require(`rxjs`),c=require(`lit/directives/class-map.js`),l=require(`lit/directives/style-map.js`),u=require(`lit/decorators.js`),d=require(`lit`),f=require(`lit/directives/ref.js`);var p=`schmancy-window-`,m=`schmancy-float-`;function h(e,t){return!(e.left>=t.left+t.width||e.left+e.width<=t.left||e.top>=t.top+t.height||e.top+e.height<=t.top)}var g,_=class e{constructor(){this._state$=new s.BehaviorSubject({windows:new Map,focusedId:null,stackOrder:[]}),this.state$=this._state$.asObservable()}static getInstance(){return e.instance||=new e,e.instance}get windows(){return this._state$.value.windows}get focusedId(){return this._state$.value.focusedId}register(e,t,n){let r=this._state$.value;if(r.windows.has(e))return;let i={id:e,bounds:t,visualState:`normal`,zIndex:o.t.assignZIndex(e),open:!1,snapTarget:n},a=new Map(r.windows);a.set(e,i);let s=o.t.getStackOrder();this._state$.next({...r,windows:a,stackOrder:s})}unregister(e){let t=this._state$.value;if(!t.windows.has(e))return;o.t.releaseId(e);let n=new Map(t.windows);n.delete(e);let r=o.t.getStackOrder(),i=t.focusedId===e?null:t.focusedId;this._state$.next({...t,windows:n,stackOrder:r,focusedId:i})}updateBounds(e,t){this._updateRecord(e,{bounds:t})}updateVisualState(e,t){this._updateRecord(e,{visualState:t})}updateOpen(e,t){this._updateRecord(e,{open:t})}focus(e){let t=this._state$.value;if(!t.windows.has(e)||t.focusedId===e)return;let n=o.t.bringToFront(e),r=new Map(t.windows),i=r.get(e);i&&r.set(e,{...i,zIndex:n});let a=o.t.getStackOrder();this._state$.next({...t,windows:r,stackOrder:a,focusedId:e})}findOverlaps(e,t){let n=[];for(let[r,i]of this._state$.value.windows)r!==t&&h(e,i.bounds)&&n.push(i);return n}getNeighbors(e){let t=[];for(let[n,r]of this._state$.value.windows)n!==e&&t.push(r);return t}selectWindow(e){return this._state$.pipe((0,s.map)(t=>t.windows.get(e)),(0,s.distinctUntilChanged)())}selectFocused(){return this._state$.pipe((0,s.map)(e=>e.focusedId),(0,s.distinctUntilChanged)())}loadPosition(e){try{let t=localStorage.getItem(p+e)??localStorage.getItem(m+e);return t?JSON.parse(t):null}catch{return null}}savePosition(e,t){try{localStorage.setItem(p+e,JSON.stringify(t))}catch{}}clearPosition(e){try{localStorage.removeItem(p+e),localStorage.removeItem(m+e)}catch{}}_updateRecord(e,t){let n=this._state$.value,r=n.windows.get(e);if(!r)return;let i=new Map(n.windows);i.set(e,{...r,...t}),this._state$.next({...n,windows:i})}}.getInstance();function v(e,t,n){let r={...e};for(let e=0;e<10&&t.some(e=>{return t=r,n=e.bounds,!(t.left>=n.left+n.width||t.left+t.width<=n.left||t.top>=n.top+n.height||t.top+t.height<=n.top);var t,n});e++)r.left+=44,r.top+=44;return function(e,t){return{width:e.width,height:e.height,left:Math.max(0,Math.min(e.left,t.width-e.width)),top:Math.max(0,Math.min(e.top,t.height-e.height))}}(r,n)}var y=48,b=class extends e.c{static{g=this}constructor(...e){super(...e),this.id=`default`,this.lowered=!1,this.corner=`bottom-right`,this.resizable=!1,this.freePosition=!1,this.visualState=`normal`,this.minWidth=280,this.minHeight=200,this.open=!1,this._hasOpened=!1,this._focused=!1,this._position={x:16,y:16},this._currentCorner=`bottom-right`,this._appliedCorner=``,this._containerRef=(0,f.createRef)(),this._bodyRef=(0,f.createRef)(),this._headRef=(0,f.createRef)(),this._handleFocus=()=>_.focus(this.id),this._handleHeadKeydown=e=>{if(e.key===`Enter`||e.key===` `)return e.preventDefault(),void this.toggle();if(e.key===`ArrowUp`||e.key===`ArrowDown`||e.key===`ArrowLeft`||e.key===`ArrowRight`){e.preventDefault();let t=e.shiftKey?20:5,n=e.key===`ArrowRight`?t:e.key===`ArrowLeft`?-t:0,r=e.key===`ArrowDown`?t:e.key===`ArrowUp`?-t:0;this._position={x:this._position.x+n,y:this._position.y+r},this._applyContainerPosition(),this._savePosition()}}}static{this.styles=[d.css`
|
|
2
2
|
:host {
|
|
3
3
|
display: contents;
|
|
4
4
|
position: relative;
|
|
@@ -56,4 +56,4 @@ require(`./chunk-CncqDLb2.cjs`);const e=require(`./mixins-DvAYa-F7.cjs`),t=requi
|
|
|
56
56
|
</div>
|
|
57
57
|
</section>
|
|
58
58
|
</schmancy-surface>
|
|
59
|
-
`}};t.
|
|
59
|
+
`}};t.a([(0,u.property)({type:String})],b.prototype,`id`,void 0),t.a([(0,u.property)({type:String})],b.prototype,`expandedWidth`,void 0),t.a([(0,u.property)({type:String})],b.prototype,`expandedHeight`,void 0),t.a([(0,u.property)({type:Boolean,reflect:!0})],b.prototype,`lowered`,void 0),t.a([(0,u.property)({type:String})],b.prototype,`corner`,void 0),t.a([(0,u.property)({type:Boolean})],b.prototype,`resizable`,void 0),t.a([(0,u.property)({type:Boolean})],b.prototype,`freePosition`,void 0),t.a([(0,u.property)({type:String,reflect:!0})],b.prototype,`visualState`,void 0),t.a([(0,u.property)({type:Number})],b.prototype,`minWidth`,void 0),t.a([(0,u.property)({type:Number})],b.prototype,`minHeight`,void 0),t.a([(0,u.property)({type:Boolean,reflect:!0})],b.prototype,`open`,void 0),t.a([(0,u.state)()],b.prototype,`_hasOpened`,void 0),t.a([(0,u.state)()],b.prototype,`_focused`,void 0),t.a([(0,u.state)()],b.prototype,`_currentCorner`,void 0);var x=b=g=t.a([(0,u.customElement)(`schmancy-window`)],b);Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return x}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"window-CSKvv4Ts.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\t/** Whether this window is the focused window in the manager — drives visual ring */\n\t@state() private _focused = 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\twindowManager.selectFocused().pipe(\n\t\t\t\t\ttap(focusedId => {\n\t\t\t\t\t\tthis._focused = focusedId === this.id\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'ring-1': !this._focused,\n\t\t\t'ring-2': this._focused,\n\t\t\t'ring-primary-default/30': this._focused,\n\t\t\t'ring-primary-default/15': this.open && !this._focused,\n\t\t\t'rounded-2xl': this.open,\n\t\t\t'ring-outline-variant/40': !this.open && !this._focused,\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-DGydMS0g.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\t/** Whether this window is the focused window in the manager — drives visual ring */\n\t@state() private _focused = 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\twindowManager.selectFocused().pipe(\n\t\t\t\t\ttap(focusedId => {\n\t\t\t\t\t\tthis._focused = focusedId === this.id\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'ring-1': !this._focused,\n\t\t\t'ring-2': this._focused,\n\t\t\t'ring-primary-default/30': this._focused,\n\t\t\t'ring-primary-default/15': this.open && !this._focused,\n\t\t\t'rounded-2xl': this.open,\n\t\t\t'ring-outline-variant/40': !this.open && !this._focused,\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-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./window-DGydMS0g.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-
|
|
1
|
+
import { n as e, t } from "./window-BTecgE_U.js";
|
|
2
2
|
export { t as SchmancyWindow, e as windowManager };
|
package/package.json
CHANGED
package/skills/schmancy/SKILL.md
CHANGED
|
@@ -57,6 +57,9 @@ Use component tags (`<schmancy-menu>`, `<schmancy-dropdown>`, `<schmancy-tooltip
|
|
|
57
57
|
- **Schmancy primitive first** (`PRIMITIVE_FIRST`). Within `web/**`, every visible UI element is a custom element exported from `packages/schmancy/src/**`, and an element absent from that export set is added there before being imported into `web/**`. The rule sits above the styling rules: a `<div class="text-xs text-surface-on-variant">…</div>` whose role is typography is a violation even when every utility resolves to a registered token, because `<schmancy-typography>` already covers that role; the styling rules apply only to whatever class strings remain after the right primitive has been selected.
|
|
58
58
|
Sources: [packages/schmancy/skills/schmancy/INDEX.md](../INDEX.md) catalogues the export set by job (foundations / atoms / forms / navigation / overlays / interaction / feedback / display); each role's reference file (`typography.md`, `surface.md`, `button.md`, `overlay.md`, …) names the props, slots, and events that displace the equivalent `<div>` + utility-class pattern. The export set is the single source — a primitive that is not exported from `packages/schmancy/src/**` does not satisfy this rule even if it lives in a private file inside the schmancy tree.
|
|
59
59
|
Remediation: walk every `.ts` and `.html` file under `web/**` and list every raw HTML element whose class string carries design-system styling (typography, color, spacing-as-design-decision, surface, layout-as-design-decision, motion, overlay) — those are the violations. For each, look up the matching schmancy primitive in `INDEX.md` and rewrite the element through that primitive (`<schmancy-typography type=… token=…>` for type-scale text, `<schmancy-surface type=… fill=…>` for elevated/bounded surfaces, `<schmancy-grid>`/`<schmancy-flex>` for layout primitives with design intent, the imperative `show`/`$notify`/`schmancyContentDrawer.push` services for overlays, `<schmancy-scroll>` for scroll containers). When a needed primitive is absent from the export set, design and implement it as a new component under `packages/schmancy/src/<role>/` — extending `SchmancyElement` with `static styles = [css\`...\`]`, registered in `HTMLElementTagNameMap`, exported through the package barrel, and documented with a sibling `.md` in the skill's reference set — and only then introduce the first call site in `web/**`. The audit subagent iterates the whole `web/**` tree, surfaces the violation list, applies the rewrites, runs `yarn workspace @momo/web tsc --noEmit` plus the colocated `*-view.test.ts` suites, and reports pre-existing violations that require a new schmancy primitive as a separate punch list for designer/architect approval before the implementation lands. The loop exits when every `web/**` file's visible UI elements are schmancy primitives and the typecheck plus the test suites pass.
|
|
60
|
+
- **Module index re-exports the subpath surface** (`MODULE_INDEX_REEXPORTS_SUBPATH`). Each schmancy module exposed through the package's `./*` subpath export resolves to `src/<name>/index.ts`, and any other source file under `src/<name>/` is visible to consumers only through symbols that index re-exports.
|
|
61
|
+
Sources: the `exports` field in [packages/schmancy/package.json](../../package.json) maps the `./*` subpath to `./dist/*.js` and the matching `./types/src/*/index.d.ts` types entry, so the only declaration a consumer reaches for `import … from '@mhmo91/schmancy/<name>'` is the one emitted from `src/<name>/index.ts`. Files placed in subdirectories of that module are bundled into the same dist output, but they cross the package boundary only through symbols re-exported up the chain into the module index. Past incident: `packages/schmancy/src/form/index.ts` exposed only `form`, `form-state`, and `form-summary`; consumers importing field types like `SchmancyInput` and `SchmancyFormSubmitDetail` from `@mhmo91/schmancy/form` saw nothing because `form/fields/*` had no path into the module index.
|
|
62
|
+
Remediation: list every direct subdirectory of `packages/schmancy/src/<name>/` that owns its own `index.ts` with component exports, and for each one verify that `packages/schmancy/src/<name>/index.ts` carries an `export * from './<subdir>'` (directly, or via a grouping barrel such as `<subdir>/index.ts` re-exported by the module index). The audit subagent runs `ls -d packages/schmancy/src/<name>/*/` for every module under `./*`, greps each subdirectory's `index.ts` for `^export`, then greps the module's `index.ts` for `export \* from './<subdir>'` (or for an intermediate barrel that re-exports it), and lists every subdirectory that fails the second grep as a violation. The fix per violation is one line in the module's `index.ts`; when a module groups several subdirectories under one role (e.g. `form/fields/*`), the loop also adds an intermediate `<subdir>/index.ts` barrel and re-exports that single barrel from the module index rather than enumerating leaves. The loop exits when every direct subdirectory's symbols round-trip through the module index and `yarn workspace @momo/web tsc --noEmit` passes against the consumers that import from `@mhmo91/schmancy/<name>`.
|
|
60
63
|
|
|
61
64
|
## Non-negotiable conventions
|
|
62
65
|
|
|
@@ -20,13 +20,18 @@
|
|
|
20
20
|
| name | string | `''` | Form submission name |
|
|
21
21
|
| required | boolean | `false` | Whether selection is required |
|
|
22
22
|
| multi | boolean | `false` | Enable multi-select with inline chips |
|
|
23
|
-
| size | `'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Input height |
|
|
23
|
+
| size | `'xxs'\|'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Input height (M3 sizes 24–56dp). |
|
|
24
24
|
| maxHeight | string | `'300px'` | Max dropdown height |
|
|
25
25
|
| debounceMs | number | `200` | Search debounce in ms |
|
|
26
26
|
| similarityThreshold | number | `0.3` | Minimum fuzzy match score (0-1) |
|
|
27
|
-
| error | boolean | `false` | Error state |
|
|
28
|
-
| validationMessage | string | `''` | Validation message |
|
|
27
|
+
| error | boolean | `false` | Error state (gated by `validateOn`). From `SchmancyFormField`. |
|
|
28
|
+
| validationMessage | string | `''` | Validation message. |
|
|
29
29
|
| description | string | `''` | Screen reader description |
|
|
30
|
+
| validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When validation errors display. |
|
|
31
|
+
| disabled | boolean | `false` | Disabled state. |
|
|
32
|
+
| hint | string | `undefined` | Helper text below the field. |
|
|
33
|
+
| touched / dirty / submitted | boolean | — | Validation state from `SchmancyFormField`. |
|
|
34
|
+
| autocomplete | string | `'off'` | Native autocomplete attribute on inner input. |
|
|
30
35
|
|
|
31
36
|
## Events
|
|
32
37
|
| Event | Detail | Description |
|
|
@@ -51,3 +56,11 @@
|
|
|
51
56
|
```
|
|
52
57
|
|
|
53
58
|
Children must be `<schmancy-option>` elements. In multi mode, selected items appear as removable chips.
|
|
59
|
+
|
|
60
|
+
## Form-field contract
|
|
61
|
+
|
|
62
|
+
Extends `SchmancyFormField()`. Auto-discovered by `<schmancy-form>` via `FIELD_CONNECT_EVENT`. Public API: `markTouched()`, `markSubmitted()`, `checkValidity()`, `reportValidity()`, `setCustomValidity()`, `resetForm()` (resets the BehaviorSubjects + clears the input).
|
|
63
|
+
|
|
64
|
+
Default `validateOn: 'dirty'` — a required-empty autocomplete shows no error until the user types-then-clears or submits. Error UI rendered in a `role="alert"` div linked via `aria-describedby`.
|
|
65
|
+
|
|
66
|
+
See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
|
|
@@ -40,6 +40,25 @@
|
|
|
40
40
|
- Hover: luminous glow shadow using primary color
|
|
41
41
|
- Active: spring press `scale(0.97)` / `scale(0.92)` for icon-button
|
|
42
42
|
|
|
43
|
+
## Submit-state mirroring (`type="submit"` only)
|
|
44
|
+
|
|
45
|
+
A `<schmancy-button type="submit">` inside a `<schmancy-form>` automatically reflects the form's submit state via a MutationObserver on the form's `aria-busy` attribute:
|
|
46
|
+
|
|
47
|
+
- While the form's `formSubmitState.status === 'submitting'` (form sets `aria-busy="true"`):
|
|
48
|
+
- Button mirrors `aria-busy="true"` onto itself.
|
|
49
|
+
- Broadcasts `:state(submitting)` for CSS targeting.
|
|
50
|
+
- **Stays focusable** — never gets the `disabled` attribute. Disabled buttons drop from the tab order; AT users would lose their place. WCAG 2.2 AA.
|
|
51
|
+
- Cleared automatically when the form's submit promise settles (success or error).
|
|
52
|
+
|
|
53
|
+
```css
|
|
54
|
+
schmancy-button:state(submitting) {
|
|
55
|
+
opacity: 0.6;
|
|
56
|
+
/* show a spinner via ::before, swap label, etc. */
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`schmancy-button` is form-associated (`static formAssociated = true` + `attachInternals()`) — clicking a `type="submit"` inside any `<form>` ancestor (native or schmancy) calls `form.requestSubmit()`. Inside `<schmancy-form>` the click is also intercepted at the form host and bridged across the shadow boundary to the inner shadow-DOM `<form>`.
|
|
61
|
+
|
|
43
62
|
## Examples
|
|
44
63
|
```html
|
|
45
64
|
<!-- Filled primary -->
|
|
@@ -18,6 +18,14 @@
|
|
|
18
18
|
| disabled | boolean | `false` | Whether the checkbox is disabled |
|
|
19
19
|
| required | boolean | `false` | Whether the checkbox is required |
|
|
20
20
|
| size | `'xxs'\|'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Checkbox size |
|
|
21
|
+
| validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When validation errors display. From `SchmancyFormField`. |
|
|
22
|
+
| validationMessage | string | `''` | Error text — default `'Please check this box if you want to proceed.'` when required and unchecked. |
|
|
23
|
+
| error | boolean | `false` | Error state (gated by `validateOn`). |
|
|
24
|
+
| hint | string | `undefined` | Helper text. |
|
|
25
|
+
| touched / dirty / submitted | boolean | — | Validation state from `SchmancyFormField`. |
|
|
26
|
+
|
|
27
|
+
## Attributes
|
|
28
|
+
- `true-value` — string written to FormData when checked. Default `'on'` (matches native checkbox semantics).
|
|
21
29
|
|
|
22
30
|
## Events
|
|
23
31
|
| Event | Detail | Description |
|
|
@@ -33,4 +41,15 @@
|
|
|
33
41
|
<schmancy-checkbox name="terms" required>
|
|
34
42
|
Accept <a href="/terms">terms and conditions</a>
|
|
35
43
|
</schmancy-checkbox>
|
|
44
|
+
|
|
45
|
+
<!-- Custom FormData string -->
|
|
46
|
+
<schmancy-checkbox name="newsletter" true-value="opt-in"></schmancy-checkbox>
|
|
36
47
|
```
|
|
48
|
+
|
|
49
|
+
## Form-field contract
|
|
50
|
+
|
|
51
|
+
Extends `SchmancyFormField()`. `value` is the boolean state; FormData submission uses the `true-value` attribute (or `'on'`). Validity overrides the mixin's "non-empty value" semantics: required + unchecked → `internals.setValidity({ valueMissing: true })`. ARIA `aria-invalid` / `aria-required` reflect through `ElementInternals`.
|
|
52
|
+
|
|
53
|
+
Public API: `markTouched()`, `markSubmitted()`, `checkValidity()`, `setCustomValidity()`, `resetForm()`. Auto-discovered by `<schmancy-form>` via `FIELD_CONNECT_EVENT`.
|
|
54
|
+
|
|
55
|
+
See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
|
|
@@ -27,6 +27,12 @@
|
|
|
27
27
|
| collapse | boolean | `false` | Icon-only on mobile |
|
|
28
28
|
| customPresets | array | `[]` | Additional preset ranges |
|
|
29
29
|
| format | string | auto | Date format string |
|
|
30
|
+
| name | string | `''` | Form submission name. From `SchmancyFormField`. |
|
|
31
|
+
| validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When validation errors display. |
|
|
32
|
+
| validationMessage | string | `''` | Error message — default `'Please select a date range.'` when required and either bound is empty. |
|
|
33
|
+
| error | boolean | `false` | Error state (gated by `validateOn`). |
|
|
34
|
+
| hint | string | `undefined` | Helper text. |
|
|
35
|
+
| touched / dirty / submitted | boolean | — | Validation state. `dirty` tracks `dateFrom.value` / `dateTo.value` against the snapshots taken at first render. |
|
|
30
36
|
|
|
31
37
|
## Events
|
|
32
38
|
| Event | Detail | Description |
|
|
@@ -48,3 +54,16 @@
|
|
|
48
54
|
```
|
|
49
55
|
|
|
50
56
|
Built-in presets include Today, Yesterday, This Week, This Month, This Year, and more.
|
|
57
|
+
|
|
58
|
+
## Form association
|
|
59
|
+
|
|
60
|
+
Extends `SchmancyFormField()`. Multi-entry FormData contribution:
|
|
61
|
+
- Set `name="dates"` and FormData receives **two** keys: `datesFrom` and `datesTo` (flat suffix shape, no bracket-key encoding).
|
|
62
|
+
- `internals.setFormValue(formData)` accepts a `FormData` object whose entries get appended to the parent form — native `new FormData(form)` sees both keys without consumer-side parsing.
|
|
63
|
+
- `<schmancy-form>`'s registry consumer also sees both keys via `toFormEntries()`.
|
|
64
|
+
|
|
65
|
+
`resetForm()` restores both `dateFrom.value` and `dateTo.value` to the snapshots captured at first render. Validity: required + either bound empty → `internals.setValidity({ valueMissing: true })`. Order/range constraints (start ≤ end, future-only, etc.) are out of scope — handle those in a domain schema layer.
|
|
66
|
+
|
|
67
|
+
Auto-discovered by `<schmancy-form>` via `FIELD_CONNECT_EVENT`. Public API: `markTouched()`, `markSubmitted()`, `checkValidity()`, `setCustomValidity()`, `resetForm()`.
|
|
68
|
+
|
|
69
|
+
See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Form UX rules — Revolute pattern → schmancy mixin API
|
|
2
|
+
|
|
3
|
+
This is the mapping between the Revolute interview-bar form UX (the source-of-truth checklist for state-of-the-art form behaviour) and the `SchmancyFormField()` API that implements each rule. When you hit a UX question, find the rule here and use the named API — don't re-derive from scratch.
|
|
4
|
+
|
|
5
|
+
## The four-phase validation contract
|
|
6
|
+
|
|
7
|
+
| Phase | UX rule | Implementation |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| 1 — Pristine | A field the user hasn't typed in shows no error, even if focused-then-blurred. The autofocus+cancel anti-pattern (focus a required field, click cancel, see "required") is forbidden. | `validateOn: 'dirty'` (default). `_shouldShowError()` returns `false` while `dirty === false`. |
|
|
10
|
+
| 2 — Dirty | User types and blurs → validate the field. Show error only if invalid. Empty required fields blurred-without-typing remain pristine. | `markTouched()` called on blur. Mixin's `willUpdate` sees `touched` change, sees `dirty` is true, calls `checkValidity()` which sets `this.error` because the gate is open. |
|
|
11
|
+
| 3 — Live correction | User returns to a field with an error → re-validate on every keystroke. Error clears immediately when valid. | Mixin's `willUpdate` re-runs `checkValidity()` on every value change while `_shouldShowError()` is true. |
|
|
12
|
+
| 4 — Submit | Submit click → validate **all** fields regardless of dirty. Focus the first invalid field. | `<schmancy-form>` calls `markSubmitted()` on every registered field. `submitted = true` overrides every `validateOn` mode and forces error display. The form then focuses the first field with `error === true`. |
|
|
13
|
+
|
|
14
|
+
After Phase 4, the field stays in Phase 3 (live re-validation) for the rest of the session because `submitted` persists until `resetForm()`.
|
|
15
|
+
|
|
16
|
+
## Per-rule cross-reference
|
|
17
|
+
|
|
18
|
+
| UX rule | API | Notes |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Default mode is "errors after the user has interacted" | `validateOn: 'dirty'` | Pristine fields stay clean; submit forces all errors. |
|
|
21
|
+
| Live search shows errors immediately | `validateOn="always"` | Bypass the dirty/touched gate entirely. |
|
|
22
|
+
| Wizard step holds errors until Next | `validateOn="submitted"` | Only `markSubmitted()` opens the gate. |
|
|
23
|
+
| Server-side error → specific field | `form.setFieldError(name, msg)` | RHF `setError` parity. Sets custom validity + marks submitted so the error shows. |
|
|
24
|
+
| Server-side error → form banner | `form.setFormError(msg, code?)` | Flips `formSubmitState` to `{ status: 'error', error: { message, code } }`. Top-of-form banners read this. |
|
|
25
|
+
| Async server-side check gating submit | `e.detail.until(promise)` | Form's `submit` event detail. Submit status reflects the promise outcome (`success` on resolve, `error` on reject). |
|
|
26
|
+
| Submit button must stay focusable while busy | `aria-busy="true"` on the host (auto) + `:state(submitting)` on `<schmancy-button[type=submit]>` (auto) | WCAG 2.2 AA. Disabled buttons drop from the tab order; we never disable. |
|
|
27
|
+
| Screen reader announces invalid fields | `internals.ariaInvalid` (auto) + `internals.ariaRequired` (auto) | Reflected through `ElementInternals` so AT reaches into shadow DOM. Not on the host as `aria-*` attributes. |
|
|
28
|
+
| Reset returns the form to pristine | `<schmancy-button type="reset">` or `form.reset()` | Mixin's `formResetCallback` → `resetForm()` clears `value`, `error`, `validationMessage`, `touched`, `submitted`. |
|
|
29
|
+
| Cross-field rules (password confirm) | `schema` prop with zod `.refine` | Validation seam is the schema, not the mixin. Cross-field violations surface on submit; map to a specific field via `form.setFieldError`. |
|
|
30
|
+
| Server-shape transforms (IBAN uppercase, trim) | `schema` prop with zod `.transform` | Runs during `schema.parse(rawFormData)` in `_onSubmit`. The `data` in the submit event is post-transform. |
|
|
31
|
+
| Multi-entry FormData (date range, tag input) | Override `toFormEntries()` + `internals.setFormValue(formData)` | Flat suffix keys (`${name}From`, `${name}To`) — no bracket-key encoding. Native `new FormData(form)` sees both keys. |
|
|
32
|
+
| Boolean state semantics (checkbox, switch) | Override `checkValidity()` | Required validity is `checked === true`, not the mixin's "non-empty value." |
|
|
33
|
+
| Numeric value (range) | `override value: number` | Narrows the mixin's wide union. Mixin's `dirty` getter uses `value !== _defaultValue` which works for primitives. |
|
|
34
|
+
| Two independent forms on one page | Each `<schmancy-form>` is its own context provider | `<schmancy-context .provides=${[formSubmitState]}>` is rendered inside each form. Submit state is isolated per instance — no cross-contamination. |
|
|
35
|
+
| Nested forms forbidden | `<schmancy-form>` `connectedCallback` checks for an ancestor `schmancy-form` and `console.error`s if found | Nested forms are platform-undefined; we surface the error early. |
|
|
36
|
+
|
|
37
|
+
## What's NOT in scope
|
|
38
|
+
|
|
39
|
+
These are deferred to v2 and **not** in the current contract:
|
|
40
|
+
|
|
41
|
+
- `<schmancy-form-summary>` (top-of-form error banner with anchor links to invalid fields).
|
|
42
|
+
- `validateOn: 'length'` (validate once `value.length === maxlength` — Stripe card-number pattern).
|
|
43
|
+
- Per-field `errorMessages` i18n hook (the default `'This field is required'` is hardcoded English).
|
|
44
|
+
- First-class `useFieldArray` API for dynamic fields.
|
|
45
|
+
- Async-validation helpers (`isValidating`, `runAsyncValidator`, `:state(validating)`).
|
|
46
|
+
- Wizard `clearSubmitted()` (post-submit state currently persists until `resetForm`).
|
|
47
|
+
- Structured `ValidityStateFlags` exposure beyond `valueMissing` + `customError`.
|
|
48
|
+
|
|
49
|
+
If a consumer needs one of these, file an issue with the use case before adding it — every addition to the binding contract has a propagation cost across all 9 form components.
|
|
50
|
+
|
|
51
|
+
## See also
|
|
52
|
+
|
|
53
|
+
- `form.md` — the `<schmancy-form>` API reference.
|
|
54
|
+
- `mixins.md` — `SchmancyFormField()` factory composition.
|
|
55
|
+
- `state.md` — `formSubmitState` singleton + per-form isolation.
|