@mhmo91/schmancy 0.10.17 → 0.10.18
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/dist/agent/schmancy.agent.js +22 -96
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/{area-ChxsDTu_.js → area-BIipuSyO.js} +1 -1
- package/dist/{area-ChxsDTu_.js.map → area-BIipuSyO.js.map} +1 -1
- package/dist/{area-Qt6yUnuA.cjs → area-C-EMiNEE.cjs} +1 -1
- package/dist/{area-Qt6yUnuA.cjs.map → area-C-EMiNEE.cjs.map} +1 -1
- package/dist/area.cjs +1 -1
- package/dist/area.js +1 -1
- package/dist/{autocomplete-Ck2zbdF9.cjs → autocomplete-B8CE5vGw.cjs} +1 -1
- package/dist/{autocomplete-Ck2zbdF9.cjs.map → autocomplete-B8CE5vGw.cjs.map} +1 -1
- package/dist/{autocomplete-CXvUjMD-.js → autocomplete-Mrb3koUN.js} +2 -2
- package/dist/{autocomplete-CXvUjMD-.js.map → autocomplete-Mrb3koUN.js.map} +1 -1
- package/dist/autocomplete.cjs +1 -1
- package/dist/autocomplete.js +1 -1
- package/dist/avatar.cjs +1 -1
- package/dist/avatar.js +1 -1
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/{boat-DpFkILFF.cjs → boat-DN1_tyvx.cjs} +2 -2
- package/dist/{boat-DpFkILFF.cjs.map → boat-DN1_tyvx.cjs.map} +1 -1
- package/dist/{boat-Bj0wVcZi.js → boat-cuoSkhGI.js} +1 -4
- package/dist/{boat-Bj0wVcZi.js.map → boat-cuoSkhGI.js.map} +1 -1
- package/dist/boat.cjs +1 -1
- package/dist/boat.js +1 -1
- package/dist/breadcrumb.cjs +2 -1
- package/dist/breadcrumb.cjs.map +1 -1
- package/dist/breadcrumb.js +2 -1
- package/dist/breadcrumb.js.map +1 -1
- package/dist/{busy-CtcnclA3.cjs → busy-CMKX4oQf.cjs} +1 -1
- package/dist/{busy-CtcnclA3.cjs.map → busy-CMKX4oQf.cjs.map} +1 -1
- package/dist/{busy-CyZSBnZP.js → busy-Cetzws-m.js} +1 -1
- package/dist/{busy-CyZSBnZP.js.map → busy-Cetzws-m.js.map} +1 -1
- package/dist/busy.cjs +1 -1
- package/dist/busy.js +1 -1
- package/dist/button.cjs +4 -3
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +4 -3
- package/dist/button.js.map +1 -1
- package/dist/{card-Cl6jp1yX.cjs → card-8VXoo2C_.cjs} +1 -1
- package/dist/{card-Cl6jp1yX.cjs.map → card-8VXoo2C_.cjs.map} +1 -1
- package/dist/{card-nYZCKmOO.js → card-D2k3dRL0.js} +1 -1
- package/dist/{card-nYZCKmOO.js.map → card-D2k3dRL0.js.map} +1 -1
- package/dist/card.cjs +1 -1
- package/dist/card.js +1 -1
- package/dist/{checkbox-DiUrZiyc.js → checkbox-8hNsBejz.js} +1 -1
- package/dist/{checkbox-DiUrZiyc.js.map → checkbox-8hNsBejz.js.map} +1 -1
- package/dist/{checkbox-BeNo0ZGt.cjs → checkbox-Cq5wzeaY.cjs} +1 -1
- package/dist/{checkbox-BeNo0ZGt.cjs.map → checkbox-Cq5wzeaY.cjs.map} +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/{chips-DK6m-VCM.cjs → chips-DSdvCpmi.cjs} +9 -18
- package/dist/chips-DSdvCpmi.cjs.map +1 -0
- package/dist/{chips-CfPFXv7Z.js → chips-m2NPN480.js} +8 -22
- package/dist/chips-m2NPN480.js.map +1 -0
- package/dist/chips.cjs +1 -1
- package/dist/chips.js +2 -2
- package/dist/connectivity.cjs +1 -1
- package/dist/connectivity.js +1 -1
- package/dist/content-drawer.cjs +1 -1
- package/dist/content-drawer.js +1 -1
- package/dist/{date-range-DjlF2u7o.js → date-range-D98QcCHl.js} +2 -2
- package/dist/{date-range-DjlF2u7o.js.map → date-range-D98QcCHl.js.map} +1 -1
- package/dist/{date-range-DA6anfcF.cjs → date-range-DxS3Agbj.cjs} +1 -1
- package/dist/{date-range-DA6anfcF.cjs.map → date-range-DxS3Agbj.cjs.map} +1 -1
- package/dist/{date-range-inline-BfYK795W.cjs → date-range-inline-Bvs2ZvEY.cjs} +1 -1
- package/dist/{date-range-inline-BfYK795W.cjs.map → date-range-inline-Bvs2ZvEY.cjs.map} +1 -1
- package/dist/{date-range-inline-n7y_H6PJ.js → date-range-inline-TWWnTZlw.js} +1 -1
- package/dist/{date-range-inline-n7y_H6PJ.js.map → date-range-inline-TWWnTZlw.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 +1 -1
- package/dist/delay.js +1 -1
- package/dist/{details-CS_ToAOj.js → details-Cpg8sH2F.js} +3 -8
- package/dist/details-Cpg8sH2F.js.map +1 -0
- package/dist/{details-BdAVsLl-.cjs → details-CwSDur6j.cjs} +2 -6
- package/dist/details-CwSDur6j.cjs.map +1 -0
- package/dist/details.cjs +1 -1
- package/dist/details.js +1 -1
- package/dist/{divider-CvWAnvdO.cjs → divider-BNdVLE0H.cjs} +1 -1
- package/dist/{divider-CvWAnvdO.cjs.map → divider-BNdVLE0H.cjs.map} +1 -1
- package/dist/{divider-COLK0RbT.js → divider-Be833gGZ.js} +1 -1
- package/dist/{divider-COLK0RbT.js.map → divider-Be833gGZ.js.map} +1 -1
- package/dist/divider.cjs +1 -1
- package/dist/divider.js +1 -1
- package/dist/dropdown.cjs +1 -1
- package/dist/dropdown.js +1 -1
- package/dist/{expand-r2sATPUJ.cjs → expand-BP6RLzHw.cjs} +1 -1
- package/dist/{expand-r2sATPUJ.cjs.map → expand-BP6RLzHw.cjs.map} +1 -1
- package/dist/{expand-D9LzmpoV.js → expand-CtoffNNj.js} +2 -2
- package/dist/{expand-D9LzmpoV.js.map → expand-CtoffNNj.js.map} +1 -1
- package/dist/expand.cjs +1 -1
- package/dist/expand.js +1 -1
- package/dist/{float-2nHYuBx-.cjs → float-B8NcSE3a.cjs} +1 -1
- package/dist/{float-2nHYuBx-.cjs.map → float-B8NcSE3a.cjs.map} +1 -1
- package/dist/{float-BWy39CXr.js → float-C-glc-3u.js} +1 -1
- package/dist/{float-BWy39CXr.js.map → float-C-glc-3u.js.map} +1 -1
- package/dist/float.cjs +1 -1
- package/dist/float.js +1 -1
- package/dist/{form-D1iJOLVb.js → form-DJvxIyfW.js} +8 -8
- package/dist/{form-D1iJOLVb.js.map → form-DJvxIyfW.js.map} +1 -1
- package/dist/{form-D9K1GhlP.cjs → form-St_IwR7y.cjs} +1 -1
- package/dist/{form-D9K1GhlP.cjs.map → form-St_IwR7y.cjs.map} +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.js +6 -6
- package/dist/handover/agent-runtime-followups.md +1 -1
- package/dist/handover/agent-runtime-v1.md +3 -3
- package/dist/{icons-BXp4vbnW.cjs → icons-BJld4JHp.cjs} +1 -1
- package/dist/{icons-BXp4vbnW.cjs.map → icons-BJld4JHp.cjs.map} +1 -1
- package/dist/{icons-COrlmBPB.js → icons-D7df1ysG.js} +1 -1
- package/dist/{icons-COrlmBPB.js.map → icons-D7df1ysG.js.map} +1 -1
- package/dist/icons.cjs +1 -1
- package/dist/icons.js +1 -1
- package/dist/{iframe-CPNsIy7k.js → iframe-DAbgW9tT.js} +1 -1
- package/dist/{iframe-CPNsIy7k.js.map → iframe-DAbgW9tT.js.map} +1 -1
- package/dist/{iframe-BwXj6mLp.cjs → iframe-GT6D8l5Z.cjs} +1 -1
- package/dist/{iframe-BwXj6mLp.cjs.map → iframe-GT6D8l5Z.cjs.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 +24 -24
- package/dist/{input-BGrF2qVq.cjs → input-BE9wEEw4.cjs} +1 -1
- package/dist/{input-BGrF2qVq.cjs.map → input-BE9wEEw4.cjs.map} +1 -1
- package/dist/{input-C1SnMNuQ.js → input-DC6ap_uN.js} +1 -1
- package/dist/{input-C1SnMNuQ.js.map → input-DC6ap_uN.js.map} +1 -1
- package/dist/{input-chip-DZktYohr.cjs → input-chip-MsiMu-b5.cjs} +4 -4
- package/dist/input-chip-MsiMu-b5.cjs.map +1 -0
- package/dist/{input-chip-CtQ0pH5b.js → input-chip-c5n547tg.js} +3 -6
- package/dist/input-chip-c5n547tg.js.map +1 -0
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/json.cjs +1 -1
- package/dist/json.js +2 -2
- package/dist/kbd.cjs +1 -1
- package/dist/kbd.js +1 -1
- package/dist/layout.cjs +1 -1
- package/dist/layout.js +1 -1
- package/dist/{lightbox-CLwpaiai.js → lightbox-CNX9Eg3U.js} +4 -4
- package/dist/lightbox-CNX9Eg3U.js.map +1 -0
- package/dist/{lightbox-Ck6BpN5u.cjs → lightbox-HqJBBjAT.cjs} +4 -4
- package/dist/lightbox-HqJBBjAT.cjs.map +1 -0
- package/dist/lightbox.cjs +1 -1
- package/dist/lightbox.js +1 -1
- package/dist/{list-Bmce1Rb8.js → list-C76Pb-c1.js} +1 -1
- package/dist/{list-Bmce1Rb8.js.map → list-C76Pb-c1.js.map} +1 -1
- package/dist/{list-EmRwSpTU.cjs → list-bhyuQSyO.cjs} +1 -1
- package/dist/{list-EmRwSpTU.cjs.map → list-bhyuQSyO.cjs.map} +1 -1
- package/dist/list.cjs +1 -1
- package/dist/list.js +1 -1
- package/dist/{menu-BA_B7QOG.js → menu-B_-weNpZ.js} +2 -2
- package/dist/{menu-BA_B7QOG.js.map → menu-B_-weNpZ.js.map} +1 -1
- package/dist/{menu-BTU3wGP6.cjs → menu-Dag0cuWV.cjs} +1 -1
- package/dist/{menu-BTU3wGP6.cjs.map → menu-Dag0cuWV.cjs.map} +1 -1
- package/dist/menu.cjs +1 -1
- package/dist/menu.js +1 -1
- package/dist/mixins-DCVXqL1Q.js +636 -0
- package/dist/{mixins-BWb9_e1s.js.map → mixins-DCVXqL1Q.js.map} +1 -1
- package/dist/mixins-Du9HMrIG.cjs +254 -0
- package/dist/{mixins-BOOu6q2n.cjs.map → mixins-Du9HMrIG.cjs.map} +1 -1
- package/dist/mixins.cjs +1 -1
- package/dist/mixins.js +1 -1
- 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 +1 -1
- package/dist/navigation-rail.js +1 -1
- package/dist/{notification-R2_Mf1HR.js → notification-DySnvQeO.js} +3 -3
- package/dist/notification-DySnvQeO.js.map +1 -0
- package/dist/{notification-CliGbcfU.cjs → notification-yd2KeHjd.cjs} +1 -1
- package/dist/notification-yd2KeHjd.cjs.map +1 -0
- package/dist/notification.cjs +1 -1
- package/dist/notification.js +1 -1
- package/dist/{option-Db98Ndzv.cjs → option-BDOKUqTy.cjs} +1 -1
- package/dist/{option-Db98Ndzv.cjs.map → option-BDOKUqTy.cjs.map} +1 -1
- package/dist/{option-DU1X4SDu.js → option-CBEHYG4U.js} +1 -1
- package/dist/{option-DU1X4SDu.js.map → option-CBEHYG4U.js.map} +1 -1
- package/dist/option.cjs +1 -1
- package/dist/option.js +1 -1
- package/dist/overlay.cjs +1 -1
- package/dist/{overlay.confirm-body-uFp-0Zfh.js → overlay.confirm-body-DESGpbru.js} +2 -2
- package/dist/{overlay.confirm-body-uFp-0Zfh.js.map → overlay.confirm-body-DESGpbru.js.map} +1 -1
- package/dist/{overlay.confirm-body-BkhNvr0c.cjs → overlay.confirm-body-sUmd_zVy.cjs} +2 -2
- package/dist/{overlay.confirm-body-BkhNvr0c.cjs.map → overlay.confirm-body-sUmd_zVy.cjs.map} +1 -1
- package/dist/overlay.js +3 -3
- package/dist/{overlay.service-1YWfUD2S.cjs → overlay.service-BxtEFFSH.cjs} +1 -1
- package/dist/{overlay.service-1YWfUD2S.cjs.map → overlay.service-BxtEFFSH.cjs.map} +1 -1
- package/dist/{overlay.service-BcF12kGb.js → overlay.service-DV_o_xQ0.js} +2 -2
- package/dist/{overlay.service-BcF12kGb.js.map → overlay.service-DV_o_xQ0.js.map} +1 -1
- package/dist/page.cjs +1 -1
- package/dist/page.js +2 -2
- package/dist/{progress-C9Y2D5cm.js → progress-C4kDZfb7.js} +1 -1
- package/dist/{progress-C9Y2D5cm.js.map → progress-C4kDZfb7.js.map} +1 -1
- package/dist/{progress-DiVTGAXa.cjs → progress-CMSst_2U.cjs} +1 -1
- package/dist/{progress-DiVTGAXa.cjs.map → progress-CMSst_2U.cjs.map} +1 -1
- package/dist/progress.cjs +1 -1
- package/dist/progress.js +1 -1
- package/dist/{radio-group-CAzjBI2n.js → radio-group-DB9D2ZkA.js} +1 -1
- package/dist/{radio-group-CAzjBI2n.js.map → radio-group-DB9D2ZkA.js.map} +1 -1
- package/dist/{radio-group-DIRJyYv6.cjs → radio-group-dVUvYFq7.cjs} +1 -1
- package/dist/{radio-group-DIRJyYv6.cjs.map → radio-group-dVUvYFq7.cjs.map} +1 -1
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/range.cjs +1 -1
- package/dist/range.js +1 -1
- package/dist/{scroll-BFHUtZOa.js → scroll-C1klVgSQ.js} +1 -1
- package/dist/{scroll-BFHUtZOa.js.map → scroll-C1klVgSQ.js.map} +1 -1
- package/dist/{scroll-nIZyoEMt.cjs → scroll-S-bXF2u6.cjs} +1 -1
- package/dist/{scroll-nIZyoEMt.cjs.map → scroll-S-bXF2u6.cjs.map} +1 -1
- package/dist/{select-7WqaUWBU.js → select-UU2pB67h.js} +1 -1
- package/dist/{select-7WqaUWBU.js.map → select-UU2pB67h.js.map} +1 -1
- package/dist/{select-DTuf6p6T.cjs → select-fu_-rZyn.cjs} +1 -1
- package/dist/{select-DTuf6p6T.cjs.map → select-fu_-rZyn.cjs.map} +1 -1
- package/dist/select.cjs +1 -1
- package/dist/select.js +1 -1
- package/dist/skeleton.cjs +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/slider.cjs +1 -1
- package/dist/slider.js +1 -1
- package/dist/{splash-screen-Kr1sPtME.cjs → splash-screen-25PTDqnp.cjs} +1 -1
- package/dist/{splash-screen-Kr1sPtME.cjs.map → splash-screen-25PTDqnp.cjs.map} +1 -1
- package/dist/{splash-screen-BcjjJSlK.js → splash-screen-bGW_sS4i.js} +1 -1
- package/dist/{splash-screen-BcjjJSlK.js.map → splash-screen-bGW_sS4i.js.map} +1 -1
- package/dist/splash-screen.cjs +1 -1
- package/dist/splash-screen.js +1 -1
- package/dist/{src-BbMJeLk9.cjs → src-Blm9PNcf.cjs} +1 -1
- package/dist/{src-BbMJeLk9.cjs.map → src-Blm9PNcf.cjs.map} +1 -1
- package/dist/{src-DCu_mEk4.js → src-olrlFt4e.js} +31 -31
- package/dist/{src-DCu_mEk4.js.map → src-olrlFt4e.js.map} +1 -1
- package/dist/steps.cjs +1 -1
- package/dist/steps.js +1 -1
- package/dist/{surface-BtMMHKol.js → surface-DCRy-EyT.js} +1 -1
- package/dist/{surface-BtMMHKol.js.map → surface-DCRy-EyT.js.map} +1 -1
- package/dist/{surface-CgXeKdGL.cjs → surface-DWwQDX9r.cjs} +1 -1
- package/dist/{surface-CgXeKdGL.cjs.map → surface-DWwQDX9r.cjs.map} +1 -1
- package/dist/surface.cjs +1 -1
- package/dist/surface.js +1 -1
- package/dist/switch.cjs +1 -1
- package/dist/switch.js +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.js +1 -1
- package/dist/{tabs-81ADWQqa.js → tabs-BVC_qn8S.js} +1 -1
- package/dist/{tabs-81ADWQqa.js.map → tabs-BVC_qn8S.js.map} +1 -1
- package/dist/{tabs-DnG3K0bu.cjs → tabs-Dc3_Ox2B.cjs} +1 -1
- package/dist/{tabs-DnG3K0bu.cjs.map → tabs-Dc3_Ox2B.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-BenjiTXB.cjs → textarea-CNa4dSvF.cjs} +1 -1
- package/dist/{textarea-BenjiTXB.cjs.map → textarea-CNa4dSvF.cjs.map} +1 -1
- package/dist/{textarea-3mWewuAf.js → textarea-DkfGmRSI.js} +1 -1
- package/dist/{textarea-3mWewuAf.js.map → textarea-DkfGmRSI.js.map} +1 -1
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.js +1 -1
- package/dist/{theme-CFPJW933.js → theme-BiCwFfCf.js} +1 -1
- package/dist/{theme-CFPJW933.js.map → theme-BiCwFfCf.js.map} +1 -1
- package/dist/{theme-DNymrucy.cjs → theme-DCybsrfv.cjs} +1 -1
- package/dist/{theme-DNymrucy.cjs.map → theme-DCybsrfv.cjs.map} +1 -1
- package/dist/{theme-button-DC_shZ_7.js → theme-button-DqiA0rJg.js} +1 -1
- package/dist/{theme-button-DC_shZ_7.js.map → theme-button-DqiA0rJg.js.map} +1 -1
- package/dist/{theme-button-ENKa3TPT.cjs → theme-button-cZGRyQRK.cjs} +1 -1
- package/dist/{theme-button-ENKa3TPT.cjs.map → theme-button-cZGRyQRK.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.js +2 -2
- package/dist/tree.cjs +1 -1
- package/dist/tree.js +1 -1
- package/dist/typography.cjs +1 -1
- package/dist/typography.js +1 -1
- package/dist/visually-hidden.cjs +1 -1
- package/dist/visually-hidden.js +1 -1
- package/dist/{window-DGydMS0g.cjs → window-BMecbTzs.cjs} +3 -3
- package/dist/window-BMecbTzs.cjs.map +1 -0
- package/dist/{window-BTecgE_U.js → window-DMy5Gsgu.js} +3 -10
- package/dist/window-DMy5Gsgu.js.map +1 -0
- package/dist/window.cjs +1 -1
- package/dist/window.js +1 -1
- package/package.json +1 -1
- package/src/boat/boat.ts +0 -3
- package/src/breadcrumb/breadcrumb.ts +1 -0
- package/src/button/button.ts +1 -1
- package/src/button/icon-button.ts +2 -1
- package/src/chips/assist-chip.ts +2 -1
- package/src/chips/filter-chip.ts +2 -16
- package/src/chips/input-chip.ts +2 -5
- package/src/chips/suggestion-chip.ts +2 -3
- package/src/details/details.ts +2 -7
- package/src/lightbox/lightbox.ts +3 -3
- package/src/notification/notification.scss +0 -1
- package/src/overlay/overlay.confirm-body.ts +1 -1
- package/src/surface/surface.styles.ts +1 -45
- package/src/window/window.ts +0 -12
- package/types/src/window/window.d.ts +0 -2
- package/dist/chips-CfPFXv7Z.js.map +0 -1
- package/dist/chips-DK6m-VCM.cjs.map +0 -1
- package/dist/details-BdAVsLl-.cjs.map +0 -1
- package/dist/details-CS_ToAOj.js.map +0 -1
- package/dist/input-chip-CtQ0pH5b.js.map +0 -1
- package/dist/input-chip-DZktYohr.cjs.map +0 -1
- package/dist/lightbox-CLwpaiai.js.map +0 -1
- package/dist/lightbox-Ck6BpN5u.cjs.map +0 -1
- package/dist/mixins-BOOu6q2n.cjs +0 -298
- package/dist/mixins-BWb9_e1s.js +0 -680
- package/dist/notification-CliGbcfU.cjs.map +0 -1
- package/dist/notification-R2_Mf1HR.js.map +0 -1
- package/dist/window-BTecgE_U.js.map +0 -1
- package/dist/window-DGydMS0g.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"notification-CliGbcfU.cjs","names":[],"sources":["../src/notification/notification.scss?inline","../src/notification/notification.ts","../src/notification/notification-service.ts","../src/notification/notify.ts"],"sourcesContent":[":host {\n\tdisplay: block;\n}\n\n.notification {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 12px;\n\tpadding-right: 32px;\n\tbackground: var(--schmancy-sys-color-surface-container);\n\tborder-radius: var(--schmancy-sys-shape-corner-extraLarge, 16px);\n\tcolor: var(--schmancy-sys-color-surface-on);\n\tmax-width: 320px;\n\toverflow: hidden;\n\n\t/* Type-colored luminous glow */\n\t--notification-glow-color: var(--schmancy-sys-color-primary-default);\n\tbox-shadow: 0 4px 24px -6px color-mix(in srgb, var(--notification-glow-color) 18%, transparent);\n\tborder-left: 2px solid color-mix(in srgb, var(--notification-glow-color) 50%, transparent);\n\n\ttransition:\n\t\tbox-shadow 300ms ease,\n\t\ttransform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);\n\n\t&.info { --notification-glow-color: var(--schmancy-sys-color-primary-default); }\n\t&.success { --notification-glow-color: var(--schmancy-sys-color-success-default); }\n\t&.warning { --notification-glow-color: var(--schmancy-sys-color-warning-default); }\n\t&.error { --notification-glow-color: var(--schmancy-sys-color-error-default); }\n\n\t&.hovered {\n\t\tbox-shadow: 0 8px 32px -4px color-mix(in srgb, var(--notification-glow-color) 28%, transparent);\n\t\ttransform: translateY(-2px);\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\ttransition: box-shadow 200ms ease;\n\t\t&.hovered { transform: none; }\n\t}\n}\n\n.emoji {\n\tfont-size: 20px;\n\tline-height: 1;\n\tflex-shrink: 0;\n\tmargin-top: 1px;\n}\n\n.content {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.title {\n\tfont-weight: 500;\n\tfont-size: 13px;\n\tline-height: 1.4;\n\tmargin-bottom: 2px;\n\tletter-spacing: 0.01em;\n\n\t.info & {\n\t\tcolor: var(--schmancy-sys-color-primary-default);\n\t}\n\t.success & {\n\t\tcolor: var(--schmancy-sys-color-success-default);\n\t}\n\t.warning & {\n\t\tcolor: var(--schmancy-sys-color-tertiary-default);\n\t}\n\t.error & {\n\t\tcolor: var(--schmancy-sys-color-error-default);\n\t}\n}\n\n.message {\n\tfont-size: 13px;\n\tline-height: 1.4;\n\topacity: 0.75;\n\tletter-spacing: 0.01em;\n}\n\n.close {\n\tposition: absolute;\n\ttop: 8px;\n\tright: 6px;\n\tbackground: none;\n\tborder: none;\n\tfont-size: 16px;\n\tfont-weight: 300;\n\tcolor: var(--schmancy-sys-color-surface-onVariant);\n\tcursor: pointer;\n\tpadding: 4px 6px;\n\tline-height: 1;\n\topacity: 0.4;\n\tborder-radius: var(--schmancy-sys-shape-corner-full, 50%);\n\ttransition: opacity 200ms ease;\n\n\t&:hover {\n\t\topacity: 0.8;\n\t}\n\n\t&:focus-visible {\n\t\toutline: none;\n\t\topacity: 1;\n\t\tbox-shadow:\n\t\t\t0 0 0 2px var(--schmancy-sys-color-primary-default),\n\t\t\t0 0 8px -2px color-mix(in srgb, var(--schmancy-sys-color-primary-default) 25%, transparent);\n\t}\n}\n\n.progress {\n\tposition: absolute;\n\tbottom: 0;\n\tleft: 0;\n\tright: 0;\n}\n","import { SchmancyElement } from '@mixins/index'\nimport { html, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { BehaviorSubject, timer, interval, NEVER } from 'rxjs'\nimport { switchMap, takeUntil, map, tap, distinctUntilChanged } from 'rxjs/operators'\nimport '../progress/progress'\nimport style from './notification.scss?inline'\n\nexport type NotificationType = 'info' | 'success' | 'warning' | 'error'\n\n/**\n * Calculate a point on an arc between two points\n */\nfunction calculateArcPoint(\n\tstart: { x: number; y: number },\n\tend: { x: number; y: number },\n\tarcDirection: 'up' | 'down' = 'up',\n\tintensity: number = 0.3,\n): { x: number; y: number } {\n\tconst midX = (start.x + end.x) / 2\n\tconst midY = (start.y + end.y) / 2\n\tconst distance = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2))\n\tconst arcHeight = Math.min(distance * intensity, 150)\n\treturn {\n\t\tx: midX,\n\t\ty: arcDirection === 'up' ? midY - arcHeight : midY + arcHeight,\n\t}\n}\n\n/**\n * @fires close - When notification is closed\n */\n@customElement('sch-notification')\nexport default class SchmancyNotification extends SchmancyElement {\n\tstatic styles = [unsafeCSS(style)];\n\n\t@property({ type: String }) title = ''\n\t@property({ type: String }) message = ''\n\t@property({ type: String }) type: NotificationType = 'info'\n\t@property({ type: Boolean }) closable = true\n\t@property({ type: Number }) duration = 5000 // 0 means no auto-close\n\t@property({ type: String }) id = `notification-${Date.now()}-${Math.floor(Math.random() * 10000)}`\n\t@property({ type: Boolean }) playSound = true\n\t@property({ type: Boolean }) showProgress = false // Show indeterminate progress bar\n\t@property({ type: Object }) startPosition: { x: number; y: number } = { x: 0, y: 0 }\n\n\t@state() private _visible = true\n\t@state() private _progress = 100\n\t@state() private _hovered = false\n\t@state() private _closing = false\n\n\tprivate paused$ = new BehaviorSubject<boolean>(false)\n\tprivate startTime = 0\n\tprivate pausedAt = 0\n\tprivate elapsedBeforePause = 0\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\t// Set fixed positioning for blackbird animation\n\t\tthis.style.position = 'fixed'\n\t\tthis.style.top = '16px'\n\t\tthis.style.right = '16px'\n\t\tthis.style.zIndex = '10001'\n\t\tthis.style.opacity = '0'\n\n\t\t// Animate in after first render\n\t\tthis.updateComplete.then(() => {\n\t\t\tthis.animateIn()\n\t\t\treturn\n\t\t})\n\n\t\tif (this.duration > 0) {\n\t\t\tthis.setupAutoClose()\n\t\t\tthis.setupProgressUpdates()\n\t\t}\n\n\t\tif (this.playSound) {\n\t\t\tthis._playSound()\n\t\t}\n\t}\n\n\tprivate async animateIn() {\n\t\t// Get the notification element's final position\n\t\tconst rect = this.getBoundingClientRect()\n\t\tconst targetX = rect.left + rect.width / 2\n\t\tconst targetY = rect.top + rect.height / 2\n\n\t\t// Calculate arc point for upward arc\n\t\tconst arcPoint = calculateArcPoint(this.startPosition, { x: targetX, y: targetY }, 'up', 0.3)\n\n\t\t// Animate from click position to final position with arc\n\t\tawait this.animate(\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\ttransform: `translate(${this.startPosition.x - targetX}px, ${this.startPosition.y - targetY}px) scale(0.1)`,\n\t\t\t\t\topacity: 0,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttransform: `translate(${arcPoint.x - targetX}px, ${arcPoint.y - targetY}px) scale(0.6)`,\n\t\t\t\t\topacity: 0.9,\n\t\t\t\t\toffset: 0.5,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttransform: 'translate(0, 0) scale(1)',\n\t\t\t\t\topacity: 1,\n\t\t\t\t},\n\t\t\t],\n\t\t\t{\n\t\t\t\tduration: 400,\n\t\t\t\teasing: 'cubic-bezier(0.34, 1.2, 0.64, 1)',\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t).finished\n\t}\n\n\tprivate setupAutoClose() {\n\t\tif (this.duration <= 0) return\n\n\t\tthis.startTime = Date.now()\n\t\tthis.elapsedBeforePause = 0\n\n\t\tthis.paused$\n\t\t\t.pipe(\n\t\t\t\tswitchMap(paused => {\n\t\t\t\t\tif (paused) {\n\t\t\t\t\t\tthis.pausedAt = Date.now()\n\t\t\t\t\t\tthis.elapsedBeforePause += this.pausedAt - this.startTime\n\t\t\t\t\t\treturn NEVER\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.startTime = Date.now()\n\t\t\t\t\t\tconst remaining = this.duration - this.elapsedBeforePause\n\t\t\t\t\t\tif (remaining <= 0) {\n\t\t\t\t\t\t\tthis.close()\n\t\t\t\t\t\t\treturn NEVER\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn timer(remaining)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\ttakeUntil(this.disconnecting),\n\t\t\t)\n\t\t\t.subscribe(() => this.close())\n\t}\n\n\tprivate setupProgressUpdates() {\n\t\tif (this.duration <= 0) return\n\n\t\tinterval(16)\n\t\t\t.pipe(\n\t\t\t\tswitchMap(() =>\n\t\t\t\t\tthis.paused$.pipe(\n\t\t\t\t\t\tmap(paused => {\n\t\t\t\t\t\t\tif (paused) return this._progress\n\t\t\t\t\t\t\tconst elapsed = this.elapsedBeforePause + (Date.now() - this.startTime)\n\t\t\t\t\t\t\tconst remaining = Math.max(0, this.duration - elapsed)\n\t\t\t\t\t\t\treturn (remaining / this.duration) * 100\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t\ttap(progress => {\n\t\t\t\t\tthis._progress = progress\n\t\t\t\t}),\n\t\t\t\ttakeUntil(this.disconnecting),\n\t\t\t)\n\t\t\t.subscribe()\n\t}\n\n\tprivate _playSound() {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('playsound', {\n\t\t\t\tdetail: { type: this.type },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate _handleMouseEnter() {\n\t\tthis._hovered = true\n\t\tthis.paused$.next(true)\n\t}\n\n\tprivate _handleMouseLeave() {\n\t\tthis._hovered = false\n\t\tthis.paused$.next(false)\n\t}\n\n\tpublic async close() {\n\t\tif (this._closing) return\n\t\tthis._closing = true\n\t\tthis._visible = false\n\n\t\t// Animate out before dispatching close event\n\t\tawait this.animate(\n\t\t\t[\n\t\t\t\t{ transform: 'translate(0, 0) scale(1)', opacity: 1 },\n\t\t\t\t{ transform: 'translate(0, -20px) scale(0.8)', opacity: 0 },\n\t\t\t],\n\t\t\t{\n\t\t\t\tduration: 200,\n\t\t\t\teasing: 'cubic-bezier(0.4, 0, 1, 1)',\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t).finished\n\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('close', {\n\t\t\t\tdetail: { id: this.id },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate _getEmoji(): string {\n\t\tswitch (this.type) {\n\t\t\tcase 'success':\n\t\t\t\treturn '\\u2705'\n\t\t\tcase 'warning':\n\t\t\t\treturn '\\u26A0\\uFE0F'\n\t\t\tcase 'error':\n\t\t\t\treturn '\\u274C'\n\t\t\tdefault:\n\t\t\t\treturn '\\u{1F4A1}'\n\t\t}\n\t}\n\n\trender() {\n\t\tif (!this._visible && this._closing) return html``\n\n\t\treturn html`\n\t\t\t<div\n\t\t\t\tclass=\"notification ${this.type} ${this._closing ? 'closing' : ''} ${this._hovered ? 'hovered' : ''}\"\n\t\t\t\trole=\"alert\"\n\t\t\t\t@mouseenter=${this._handleMouseEnter}\n\t\t\t\t@mouseleave=${this._handleMouseLeave}\n\t\t\t>\n\t\t\t\t<span class=\"emoji\">${this._getEmoji()}</span>\n\t\t\t\t<div class=\"content\">\n\t\t\t\t\t${this.title ? html`<div class=\"title\">${this.title}</div>` : ''}\n\t\t\t\t\t<div class=\"message\">${this.message}</div>\n\t\t\t\t</div>\n\t\t\t\t${this.closable\n\t\t\t\t\t? html`\n\t\t\t\t\t\t\t<button class=\"close\" aria-label=\"Close notification\" @click=${this.close}>x</button>\n\t\t\t\t\t\t`\n\t\t\t\t\t: ''}\n\t\t\t\t${this.showProgress || this.duration > 0\n\t\t\t\t\t? html`<schmancy-progress\n\t\t\t\t\t\tclass=\"progress\"\n\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\t.value=${this._progress}\n\t\t\t\t\t\t?indeterminate=${this.showProgress && this.duration === 0}\n\t\t\t\t\t></schmancy-progress>`\n\t\t\t\t\t: ''}\n\t\t\t</div>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sch-notification': SchmancyNotification\n\t}\n}\n","import { $sounds, type Feeling } from '../audio'\nimport SchmancyNotification, { NotificationType } from './notification'\n\nexport interface NotificationOptions {\n\tid?: string\n\ttitle?: string\n\tmessage: string\n\ttype?: NotificationType\n\tduration?: number\n\tclosable?: boolean\n\tplaySound?: boolean\n\tshowProgress?: boolean\n}\n\nconst typeToFeeling: Record<NotificationType, Feeling> = {\n\tinfo: 'curious',\n\tsuccess: 'content',\n\twarning: 'anxious',\n\terror: 'disappointed',\n}\n\n// Track last mouse position\nlet lastClickPosition = { x: window.innerWidth - 100, y: 50 }\n\n// Global mousedown listener to track click position\nif (typeof window !== 'undefined') {\n\twindow.addEventListener(\n\t\t'mousedown',\n\t\t(e: MouseEvent) => {\n\t\t\tlastClickPosition = { x: e.clientX, y: e.clientY }\n\t\t},\n\t\t{ capture: true, passive: true },\n\t)\n}\n\n// Track current notification element\nlet currentNotification: SchmancyNotification | null = null\n\n/**\n * Notification service for centralized notification management.\n * Provides a simple API for showing notifications.\n */\nexport class NotificationService {\n\tprivate static instance: NotificationService\n\tprivate notificationStack: string[] = []\n\tprivate audioVolume = 0.1\n\n\t// Default notification options\n\tprivate static DEFAULT_OPTIONS: Partial<NotificationOptions> = {\n\t\tduration: 1000, // 1 seconds - long enough to be readable\n\t\tclosable: true,\n\t\tplaySound: true,\n\t}\n\n\t// Type-specific default durations (in milliseconds)\n\tprivate static TYPE_DURATIONS: Record<NotificationType, number> = {\n\t\tsuccess: 1500, // 1.5 seconds - quick confirmation\n\t\tinfo: 2000, // 2 seconds - informational\n\t\twarning: 2500, // 2.5 seconds - needs attention\n\t\terror: 2500, // 2.5 seconds - important\n\t}\n\n\t// Private constructor for singleton pattern\n\tprivate constructor() {\n\t\t$sounds.setVolume(this.audioVolume)\n\t}\n\n\t/**\n\t * Get the singleton instance\n\t */\n\tpublic static getInstance(): NotificationService {\n\t\tif (!NotificationService.instance) {\n\t\t\tNotificationService.instance = new NotificationService()\n\t\t}\n\t\treturn NotificationService.instance\n\t}\n\n\t/**\n\t * Show a notification\n\t * @returns The ID of the created notification\n\t */\n\tpublic notify(options: NotificationOptions): string {\n\t\t// Apply default options\n\t\tconst completeOptions = {\n\t\t\t...NotificationService.DEFAULT_OPTIONS,\n\t\t\t...options,\n\t\t\t// Override with duraton from options if provided, otherwise use default\n\t\t\tduration: options.duration ?? NotificationService.DEFAULT_OPTIONS.duration,\n\t\t}\n\n\t\tconst id = completeOptions.id || `notification-${Date.now()}-${Math.floor(Math.random() * 10000)}`\n\n\t\t// Add to stack for tracking\n\t\tthis.notificationStack.push(id)\n\n\t\t// Remove existing notification if any (only 1 at a time)\n\t\tif (currentNotification) {\n\t\t\tcurrentNotification.remove()\n\t\t\tcurrentNotification = null\n\t\t}\n\n\t\t// Create the notification element directly\n\t\tconst notification = document.createElement('sch-notification') as SchmancyNotification\n\t\tnotification.id = id\n\t\tnotification.title = completeOptions.title || ''\n\t\tnotification.message = completeOptions.message\n\t\tnotification.type = completeOptions.type || 'info'\n\t\tnotification.duration = completeOptions.duration ?? 1000\n\t\tnotification.closable = completeOptions.closable !== false\n\t\tnotification.playSound = false // We handle sound here\n\t\tnotification.showProgress = completeOptions.showProgress || false\n\t\tnotification.startPosition = { ...lastClickPosition }\n\n\t\t// Play sound if enabled\n\t\tif (completeOptions.playSound !== false) {\n\t\t\t$sounds.play(typeToFeeling[notification.type])\n\t\t}\n\n\t\t// Listen for close event\n\t\tnotification.addEventListener('close', () => {\n\t\t\tconst index = this.notificationStack.indexOf(id)\n\t\t\tif (index > -1) {\n\t\t\t\tthis.notificationStack.splice(index, 1)\n\t\t\t}\n\t\t\tnotification.remove()\n\t\t\tif (currentNotification === notification) {\n\t\t\t\tcurrentNotification = null\n\t\t\t}\n\t\t})\n\n\t\t// Append to body\n\t\tdocument.body.appendChild(notification)\n\t\tcurrentNotification = notification\n\n\t\treturn id\n\t}\n\n\t/**\n\t * Dismiss a notification\n\t * @param id Optional notification ID. If not provided, dismisses the most recent notification\n\t */\n\tpublic dismiss(id?: string): void {\n\t\tlet targetId: string | undefined\n\n\t\tif (id) {\n\t\t\t// Remove specific notification from stack\n\t\t\tconst index = this.notificationStack.indexOf(id)\n\t\t\tif (index > -1) {\n\t\t\t\tthis.notificationStack.splice(index, 1)\n\t\t\t\ttargetId = id\n\t\t\t}\n\t\t} else {\n\t\t\t// Remove most recent notification (last in stack)\n\t\t\ttargetId = this.notificationStack.pop()\n\t\t}\n\n\t\tif (targetId && currentNotification && currentNotification.id === targetId) {\n\t\t\tcurrentNotification.close()\n\t\t}\n\t}\n\n\t/**\n\t * Update a notification's content\n\t */\n\tpublic update(id: string, options: Partial<NotificationOptions>): void {\n\t\tif (currentNotification && currentNotification.id === id) {\n\t\t\tif (options.title !== undefined) currentNotification.title = options.title\n\t\t\tif (options.message !== undefined) currentNotification.message = options.message\n\t\t\tif (options.type !== undefined) currentNotification.type = options.type\n\t\t}\n\t}\n\n\t/**\n\t * Show an info notification\n\t */\n\tpublic info(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'info',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.info) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a success notification\n\t */\n\tpublic success(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'success',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.success) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a warning notification\n\t */\n\tpublic warning(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'warning',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.warning) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show an error notification\n\t */\n\tpublic error(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'error',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.error) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a notification with a custom duration\n\t */\n\tpublic customDuration(\n\t\tmessage: string,\n\t\tduration: number,\n\t\toptions: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {},\n\t): string {\n\t\treturn this.notify({\n\t\t\tmessage,\n\t\t\tduration,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a persistent notification (won't auto-dismiss)\n\t */\n\tpublic persistent(message: string, options: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage,\n\t\t\tduration: 0, // Zero duration means no auto-close\n\t\t\t...options,\n\t\t})\n\t}\n}\n\n/**\n * Global notification (toast) utility. Fire-and-forget API for success,\n * error, info, and warning toasts, plus a low-level `show` for custom\n * notifications.\n *\n * @service\n * @summary Toast notifications — success, error, info, warning.\n * @method show(options: NotificationOptions) - Low-level; show any NotificationOptions.\n * @method success(message, options?) - Green success toast.\n * @method error(message, options?) - Red error toast.\n * @method info(message, options?) - Blue informational toast.\n * @method warning(message, options?) - Amber warning toast.\n */\nexport const $notify = {\n\t/**\n\t * Show a notification\n\t */\n\tshow: (options: NotificationOptions): string => {\n\t\treturn NotificationService.getInstance().notify(options)\n\t},\n\n\t/**\n\t * Show an info notification\n\t */\n\tinfo: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().info(message, options)\n\t},\n\n\t/**\n\t * Show a success notification\n\t */\n\tsuccess: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().success(message, options)\n\t},\n\n\t/**\n\t * Show a warning notification\n\t */\n\twarning: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().warning(message, options)\n\t},\n\n\t/**\n\t * Show an error notification\n\t */\n\terror: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().error(message, options)\n\t},\n\n\t/**\n\t * Show a notification with a custom duration\n\t * @param message The notification message\n\t * @param duration Duration in milliseconds before auto-dismissing (0 for no auto-dismiss)\n\t * @param options Additional notification options\n\t */\n\tcustomDuration: (\n\t\tmessage: string,\n\t\tduration: number,\n\t\toptions: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {},\n\t): string => {\n\t\treturn NotificationService.getInstance().customDuration(message, duration, options)\n\t},\n\n\t/**\n\t * Show a persistent notification that won't auto-dismiss\n\t */\n\tpersistent: (message: string, options: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {}): string => {\n\t\treturn NotificationService.getInstance().persistent(message, options)\n\t},\n\n\t/**\n\t * Dismiss a notification\n\t * @param id Optional notification ID. If not provided, dismisses the most recent notification (queue-like behavior)\n\t */\n\tdismiss: (id?: string): void => {\n\t\treturn NotificationService.getInstance().dismiss(id)\n\t},\n\n\t/**\n\t * Update a notification's content\n\t */\n\tupdate: (id: string, options: Partial<NotificationOptions>): void => {\n\t\treturn NotificationService.getInstance().update(id, options)\n\t},\n}\n","import { Observable, tap, finalize, catchError } from 'rxjs'\r\nimport { $notify, NotificationOptions } from './notification-service'\r\n\r\nexport interface NotifyOptions {\r\n\t/**\r\n\t * Message to show while the operation is in progress\r\n\t */\r\n\tloadingMessage?: string\r\n\t/**\r\n\t * Message to show when the operation completes successfully\r\n\t */\r\n\tsuccessMessage?: string\r\n\t/**\r\n\t * Message to show when the operation fails (can be a function to format error)\r\n\t */\r\n\terrorMessage?: string | ((error: any) => string)\r\n\t/**\r\n\t * Type of notification for loading state\r\n\t */\r\n\tloadingType?: NotificationOptions['type']\r\n\t/**\r\n\t * Type of notification for success state\r\n\t */\r\n\tsuccessType?: NotificationOptions['type']\r\n\t/**\r\n\t * Type of notification for error state\r\n\t */\r\n\terrorType?: NotificationOptions['type']\r\n\t/**\r\n\t * Whether to auto-dismiss the loading notification on complete/error\r\n\t */\r\n\tautoDismissLoading?: boolean\r\n\t/**\r\n\t * Duration for success notification (ms). Use 0 for persistent\r\n\t */\r\n\tsuccessDuration?: number\r\n\t/**\r\n\t * Duration for error notification (ms). Use 0 for persistent\r\n\t */\r\n\terrorDuration?: number\r\n}\r\n\r\n/**\r\n * Wraps an Observable with notification lifecycle management.\r\n * Shows a loading notification with progress indicator, then auto-dismisses and shows success/error notification.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Basic usage with progress indicator\r\n * someApiCall().pipe(\r\n * notify({\r\n * loadingMessage: 'Loading data...',\r\n * successMessage: 'Data loaded successfully!',\r\n * errorMessage: 'Failed to load data'\r\n * })\r\n * ).subscribe()\r\n * \r\n * // With custom durations\r\n * saveData().pipe(\r\n * notify({\r\n * loadingMessage: 'Saving...',\r\n * successMessage: 'Saved!',\r\n * successDuration: 5000, // Success stays for 5 seconds\r\n * errorMessage: (err) => `Save failed: ${err.message}`,\r\n * errorDuration: 0 // Error is persistent until dismissed\r\n * })\r\n * ).subscribe()\r\n * \r\n * // Full configuration example\r\n * uploadFile().pipe(\r\n * notify({\r\n * loadingMessage: 'Uploading file...',\r\n * loadingType: 'info',\r\n * successMessage: 'Upload complete!',\r\n * successType: 'success',\r\n * successDuration: 3000,\r\n * errorMessage: (err) => `Upload failed: ${err.message}`,\r\n * errorType: 'error',\r\n * errorDuration: 10000,\r\n * autoDismissLoading: true\r\n * })\r\n * ).subscribe()\r\n * ```\r\n */\r\nexport function notify<T>(options: NotifyOptions) {\r\n\treturn (source: Observable<T>): Observable<T> => {\r\n\t\tlet loadingNotificationId: string | undefined\r\n\r\n\t\t// Show loading notification if message provided\r\n\t\tif (options.loadingMessage) {\r\n\t\t\tloadingNotificationId = $notify.show({\r\n\t\t\t\tmessage: options.loadingMessage,\r\n\t\t\t\ttype: options.loadingType || 'info',\r\n\t\t\t\tduration: 0, // Persistent until dismissed\r\n\t\t\t\tshowProgress: true, // Show indeterminate progress by default\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn source.pipe(\r\n\t\t\ttap((value) => {\r\n\t\t\t\t// Check if the emitted value contains progress information\r\n\t\t\t\t// Common patterns: { progress: number }, { loaded: number, total: number }, etc.\r\n\t\t\t\tif (loadingNotificationId && typeof value === 'object' && value !== null) {\r\n\t\t\t\t\tlet progress: number | undefined\r\n\t\t\t\t\t\r\n\t\t\t\t\t// Check for different progress patterns\r\n\t\t\t\t\tif ('progress' in value && typeof (value as any).progress === 'number') {\r\n\t\t\t\t\t\tprogress = (value as any).progress\r\n\t\t\t\t\t} else if ('loaded' in value && 'total' in value) {\r\n\t\t\t\t\t\tconst loaded = (value as any).loaded\r\n\t\t\t\t\t\tconst total = (value as any).total\r\n\t\t\t\t\t\tif (typeof loaded === 'number' && typeof total === 'number' && total > 0) {\r\n\t\t\t\t\t\t\tprogress = (loaded / total) * 100\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\t// Update notification with progress if available\r\n\t\t\t\t\tif (progress !== undefined) {\r\n\t\t\t\t\t\t// We need to update the progress of the notification\r\n\t\t\t\t\t\t// For now, we'll update the message to show progress percentage\r\n\t\t\t\t\t\t$notify.update?.(loadingNotificationId, {\r\n\t\t\t\t\t\t\tmessage: `${options.loadingMessage} (${Math.round(progress)}%)`,\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t// Check if this is the final success emission (not a progress update)\r\n\t\t\t\t// Typically file uploads emit progress events then a final result\r\n\t\t\t\tconst isProgressUpdate = typeof value === 'object' && value !== null && \r\n\t\t\t\t\t('progress' in value || ('loaded' in value && 'total' in value))\r\n\t\t\t\t\r\n\t\t\t\tif (!isProgressUpdate) {\r\n\t\t\t\t\t// On successful final emission, dismiss loading and show success\r\n\t\t\t\t\tif (loadingNotificationId && options.autoDismissLoading !== false) {\r\n\t\t\t\t\t\t$notify.dismiss(loadingNotificationId)\r\n\t\t\t\t\t\tloadingNotificationId = undefined\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (options.successMessage) {\r\n\t\t\t\t\t\t$notify.show({\r\n\t\t\t\t\t\t\tmessage: options.successMessage,\r\n\t\t\t\t\t\t\ttype: options.successType || 'success',\r\n\t\t\t\t\t\t\tduration: options.successDuration ?? 2000,\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}),\r\n\t\t\tcatchError((error) => {\r\n\t\t\t\t// On error, dismiss loading and show error\r\n\t\t\t\tif (loadingNotificationId && options.autoDismissLoading !== false) {\r\n\t\t\t\t\t$notify.dismiss(loadingNotificationId)\r\n\t\t\t\t\tloadingNotificationId = undefined\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (options.errorMessage) {\r\n\t\t\t\t\tconst message = typeof options.errorMessage === 'function' \r\n\t\t\t\t\t\t? options.errorMessage(error)\r\n\t\t\t\t\t\t: options.errorMessage\r\n\t\t\t\t\t\r\n\t\t\t\t\t$notify.show({\r\n\t\t\t\t\t\tmessage,\r\n\t\t\t\t\t\ttype: options.errorType || 'error',\r\n\t\t\t\t\t\tduration: options.errorDuration ?? 3000,\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Re-throw the error to maintain the error flow\r\n\t\t\t\tthrow error\r\n\t\t\t}),\r\n\t\t\tfinalize(() => {\r\n\t\t\t\t// Clean up any remaining loading notification\r\n\t\t\t\tif (loadingNotificationId && options.autoDismissLoading !== false) {\r\n\t\t\t\t\t$notify.dismiss(loadingNotificationId)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t)\r\n\t}\r\n}\r\n\r\n/**\r\n * Simplified version for API calls that just need loading and auto-dismiss.\r\n * Perfect for fire-and-forget operations where you want to show progress.\r\n * \r\n * @example\r\n * ```typescript\r\n * downloadData().pipe(\r\n * notifyProgress('Downloading...')\r\n * ).subscribe()\r\n * \r\n * // With custom messages\r\n * saveDocument().pipe(\r\n * notifyProgress('Saving document...', 'Document saved!', 'Save failed')\r\n * ).subscribe()\r\n * ```\r\n */\r\nexport function notifyProgress<T>(\r\n\tloadingMessage: string,\r\n\tsuccessMessage?: string,\r\n\terrorMessage?: string\r\n) {\r\n\treturn notify<T>({\r\n\t\tloadingMessage,\r\n\t\tsuccessMessage: successMessage || undefined,\r\n\t\terrorMessage: errorMessage || undefined,\r\n\t\tautoDismissLoading: true,\r\n\t})\r\n}"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"notification-R2_Mf1HR.js","names":[],"sources":["../src/notification/notification.scss?inline","../src/notification/notification.ts","../src/notification/notification-service.ts","../src/notification/notify.ts"],"sourcesContent":[":host {\n\tdisplay: block;\n}\n\n.notification {\n\tposition: relative;\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 10px;\n\tpadding: 12px;\n\tpadding-right: 32px;\n\tbackground: var(--schmancy-sys-color-surface-container);\n\tborder-radius: var(--schmancy-sys-shape-corner-extraLarge, 16px);\n\tcolor: var(--schmancy-sys-color-surface-on);\n\tmax-width: 320px;\n\toverflow: hidden;\n\n\t/* Type-colored luminous glow */\n\t--notification-glow-color: var(--schmancy-sys-color-primary-default);\n\tbox-shadow: 0 4px 24px -6px color-mix(in srgb, var(--notification-glow-color) 18%, transparent);\n\tborder-left: 2px solid color-mix(in srgb, var(--notification-glow-color) 50%, transparent);\n\n\ttransition:\n\t\tbox-shadow 300ms ease,\n\t\ttransform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);\n\n\t&.info { --notification-glow-color: var(--schmancy-sys-color-primary-default); }\n\t&.success { --notification-glow-color: var(--schmancy-sys-color-success-default); }\n\t&.warning { --notification-glow-color: var(--schmancy-sys-color-warning-default); }\n\t&.error { --notification-glow-color: var(--schmancy-sys-color-error-default); }\n\n\t&.hovered {\n\t\tbox-shadow: 0 8px 32px -4px color-mix(in srgb, var(--notification-glow-color) 28%, transparent);\n\t\ttransform: translateY(-2px);\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\ttransition: box-shadow 200ms ease;\n\t\t&.hovered { transform: none; }\n\t}\n}\n\n.emoji {\n\tfont-size: 20px;\n\tline-height: 1;\n\tflex-shrink: 0;\n\tmargin-top: 1px;\n}\n\n.content {\n\tflex: 1;\n\tmin-width: 0;\n}\n\n.title {\n\tfont-weight: 500;\n\tfont-size: 13px;\n\tline-height: 1.4;\n\tmargin-bottom: 2px;\n\tletter-spacing: 0.01em;\n\n\t.info & {\n\t\tcolor: var(--schmancy-sys-color-primary-default);\n\t}\n\t.success & {\n\t\tcolor: var(--schmancy-sys-color-success-default);\n\t}\n\t.warning & {\n\t\tcolor: var(--schmancy-sys-color-tertiary-default);\n\t}\n\t.error & {\n\t\tcolor: var(--schmancy-sys-color-error-default);\n\t}\n}\n\n.message {\n\tfont-size: 13px;\n\tline-height: 1.4;\n\topacity: 0.75;\n\tletter-spacing: 0.01em;\n}\n\n.close {\n\tposition: absolute;\n\ttop: 8px;\n\tright: 6px;\n\tbackground: none;\n\tborder: none;\n\tfont-size: 16px;\n\tfont-weight: 300;\n\tcolor: var(--schmancy-sys-color-surface-onVariant);\n\tcursor: pointer;\n\tpadding: 4px 6px;\n\tline-height: 1;\n\topacity: 0.4;\n\tborder-radius: var(--schmancy-sys-shape-corner-full, 50%);\n\ttransition: opacity 200ms ease;\n\n\t&:hover {\n\t\topacity: 0.8;\n\t}\n\n\t&:focus-visible {\n\t\toutline: none;\n\t\topacity: 1;\n\t\tbox-shadow:\n\t\t\t0 0 0 2px var(--schmancy-sys-color-primary-default),\n\t\t\t0 0 8px -2px color-mix(in srgb, var(--schmancy-sys-color-primary-default) 25%, transparent);\n\t}\n}\n\n.progress {\n\tposition: absolute;\n\tbottom: 0;\n\tleft: 0;\n\tright: 0;\n}\n","import { SchmancyElement } from '@mixins/index'\nimport { html, unsafeCSS } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { BehaviorSubject, timer, interval, NEVER } from 'rxjs'\nimport { switchMap, takeUntil, map, tap, distinctUntilChanged } from 'rxjs/operators'\nimport '../progress/progress'\nimport style from './notification.scss?inline'\n\nexport type NotificationType = 'info' | 'success' | 'warning' | 'error'\n\n/**\n * Calculate a point on an arc between two points\n */\nfunction calculateArcPoint(\n\tstart: { x: number; y: number },\n\tend: { x: number; y: number },\n\tarcDirection: 'up' | 'down' = 'up',\n\tintensity: number = 0.3,\n): { x: number; y: number } {\n\tconst midX = (start.x + end.x) / 2\n\tconst midY = (start.y + end.y) / 2\n\tconst distance = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2))\n\tconst arcHeight = Math.min(distance * intensity, 150)\n\treturn {\n\t\tx: midX,\n\t\ty: arcDirection === 'up' ? midY - arcHeight : midY + arcHeight,\n\t}\n}\n\n/**\n * @fires close - When notification is closed\n */\n@customElement('sch-notification')\nexport default class SchmancyNotification extends SchmancyElement {\n\tstatic styles = [unsafeCSS(style)];\n\n\t@property({ type: String }) title = ''\n\t@property({ type: String }) message = ''\n\t@property({ type: String }) type: NotificationType = 'info'\n\t@property({ type: Boolean }) closable = true\n\t@property({ type: Number }) duration = 5000 // 0 means no auto-close\n\t@property({ type: String }) id = `notification-${Date.now()}-${Math.floor(Math.random() * 10000)}`\n\t@property({ type: Boolean }) playSound = true\n\t@property({ type: Boolean }) showProgress = false // Show indeterminate progress bar\n\t@property({ type: Object }) startPosition: { x: number; y: number } = { x: 0, y: 0 }\n\n\t@state() private _visible = true\n\t@state() private _progress = 100\n\t@state() private _hovered = false\n\t@state() private _closing = false\n\n\tprivate paused$ = new BehaviorSubject<boolean>(false)\n\tprivate startTime = 0\n\tprivate pausedAt = 0\n\tprivate elapsedBeforePause = 0\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\t// Set fixed positioning for blackbird animation\n\t\tthis.style.position = 'fixed'\n\t\tthis.style.top = '16px'\n\t\tthis.style.right = '16px'\n\t\tthis.style.zIndex = '10001'\n\t\tthis.style.opacity = '0'\n\n\t\t// Animate in after first render\n\t\tthis.updateComplete.then(() => {\n\t\t\tthis.animateIn()\n\t\t\treturn\n\t\t})\n\n\t\tif (this.duration > 0) {\n\t\t\tthis.setupAutoClose()\n\t\t\tthis.setupProgressUpdates()\n\t\t}\n\n\t\tif (this.playSound) {\n\t\t\tthis._playSound()\n\t\t}\n\t}\n\n\tprivate async animateIn() {\n\t\t// Get the notification element's final position\n\t\tconst rect = this.getBoundingClientRect()\n\t\tconst targetX = rect.left + rect.width / 2\n\t\tconst targetY = rect.top + rect.height / 2\n\n\t\t// Calculate arc point for upward arc\n\t\tconst arcPoint = calculateArcPoint(this.startPosition, { x: targetX, y: targetY }, 'up', 0.3)\n\n\t\t// Animate from click position to final position with arc\n\t\tawait this.animate(\n\t\t\t[\n\t\t\t\t{\n\t\t\t\t\ttransform: `translate(${this.startPosition.x - targetX}px, ${this.startPosition.y - targetY}px) scale(0.1)`,\n\t\t\t\t\topacity: 0,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttransform: `translate(${arcPoint.x - targetX}px, ${arcPoint.y - targetY}px) scale(0.6)`,\n\t\t\t\t\topacity: 0.9,\n\t\t\t\t\toffset: 0.5,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttransform: 'translate(0, 0) scale(1)',\n\t\t\t\t\topacity: 1,\n\t\t\t\t},\n\t\t\t],\n\t\t\t{\n\t\t\t\tduration: 400,\n\t\t\t\teasing: 'cubic-bezier(0.34, 1.2, 0.64, 1)',\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t).finished\n\t}\n\n\tprivate setupAutoClose() {\n\t\tif (this.duration <= 0) return\n\n\t\tthis.startTime = Date.now()\n\t\tthis.elapsedBeforePause = 0\n\n\t\tthis.paused$\n\t\t\t.pipe(\n\t\t\t\tswitchMap(paused => {\n\t\t\t\t\tif (paused) {\n\t\t\t\t\t\tthis.pausedAt = Date.now()\n\t\t\t\t\t\tthis.elapsedBeforePause += this.pausedAt - this.startTime\n\t\t\t\t\t\treturn NEVER\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.startTime = Date.now()\n\t\t\t\t\t\tconst remaining = this.duration - this.elapsedBeforePause\n\t\t\t\t\t\tif (remaining <= 0) {\n\t\t\t\t\t\t\tthis.close()\n\t\t\t\t\t\t\treturn NEVER\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn timer(remaining)\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\ttakeUntil(this.disconnecting),\n\t\t\t)\n\t\t\t.subscribe(() => this.close())\n\t}\n\n\tprivate setupProgressUpdates() {\n\t\tif (this.duration <= 0) return\n\n\t\tinterval(16)\n\t\t\t.pipe(\n\t\t\t\tswitchMap(() =>\n\t\t\t\t\tthis.paused$.pipe(\n\t\t\t\t\t\tmap(paused => {\n\t\t\t\t\t\t\tif (paused) return this._progress\n\t\t\t\t\t\t\tconst elapsed = this.elapsedBeforePause + (Date.now() - this.startTime)\n\t\t\t\t\t\t\tconst remaining = Math.max(0, this.duration - elapsed)\n\t\t\t\t\t\t\treturn (remaining / this.duration) * 100\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tdistinctUntilChanged(),\n\t\t\t\ttap(progress => {\n\t\t\t\t\tthis._progress = progress\n\t\t\t\t}),\n\t\t\t\ttakeUntil(this.disconnecting),\n\t\t\t)\n\t\t\t.subscribe()\n\t}\n\n\tprivate _playSound() {\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('playsound', {\n\t\t\t\tdetail: { type: this.type },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate _handleMouseEnter() {\n\t\tthis._hovered = true\n\t\tthis.paused$.next(true)\n\t}\n\n\tprivate _handleMouseLeave() {\n\t\tthis._hovered = false\n\t\tthis.paused$.next(false)\n\t}\n\n\tpublic async close() {\n\t\tif (this._closing) return\n\t\tthis._closing = true\n\t\tthis._visible = false\n\n\t\t// Animate out before dispatching close event\n\t\tawait this.animate(\n\t\t\t[\n\t\t\t\t{ transform: 'translate(0, 0) scale(1)', opacity: 1 },\n\t\t\t\t{ transform: 'translate(0, -20px) scale(0.8)', opacity: 0 },\n\t\t\t],\n\t\t\t{\n\t\t\t\tduration: 200,\n\t\t\t\teasing: 'cubic-bezier(0.4, 0, 1, 1)',\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t).finished\n\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('close', {\n\t\t\t\tdetail: { id: this.id },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t)\n\t}\n\n\tprivate _getEmoji(): string {\n\t\tswitch (this.type) {\n\t\t\tcase 'success':\n\t\t\t\treturn '\\u2705'\n\t\t\tcase 'warning':\n\t\t\t\treturn '\\u26A0\\uFE0F'\n\t\t\tcase 'error':\n\t\t\t\treturn '\\u274C'\n\t\t\tdefault:\n\t\t\t\treturn '\\u{1F4A1}'\n\t\t}\n\t}\n\n\trender() {\n\t\tif (!this._visible && this._closing) return html``\n\n\t\treturn html`\n\t\t\t<div\n\t\t\t\tclass=\"notification ${this.type} ${this._closing ? 'closing' : ''} ${this._hovered ? 'hovered' : ''}\"\n\t\t\t\trole=\"alert\"\n\t\t\t\t@mouseenter=${this._handleMouseEnter}\n\t\t\t\t@mouseleave=${this._handleMouseLeave}\n\t\t\t>\n\t\t\t\t<span class=\"emoji\">${this._getEmoji()}</span>\n\t\t\t\t<div class=\"content\">\n\t\t\t\t\t${this.title ? html`<div class=\"title\">${this.title}</div>` : ''}\n\t\t\t\t\t<div class=\"message\">${this.message}</div>\n\t\t\t\t</div>\n\t\t\t\t${this.closable\n\t\t\t\t\t? html`\n\t\t\t\t\t\t\t<button class=\"close\" aria-label=\"Close notification\" @click=${this.close}>x</button>\n\t\t\t\t\t\t`\n\t\t\t\t\t: ''}\n\t\t\t\t${this.showProgress || this.duration > 0\n\t\t\t\t\t? html`<schmancy-progress\n\t\t\t\t\t\tclass=\"progress\"\n\t\t\t\t\t\tsize=\"xs\"\n\t\t\t\t\t\t.value=${this._progress}\n\t\t\t\t\t\t?indeterminate=${this.showProgress && this.duration === 0}\n\t\t\t\t\t></schmancy-progress>`\n\t\t\t\t\t: ''}\n\t\t\t</div>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'sch-notification': SchmancyNotification\n\t}\n}\n","import { $sounds, type Feeling } from '../audio'\nimport SchmancyNotification, { NotificationType } from './notification'\n\nexport interface NotificationOptions {\n\tid?: string\n\ttitle?: string\n\tmessage: string\n\ttype?: NotificationType\n\tduration?: number\n\tclosable?: boolean\n\tplaySound?: boolean\n\tshowProgress?: boolean\n}\n\nconst typeToFeeling: Record<NotificationType, Feeling> = {\n\tinfo: 'curious',\n\tsuccess: 'content',\n\twarning: 'anxious',\n\terror: 'disappointed',\n}\n\n// Track last mouse position\nlet lastClickPosition = { x: window.innerWidth - 100, y: 50 }\n\n// Global mousedown listener to track click position\nif (typeof window !== 'undefined') {\n\twindow.addEventListener(\n\t\t'mousedown',\n\t\t(e: MouseEvent) => {\n\t\t\tlastClickPosition = { x: e.clientX, y: e.clientY }\n\t\t},\n\t\t{ capture: true, passive: true },\n\t)\n}\n\n// Track current notification element\nlet currentNotification: SchmancyNotification | null = null\n\n/**\n * Notification service for centralized notification management.\n * Provides a simple API for showing notifications.\n */\nexport class NotificationService {\n\tprivate static instance: NotificationService\n\tprivate notificationStack: string[] = []\n\tprivate audioVolume = 0.1\n\n\t// Default notification options\n\tprivate static DEFAULT_OPTIONS: Partial<NotificationOptions> = {\n\t\tduration: 1000, // 1 seconds - long enough to be readable\n\t\tclosable: true,\n\t\tplaySound: true,\n\t}\n\n\t// Type-specific default durations (in milliseconds)\n\tprivate static TYPE_DURATIONS: Record<NotificationType, number> = {\n\t\tsuccess: 1500, // 1.5 seconds - quick confirmation\n\t\tinfo: 2000, // 2 seconds - informational\n\t\twarning: 2500, // 2.5 seconds - needs attention\n\t\terror: 2500, // 2.5 seconds - important\n\t}\n\n\t// Private constructor for singleton pattern\n\tprivate constructor() {\n\t\t$sounds.setVolume(this.audioVolume)\n\t}\n\n\t/**\n\t * Get the singleton instance\n\t */\n\tpublic static getInstance(): NotificationService {\n\t\tif (!NotificationService.instance) {\n\t\t\tNotificationService.instance = new NotificationService()\n\t\t}\n\t\treturn NotificationService.instance\n\t}\n\n\t/**\n\t * Show a notification\n\t * @returns The ID of the created notification\n\t */\n\tpublic notify(options: NotificationOptions): string {\n\t\t// Apply default options\n\t\tconst completeOptions = {\n\t\t\t...NotificationService.DEFAULT_OPTIONS,\n\t\t\t...options,\n\t\t\t// Override with duraton from options if provided, otherwise use default\n\t\t\tduration: options.duration ?? NotificationService.DEFAULT_OPTIONS.duration,\n\t\t}\n\n\t\tconst id = completeOptions.id || `notification-${Date.now()}-${Math.floor(Math.random() * 10000)}`\n\n\t\t// Add to stack for tracking\n\t\tthis.notificationStack.push(id)\n\n\t\t// Remove existing notification if any (only 1 at a time)\n\t\tif (currentNotification) {\n\t\t\tcurrentNotification.remove()\n\t\t\tcurrentNotification = null\n\t\t}\n\n\t\t// Create the notification element directly\n\t\tconst notification = document.createElement('sch-notification') as SchmancyNotification\n\t\tnotification.id = id\n\t\tnotification.title = completeOptions.title || ''\n\t\tnotification.message = completeOptions.message\n\t\tnotification.type = completeOptions.type || 'info'\n\t\tnotification.duration = completeOptions.duration ?? 1000\n\t\tnotification.closable = completeOptions.closable !== false\n\t\tnotification.playSound = false // We handle sound here\n\t\tnotification.showProgress = completeOptions.showProgress || false\n\t\tnotification.startPosition = { ...lastClickPosition }\n\n\t\t// Play sound if enabled\n\t\tif (completeOptions.playSound !== false) {\n\t\t\t$sounds.play(typeToFeeling[notification.type])\n\t\t}\n\n\t\t// Listen for close event\n\t\tnotification.addEventListener('close', () => {\n\t\t\tconst index = this.notificationStack.indexOf(id)\n\t\t\tif (index > -1) {\n\t\t\t\tthis.notificationStack.splice(index, 1)\n\t\t\t}\n\t\t\tnotification.remove()\n\t\t\tif (currentNotification === notification) {\n\t\t\t\tcurrentNotification = null\n\t\t\t}\n\t\t})\n\n\t\t// Append to body\n\t\tdocument.body.appendChild(notification)\n\t\tcurrentNotification = notification\n\n\t\treturn id\n\t}\n\n\t/**\n\t * Dismiss a notification\n\t * @param id Optional notification ID. If not provided, dismisses the most recent notification\n\t */\n\tpublic dismiss(id?: string): void {\n\t\tlet targetId: string | undefined\n\n\t\tif (id) {\n\t\t\t// Remove specific notification from stack\n\t\t\tconst index = this.notificationStack.indexOf(id)\n\t\t\tif (index > -1) {\n\t\t\t\tthis.notificationStack.splice(index, 1)\n\t\t\t\ttargetId = id\n\t\t\t}\n\t\t} else {\n\t\t\t// Remove most recent notification (last in stack)\n\t\t\ttargetId = this.notificationStack.pop()\n\t\t}\n\n\t\tif (targetId && currentNotification && currentNotification.id === targetId) {\n\t\t\tcurrentNotification.close()\n\t\t}\n\t}\n\n\t/**\n\t * Update a notification's content\n\t */\n\tpublic update(id: string, options: Partial<NotificationOptions>): void {\n\t\tif (currentNotification && currentNotification.id === id) {\n\t\t\tif (options.title !== undefined) currentNotification.title = options.title\n\t\t\tif (options.message !== undefined) currentNotification.message = options.message\n\t\t\tif (options.type !== undefined) currentNotification.type = options.type\n\t\t}\n\t}\n\n\t/**\n\t * Show an info notification\n\t */\n\tpublic info(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'info',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.info) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a success notification\n\t */\n\tpublic success(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'success',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.success) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a warning notification\n\t */\n\tpublic warning(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'warning',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.warning) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show an error notification\n\t */\n\tpublic error(message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage: message ?? '',\n\t\t\ttype: 'error',\n\t\t\tduration: message ? (options.duration ?? NotificationService.TYPE_DURATIONS.error) : 1,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a notification with a custom duration\n\t */\n\tpublic customDuration(\n\t\tmessage: string,\n\t\tduration: number,\n\t\toptions: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {},\n\t): string {\n\t\treturn this.notify({\n\t\t\tmessage,\n\t\t\tduration,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Show a persistent notification (won't auto-dismiss)\n\t */\n\tpublic persistent(message: string, options: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {}): string {\n\t\treturn this.notify({\n\t\t\tmessage,\n\t\t\tduration: 0, // Zero duration means no auto-close\n\t\t\t...options,\n\t\t})\n\t}\n}\n\n/**\n * Global notification (toast) utility. Fire-and-forget API for success,\n * error, info, and warning toasts, plus a low-level `show` for custom\n * notifications.\n *\n * @service\n * @summary Toast notifications — success, error, info, warning.\n * @method show(options: NotificationOptions) - Low-level; show any NotificationOptions.\n * @method success(message, options?) - Green success toast.\n * @method error(message, options?) - Red error toast.\n * @method info(message, options?) - Blue informational toast.\n * @method warning(message, options?) - Amber warning toast.\n */\nexport const $notify = {\n\t/**\n\t * Show a notification\n\t */\n\tshow: (options: NotificationOptions): string => {\n\t\treturn NotificationService.getInstance().notify(options)\n\t},\n\n\t/**\n\t * Show an info notification\n\t */\n\tinfo: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().info(message, options)\n\t},\n\n\t/**\n\t * Show a success notification\n\t */\n\tsuccess: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().success(message, options)\n\t},\n\n\t/**\n\t * Show a warning notification\n\t */\n\twarning: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().warning(message, options)\n\t},\n\n\t/**\n\t * Show an error notification\n\t */\n\terror: (message?: string, options: Partial<Omit<NotificationOptions, 'message' | 'type'>> = {}): string => {\n\t\treturn NotificationService.getInstance().error(message, options)\n\t},\n\n\t/**\n\t * Show a notification with a custom duration\n\t * @param message The notification message\n\t * @param duration Duration in milliseconds before auto-dismissing (0 for no auto-dismiss)\n\t * @param options Additional notification options\n\t */\n\tcustomDuration: (\n\t\tmessage: string,\n\t\tduration: number,\n\t\toptions: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {},\n\t): string => {\n\t\treturn NotificationService.getInstance().customDuration(message, duration, options)\n\t},\n\n\t/**\n\t * Show a persistent notification that won't auto-dismiss\n\t */\n\tpersistent: (message: string, options: Partial<Omit<NotificationOptions, 'message' | 'duration'>> = {}): string => {\n\t\treturn NotificationService.getInstance().persistent(message, options)\n\t},\n\n\t/**\n\t * Dismiss a notification\n\t * @param id Optional notification ID. If not provided, dismisses the most recent notification (queue-like behavior)\n\t */\n\tdismiss: (id?: string): void => {\n\t\treturn NotificationService.getInstance().dismiss(id)\n\t},\n\n\t/**\n\t * Update a notification's content\n\t */\n\tupdate: (id: string, options: Partial<NotificationOptions>): void => {\n\t\treturn NotificationService.getInstance().update(id, options)\n\t},\n}\n","import { Observable, tap, finalize, catchError } from 'rxjs'\r\nimport { $notify, NotificationOptions } from './notification-service'\r\n\r\nexport interface NotifyOptions {\r\n\t/**\r\n\t * Message to show while the operation is in progress\r\n\t */\r\n\tloadingMessage?: string\r\n\t/**\r\n\t * Message to show when the operation completes successfully\r\n\t */\r\n\tsuccessMessage?: string\r\n\t/**\r\n\t * Message to show when the operation fails (can be a function to format error)\r\n\t */\r\n\terrorMessage?: string | ((error: any) => string)\r\n\t/**\r\n\t * Type of notification for loading state\r\n\t */\r\n\tloadingType?: NotificationOptions['type']\r\n\t/**\r\n\t * Type of notification for success state\r\n\t */\r\n\tsuccessType?: NotificationOptions['type']\r\n\t/**\r\n\t * Type of notification for error state\r\n\t */\r\n\terrorType?: NotificationOptions['type']\r\n\t/**\r\n\t * Whether to auto-dismiss the loading notification on complete/error\r\n\t */\r\n\tautoDismissLoading?: boolean\r\n\t/**\r\n\t * Duration for success notification (ms). Use 0 for persistent\r\n\t */\r\n\tsuccessDuration?: number\r\n\t/**\r\n\t * Duration for error notification (ms). Use 0 for persistent\r\n\t */\r\n\terrorDuration?: number\r\n}\r\n\r\n/**\r\n * Wraps an Observable with notification lifecycle management.\r\n * Shows a loading notification with progress indicator, then auto-dismisses and shows success/error notification.\r\n * \r\n * @example\r\n * ```typescript\r\n * // Basic usage with progress indicator\r\n * someApiCall().pipe(\r\n * notify({\r\n * loadingMessage: 'Loading data...',\r\n * successMessage: 'Data loaded successfully!',\r\n * errorMessage: 'Failed to load data'\r\n * })\r\n * ).subscribe()\r\n * \r\n * // With custom durations\r\n * saveData().pipe(\r\n * notify({\r\n * loadingMessage: 'Saving...',\r\n * successMessage: 'Saved!',\r\n * successDuration: 5000, // Success stays for 5 seconds\r\n * errorMessage: (err) => `Save failed: ${err.message}`,\r\n * errorDuration: 0 // Error is persistent until dismissed\r\n * })\r\n * ).subscribe()\r\n * \r\n * // Full configuration example\r\n * uploadFile().pipe(\r\n * notify({\r\n * loadingMessage: 'Uploading file...',\r\n * loadingType: 'info',\r\n * successMessage: 'Upload complete!',\r\n * successType: 'success',\r\n * successDuration: 3000,\r\n * errorMessage: (err) => `Upload failed: ${err.message}`,\r\n * errorType: 'error',\r\n * errorDuration: 10000,\r\n * autoDismissLoading: true\r\n * })\r\n * ).subscribe()\r\n * ```\r\n */\r\nexport function notify<T>(options: NotifyOptions) {\r\n\treturn (source: Observable<T>): Observable<T> => {\r\n\t\tlet loadingNotificationId: string | undefined\r\n\r\n\t\t// Show loading notification if message provided\r\n\t\tif (options.loadingMessage) {\r\n\t\t\tloadingNotificationId = $notify.show({\r\n\t\t\t\tmessage: options.loadingMessage,\r\n\t\t\t\ttype: options.loadingType || 'info',\r\n\t\t\t\tduration: 0, // Persistent until dismissed\r\n\t\t\t\tshowProgress: true, // Show indeterminate progress by default\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\treturn source.pipe(\r\n\t\t\ttap((value) => {\r\n\t\t\t\t// Check if the emitted value contains progress information\r\n\t\t\t\t// Common patterns: { progress: number }, { loaded: number, total: number }, etc.\r\n\t\t\t\tif (loadingNotificationId && typeof value === 'object' && value !== null) {\r\n\t\t\t\t\tlet progress: number | undefined\r\n\t\t\t\t\t\r\n\t\t\t\t\t// Check for different progress patterns\r\n\t\t\t\t\tif ('progress' in value && typeof (value as any).progress === 'number') {\r\n\t\t\t\t\t\tprogress = (value as any).progress\r\n\t\t\t\t\t} else if ('loaded' in value && 'total' in value) {\r\n\t\t\t\t\t\tconst loaded = (value as any).loaded\r\n\t\t\t\t\t\tconst total = (value as any).total\r\n\t\t\t\t\t\tif (typeof loaded === 'number' && typeof total === 'number' && total > 0) {\r\n\t\t\t\t\t\t\tprogress = (loaded / total) * 100\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\r\n\t\t\t\t\t// Update notification with progress if available\r\n\t\t\t\t\tif (progress !== undefined) {\r\n\t\t\t\t\t\t// We need to update the progress of the notification\r\n\t\t\t\t\t\t// For now, we'll update the message to show progress percentage\r\n\t\t\t\t\t\t$notify.update?.(loadingNotificationId, {\r\n\t\t\t\t\t\t\tmessage: `${options.loadingMessage} (${Math.round(progress)}%)`,\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\t\r\n\t\t\t\t// Check if this is the final success emission (not a progress update)\r\n\t\t\t\t// Typically file uploads emit progress events then a final result\r\n\t\t\t\tconst isProgressUpdate = typeof value === 'object' && value !== null && \r\n\t\t\t\t\t('progress' in value || ('loaded' in value && 'total' in value))\r\n\t\t\t\t\r\n\t\t\t\tif (!isProgressUpdate) {\r\n\t\t\t\t\t// On successful final emission, dismiss loading and show success\r\n\t\t\t\t\tif (loadingNotificationId && options.autoDismissLoading !== false) {\r\n\t\t\t\t\t\t$notify.dismiss(loadingNotificationId)\r\n\t\t\t\t\t\tloadingNotificationId = undefined\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (options.successMessage) {\r\n\t\t\t\t\t\t$notify.show({\r\n\t\t\t\t\t\t\tmessage: options.successMessage,\r\n\t\t\t\t\t\t\ttype: options.successType || 'success',\r\n\t\t\t\t\t\t\tduration: options.successDuration ?? 2000,\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}),\r\n\t\t\tcatchError((error) => {\r\n\t\t\t\t// On error, dismiss loading and show error\r\n\t\t\t\tif (loadingNotificationId && options.autoDismissLoading !== false) {\r\n\t\t\t\t\t$notify.dismiss(loadingNotificationId)\r\n\t\t\t\t\tloadingNotificationId = undefined\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (options.errorMessage) {\r\n\t\t\t\t\tconst message = typeof options.errorMessage === 'function' \r\n\t\t\t\t\t\t? options.errorMessage(error)\r\n\t\t\t\t\t\t: options.errorMessage\r\n\t\t\t\t\t\r\n\t\t\t\t\t$notify.show({\r\n\t\t\t\t\t\tmessage,\r\n\t\t\t\t\t\ttype: options.errorType || 'error',\r\n\t\t\t\t\t\tduration: options.errorDuration ?? 3000,\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// Re-throw the error to maintain the error flow\r\n\t\t\t\tthrow error\r\n\t\t\t}),\r\n\t\t\tfinalize(() => {\r\n\t\t\t\t// Clean up any remaining loading notification\r\n\t\t\t\tif (loadingNotificationId && options.autoDismissLoading !== false) {\r\n\t\t\t\t\t$notify.dismiss(loadingNotificationId)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t)\r\n\t}\r\n}\r\n\r\n/**\r\n * Simplified version for API calls that just need loading and auto-dismiss.\r\n * Perfect for fire-and-forget operations where you want to show progress.\r\n * \r\n * @example\r\n * ```typescript\r\n * downloadData().pipe(\r\n * notifyProgress('Downloading...')\r\n * ).subscribe()\r\n * \r\n * // With custom messages\r\n * saveDocument().pipe(\r\n * notifyProgress('Saving document...', 'Document saved!', 'Save failed')\r\n * ).subscribe()\r\n * ```\r\n */\r\nexport function notifyProgress<T>(\r\n\tloadingMessage: string,\r\n\tsuccessMessage?: string,\r\n\terrorMessage?: string\r\n) {\r\n\treturn notify<T>({\r\n\t\tloadingMessage,\r\n\t\tsuccessMessage: successMessage || undefined,\r\n\t\terrorMessage: errorMessage || undefined,\r\n\t\tautoDismissLoading: true,\r\n\t})\r\n}"],"mappings":";;;;;;;;ACiCe,IAAA,IAAA,cAAmC,EAAA;CAAA,YAAA,GAAA,GAAA;EAAA,MAAA,GAAA,EAAA,EAAA,KAAA,QAGb,IAAA,KAAA,UACE,IAAA,KAAA,OACe,QAAA,KAAA,WAAA,CACb,GAAA,KAAA,WACD,KAAA,KAAA,KACN,gBAAgB,KAAK,KAAA,CAAA,GAAS,KAAK,MAAsB,MAAhB,KAAK,QAAA,CAAA,IAAA,KAAA,YAAA,CACtC,GAAA,KAAA,eAAA,CACG,GAAA,KAAA,gBAC0B;GAAE,GAAG;GAAG,GAAG;GAAA,EAAA,KAAA,WAAA,CAErD,GAAA,KAAA,YACC,KAAA,KAAA,WAAA,CACD,GAAA,KAAA,WAAA,CACA,GAAA,KAAA,UAEV,IAAI,EAAA,CAAyB,EAAA,EAAA,KAAA,YAC3B,GAAA,KAAA,WACD,GAAA,KAAA,qBACU;;CAAA;EAAA,KAAA,SApBb,CAAC,EAAA,wxEAAA,CAAA;;CAsBjB,oBAAA;EACC,MAAM,mBAAA,EAGN,KAAK,MAAM,WAAW,SACtB,KAAK,MAAM,MAAM,QACjB,KAAK,MAAM,QAAQ,QACnB,KAAK,MAAM,SAAS,SACpB,KAAK,MAAM,UAAU,KAGrB,KAAK,eAAe,WAAA;GACnB,KAAK,WAAA;IAAA,EAIF,KAAK,WAAW,MACnB,KAAK,gBAAA,EACL,KAAK,sBAAA,GAGF,KAAK,aACR,KAAK,YAAA;;CAIP,MAAA,YAAc;EAEb,IAAM,IAAO,KAAK,uBAAA,EACZ,IAAU,EAAK,OAAO,EAAK,QAAQ,GACnC,IAAU,EAAK,MAAM,EAAK,SAAS,GAGnC,IA5ER,SACC,GACA,GACA,IAA8B,MAC9B,IAAoB,IAAA;GAEpB,IAAM,KAAQ,EAAM,IAAI,EAAI,KAAK,GAC3B,KAAQ,EAAM,IAAI,EAAI,KAAK,GAC3B,IAAW,KAAK,MAAc,EAAI,IAAI,EAAM,MAAG,KAAc,EAAI,IAAI,EAAM,MAAG,EAAA,EAC9E,IAAY,KAAK,IAAI,IAAW,GAAW,IAAA;GACjD,OAAO;IACN,GAAG;IACH,GAAG,MAAiB,OAAO,IAAO,IAAY,IAAO;IAAA;IAgElB,KAAK,eAAe;GAAE,GAAG;GAAS,GAAG;GAAA,EAAW,MAAM,GAAA;EAAA,MAGnF,KAAK,QACV;GACC;IACC,WAAW,aAAa,KAAK,cAAc,IAAI,EAAA,MAAc,KAAK,cAAc,IAAI,EAAA;IACpF,SAAS;IAAA;GAEV;IACC,WAAW,aAAa,EAAS,IAAI,EAAA,MAAc,EAAS,IAAI,EAAA;IAChE,SAAS;IACT,QAAQ;IAAA;GAET;IACC,WAAW;IACX,SAAS;IAAA;GAAA,EAGX;GACC,UAAU;GACV,QAAQ;GACR,MAAM;GAAA,CAAA,CAEN;;CAGH,iBAAA;EACK,KAAK,YAAY,MAErB,KAAK,YAAY,KAAK,KAAA,EACtB,KAAK,qBAAqB,GAE1B,KAAK,QACH,KACA,GAAU,MAAA;GACT,IAAI,GAGH,OAFA,KAAK,WAAW,KAAK,KAAA,EACrB,KAAK,sBAAsB,KAAK,WAAW,KAAK,WACzC;GACD;IACN,KAAK,YAAY,KAAK,KAAA;IACtB,IAAM,IAAY,KAAK,WAAW,KAAK;IACvC,OAAI,KAAa,KAChB,KAAK,OAAA,EACE,KAED,EAAM,EAAA;;IAAA,EAGf,EAAU,KAAK,cAAA,CAAA,CAEf,gBAAgB,KAAK,OAAA,CAAA;;CAGxB,uBAAA;EACK,KAAK,YAAY,KAErB,EAAS,GAAA,CACP,KACA,QACC,KAAK,QAAQ,KACZ,GAAI,MAAA;GACH,IAAI,GAAQ,OAAO,KAAK;GACxB,IAAM,IAAU,KAAK,sBAAsB,KAAK,KAAA,GAAQ,KAAK;GAE7D,OADkB,KAAK,IAAI,GAAG,KAAK,WAAW,EAAA,GAC1B,KAAK,WAAY;IAAA,CAAA,CAAA,EAIxC,GAAA,EACA,GAAI,MAAA;GACH,KAAK,YAAY;IAAA,EAElB,EAAU,KAAK,cAAA,CAAA,CAEf,WAAA;;CAGH,aAAA;EACC,KAAK,cACJ,IAAI,YAAY,aAAa;GAC5B,QAAQ,EAAE,MAAM,KAAK,MAAA;GACrB,SAAA,CAAS;GACT,UAAA,CAAU;GAAA,CAAA,CAAA;;CAKb,oBAAA;EACC,KAAK,WAAA,CAAW,GAChB,KAAK,QAAQ,KAAA,CAAK,EAAA;;CAGnB,oBAAA;EACC,KAAK,WAAA,CAAW,GAChB,KAAK,QAAQ,KAAA,CAAK,EAAA;;CAGnB,MAAA,QAAa;EACR,KAAK,aACT,KAAK,WAAA,CAAW,GAChB,KAAK,WAAA,CAAW,GAAA,MAGV,KAAK,QACV,CACC;GAAE,WAAW;GAA4B,SAAS;GAAA,EAClD;GAAE,WAAW;GAAkC,SAAS;GAAA,CAAA,EAEzD;GACC,UAAU;GACV,QAAQ;GACR,MAAM;GAAA,CAAA,CAEN,UAEF,KAAK,cACJ,IAAI,YAAY,SAAS;GACxB,QAAQ,EAAE,IAAI,KAAK,IAAA;GACnB,SAAA,CAAS;GACT,UAAA,CAAU;GAAA,CAAA,CAAA;;CAKb,YAAA;EACC,QAAQ,KAAK,MAAb;GACC,KAAK,WACJ,OAAO;GACR,KAAK,WACJ,OAAO;GACR,KAAK,SACJ,OAAO;GACR,SACC,OAAO;;;CAIV,SAAA;EACC,OAAA,CAAK,KAAK,YAAY,KAAK,WAAiB,CAAI,KAEzC,CAAI;;0BAEa,KAAK,KAAA,GAAQ,KAAK,WAAW,YAAY,GAAA,GAAM,KAAK,WAAW,YAAY,GAAA;;kBAEnF,KAAK,kBAAA;kBACL,KAAK,kBAAA;;0BAEG,KAAK,WAAA,CAAA;;OAExB,KAAK,QAAQ,CAAI,sBAAsB,KAAK,MAAA,UAAgB,GAAA;4BACvC,KAAK,QAAA;;MAE3B,KAAK,WACJ,CAAI;sEAC2D,KAAK,MAAA;UAEpE,GAAA;MACD,KAAK,gBAAgB,KAAK,WAAW,IACpC,CAAI;;;eAGI,KAAK,UAAA;uBACG,KAAK,gBAAgB,KAAK,aAAa,EAAb;8BAE1C,GAAA;;;;;GA3NL,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,SAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,WAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,QAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,SAAA,CAAA,CAAA,EAAU,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC3B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,MAAA,KAAA,EAAA,EAAA,EAAA,CAC1B,EAAS,EAAE,MAAM,SAAA,CAAA,CAAA,EAAU,EAAA,WAAA,aAAA,KAAA,EAAA,EAAA,EAAA,CAC3B,EAAS,EAAE,MAAM,SAAA,CAAA,CAAA,EAAU,EAAA,WAAA,gBAAA,KAAA,EAAA,EAAA,EAAA,CAC3B,EAAS,EAAE,MAAM,QAAA,CAAA,CAAA,EAAS,EAAA,WAAA,iBAAA,KAAA,EAAA,EAAA,EAAA,CAE1B,GAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CACP,GAAA,CAAA,EAAO,EAAA,WAAA,aAAA,KAAA,EAAA,EAAA,EAAA,CACP,GAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA,EAAA,EAAA,CACP,GAAA,CAAA,EAAO,EAAA,WAAA,YAAA,KAAA,EAAA;AAAA,IAAA,IAAA,IAAA,EAAA,CAjBR,EAAc,mBAAA,CAAA,EAAmB,EAAA,EClB5B,IAAmD;CACxD,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;CAAA,EAIJ,IAAoB;CAAE,GAAG,OAAO,aAAa;CAAK,GAAG;CAAA;AAGnC,OAAX,SAAW,OACrB,OAAO,iBACN,cACC,MAAA;CACA,IAAoB;EAAE,GAAG,EAAE;EAAS,GAAG,EAAE;EAAA;GAE1C;CAAE,SAAA,CAAS;CAAM,SAAA,CAAS;CAAA,CAAA;AAK5B,IAAI,IAAmD,MAM1C,IAAb,MAAa,EAAA;CAAA;EAAA,KAAA,kBAMmD;GAC9D,UAAU;GACV,UAAA,CAAU;GACV,WAAA,CAAW;GAAA;;CAAA;EAAA,KAAA,iBAIsD;GACjE,SAAS;GACT,MAAM;GACN,SAAS;GACT,OAAO;GAAA;;CAIR,cAAA;EAAA,KAAA,oBAnBsC,EAAA,EAAA,KAAA,cAChB,IAmBrB,EAAQ,UAAU,KAAK,YAAA;;CAMxB,OAAA,cAAc;EAIb,OAHK,AACJ,EAAoB,aAAW,IAAI,GAAA,EAE7B,EAAoB;;CAO5B,OAAc,GAAA;EAEb,IAAM,IAAkB;GAAA,GACpB,EAAoB;GAAA,GACpB;GAEH,UAAU,EAAQ,YAAY,EAAoB,gBAAgB;GAAA,EAG7D,IAAK,EAAgB,MAAM,gBAAgB,KAAK,KAAA,CAAA,GAAS,KAAK,MAAsB,MAAhB,KAAK,QAAA,CAAA;EAG/E,KAAK,kBAAkB,KAAK,EAAA,EAGxB,AAEH,OADA,EAAoB,QAAA,EACE;EAIvB,IAAM,IAAe,SAAS,cAAc,mBAAA;EAgC5C,OA/BA,EAAa,KAAK,GAClB,EAAa,QAAQ,EAAgB,SAAS,IAC9C,EAAa,UAAU,EAAgB,SACvC,EAAa,OAAO,EAAgB,QAAQ,QAC5C,EAAa,WAAW,EAAgB,YAAY,KACpD,EAAa,WAAA,CAAwC,MAA7B,EAAgB,UACxC,EAAa,YAAA,CAAY,GACzB,EAAa,eAAe,EAAgB,gBAAA,CAAgB,GAC5D,EAAa,gBAAgB,EAAA,GAAK,GAAA,EAAA,CAGA,MAA9B,EAAgB,aACnB,EAAQ,KAAK,EAAc,EAAa,MAAA,EAIzC,EAAa,iBAAiB,eAAA;GAC7B,IAAM,IAAQ,KAAK,kBAAkB,QAAQ,EAAA;GACzC,IAAA,MACH,KAAK,kBAAkB,OAAO,GAAO,EAAA,EAEtC,EAAa,QAAA,EACT,MAAwB,MAC3B,IAAsB;IAAA,EAKxB,SAAS,KAAK,YAAY,EAAA,EAC1B,IAAsB,GAEf;;CAOR,QAAe,GAAA;EACd,IAAI;EAEJ,IAAI,GAAI;GAEP,IAAM,IAAQ,KAAK,kBAAkB,QAAQ,EAAA;GACzC,IAAA,OACH,KAAK,kBAAkB,OAAO,GAAO,EAAA,EACrC,IAAW;SAIZ,IAAW,KAAK,kBAAkB,KAAA;EAG/B,KAAY,KAAuB,EAAoB,OAAO,KACjE,EAAoB,OAAA;;CAOtB,OAAc,GAAY,GAAA;EACrB,KAAuB,EAAoB,OAAO,MACjD,EAAQ,UADyC,KAC/B,MAAW,EAAoB,QAAQ,EAAQ,QACjE,EAAQ,YADyD,KAC7C,MAAW,EAAoB,UAAU,EAAQ,UACrE,EAAQ,SAD6D,KACpD,MAAW,EAAoB,OAAO,EAAQ;;CAOrE,KAAY,GAAkB,IAAkE,EAAA,EAAA;EAC/F,OAAO,KAAK,OAAO;GAClB,SAAS,KAAW;GACpB,MAAM;GACN,UAAU,IAAW,EAAQ,YAAY,EAAoB,eAAe,OAAQ;GAAA,GACjF;GAAA,CAAA;;CAOL,QAAe,GAAkB,IAAkE,EAAA,EAAA;EAClG,OAAO,KAAK,OAAO;GAClB,SAAS,KAAW;GACpB,MAAM;GACN,UAAU,IAAW,EAAQ,YAAY,EAAoB,eAAe,UAAW;GAAA,GACpF;GAAA,CAAA;;CAOL,QAAe,GAAkB,IAAkE,EAAA,EAAA;EAClG,OAAO,KAAK,OAAO;GAClB,SAAS,KAAW;GACpB,MAAM;GACN,UAAU,IAAW,EAAQ,YAAY,EAAoB,eAAe,UAAW;GAAA,GACpF;GAAA,CAAA;;CAOL,MAAa,GAAkB,IAAkE,EAAA,EAAA;EAChG,OAAO,KAAK,OAAO;GAClB,SAAS,KAAW;GACpB,MAAM;GACN,UAAU,IAAW,EAAQ,YAAY,EAAoB,eAAe,QAAS;GAAA,GAClF;GAAA,CAAA;;CAOL,eACC,GACA,GACA,IAAsE,EAAA,EAAA;EAEtE,OAAO,KAAK,OAAO;GAClB,SAAA;GACA,UAAA;GAAA,GACG;GAAA,CAAA;;CAOL,WAAkB,GAAiB,IAAsE,EAAA,EAAA;EACxG,OAAO,KAAK,OAAO;GAClB,SAAA;GACA,UAAU;GAAA,GACP;GAAA,CAAA;;GAkBO,IAAU;CAItB,OAAO,MACC,EAAoB,aAAA,CAAc,OAAO,EAAA;CAMjD,OAAO,GAAkB,IAAkE,EAAA,KACnF,EAAoB,aAAA,CAAc,KAAK,GAAS,EAAA;CAMxD,UAAU,GAAkB,IAAkE,EAAA,KACtF,EAAoB,aAAA,CAAc,QAAQ,GAAS,EAAA;CAM3D,UAAU,GAAkB,IAAkE,EAAA,KACtF,EAAoB,aAAA,CAAc,QAAQ,GAAS,EAAA;CAM3D,QAAQ,GAAkB,IAAkE,EAAA,KACpF,EAAoB,aAAA,CAAc,MAAM,GAAS,EAAA;CASzD,iBACC,GACA,GACA,IAAsE,EAAA,KAE/D,EAAoB,aAAA,CAAc,eAAe,GAAS,GAAU,EAAA;CAM5E,aAAa,GAAiB,IAAsE,EAAA,KAC5F,EAAoB,aAAA,CAAc,WAAW,GAAS,EAAA;CAO9D,UAAU,MACF,EAAoB,aAAA,CAAc,QAAQ,EAAA;CAMlD,SAAS,GAAY,MACb,EAAoB,aAAA,CAAc,OAAO,GAAI,EAAA;CAAA;ACrPtD,SAAgB,EAAU,GAAA;CACzB,QAAQ,MAAA;EACP,IAAI;EAYJ,OATI,EAAQ,mBACX,IAAwB,EAAQ,KAAK;GACpC,SAAS,EAAQ;GACjB,MAAM,EAAQ,eAAe;GAC7B,UAAU;GACV,cAAA,CAAc;GAAA,CAAA,GAIT,EAAO,KACb,GAAK,MAAA;GAGJ,IAAI,KAA0C,OAAV,KAAU,YAAY,GAAgB;IACzE,IAAI;IAGJ,IAAI,cAAc,KAA4C,OAA3B,EAAc,YAAa,UAC7D,IAAY,EAAc;SACpB,IAAI,YAAY,KAAS,WAAW,GAAO;KACjD,IAAM,IAAU,EAAc,QACxB,IAAS,EAAc;KACP,AAAA,OAAX,KAAW,YAA6B,OAAV,KAAU,YAAY,IAAQ,MACtE,IAAY,IAAS,IAAS;;IAAA,AAK5B,MAL4B,KAKf,KAGhB,EAAQ,SAAS,GAAuB,EACvC,SAAS,GAAG,EAAQ,eAAA,IAAmB,KAAK,MAAM,EAAA,CAAA,KAAA,CAAA;;GAOX,AAAA,OAAV,KAAU,YAAY,MACpD,cAAc,KAAU,YAAY,KAAS,WAAW,OAIrD,KAAA,CAAwD,MAA/B,EAAQ,uBACpC,EAAQ,QAAQ,EAAA,EAChB,IAAA,KAAwB,IAGrB,EAAQ,kBACX,EAAQ,KAAK;IACZ,SAAS,EAAQ;IACjB,MAAM,EAAQ,eAAe;IAC7B,UAAU,EAAQ,mBAAmB;IAAA,CAAA;IAAA,EAKzC,GAAY,MAAA;GAOX,IALI,KAAA,CAAwD,MAA/B,EAAQ,uBACpC,EAAQ,QAAQ,EAAA,EAChB,IAAA,KAAwB,IAGrB,EAAQ,cAAc;IACzB,IAAM,IAA0C,OAAzB,EAAQ,gBAAiB,aAC7C,EAAQ,aAAa,EAAA,GACrB,EAAQ;IAEX,EAAQ,KAAK;KACZ,SAAA;KACA,MAAM,EAAQ,aAAa;KAC3B,UAAU,EAAQ,iBAAiB;KAAA,CAAA;;GAKrC,MAAM;IAAA,EAEP,QAAA;GAEK,KAAA,CAAwD,MAA/B,EAAQ,sBACpC,EAAQ,QAAQ,EAAA;IAAA,CAAA;;;AAuBrB,SAAgB,EACf,GACA,GACA,GAAA;CAEA,OAAO,EAAU;EAChB,gBAAA;EACA,gBAAgB,KAAA,KAAkB;EAClC,cAAc,KAAA,KAAgB;EAC9B,oBAAA,CAAoB;EAAA,CAAA;;AAAA,SAAA,KAAA,GAAA,KAAA,GAAA,KAAA,GAAA,KAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"window-BTecgE_U.js","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 +0,0 @@
|
|
|
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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"}
|