@mhmo91/schmancy 0.5.35 → 0.5.37
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/ai/content-drawer.md +114 -140
- package/ai/navigation-bar.md +30 -4
- package/ai/navigation-rail.md +72 -0
- package/ai/theme.md +779 -716
- package/dist/ai/content-drawer.md +114 -140
- package/dist/ai/navigation-bar.md +30 -4
- package/dist/ai/navigation-rail.md +72 -0
- package/dist/ai/theme.md +779 -716
- package/dist/{animated-text-COvhr8E3.js → animated-text-Cfs1zx2e.js} +4 -3
- package/dist/{animated-text-COvhr8E3.js.map → animated-text-Cfs1zx2e.js.map} +1 -1
- package/dist/{animated-text-BZUrBdvN.cjs → animated-text-DoLx8YhT.cjs} +2 -2
- package/dist/{animated-text-BZUrBdvN.cjs.map → animated-text-DoLx8YhT.cjs.map} +1 -1
- package/dist/animated-text.cjs +1 -1
- package/dist/animated-text.js +1 -1
- package/dist/area.cjs +1 -1
- package/dist/{area.component-BHtBHWVt.js → area.component-A6Xw-dfF.js} +4 -3
- package/dist/{area.component-BHtBHWVt.js.map → area.component-A6Xw-dfF.js.map} +1 -1
- package/dist/area.component-DMRF1lD-.cjs +12 -0
- package/dist/{area.component-Ch2Eaa4i.cjs.map → area.component-DMRF1lD-.cjs.map} +1 -1
- package/dist/area.js +1 -1
- package/dist/{autocomplete-9RkU9LmA.js → autocomplete-C5DIxpTG.js} +18 -18
- package/dist/{autocomplete-9RkU9LmA.js.map → autocomplete-C5DIxpTG.js.map} +1 -1
- package/dist/{autocomplete-CenwFcT1.cjs → autocomplete-DkJqOYTg.cjs} +2 -2
- package/dist/{autocomplete-CenwFcT1.cjs.map → autocomplete-DkJqOYTg.cjs.map} +1 -1
- package/dist/autocomplete.cjs +1 -1
- package/dist/autocomplete.js +1 -1
- package/dist/{avatar-CjjwZDsw.js → avatar-BDy0wAek.js} +144 -134
- package/dist/avatar-BDy0wAek.js.map +1 -0
- package/dist/avatar-BmcocEQ4.cjs +306 -0
- package/dist/avatar-BmcocEQ4.cjs.map +1 -0
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/boat-CfIXRMn-.cjs +78 -0
- package/dist/boat-CfIXRMn-.cjs.map +1 -0
- package/dist/boat-DumUFcmT.js +276 -0
- package/dist/boat-DumUFcmT.js.map +1 -0
- package/dist/boat.cjs +1 -1
- package/dist/boat.js +1 -1
- package/dist/busy.cjs +1 -1
- package/dist/busy.js +1 -1
- package/dist/button.cjs +1 -1
- package/dist/button.js +1 -1
- package/dist/card.cjs +1 -1
- package/dist/card.js +1 -1
- package/dist/{checkbox-D6-WQeEk.js → checkbox-CHG-gT2P.js} +3 -2
- package/dist/{checkbox-D6-WQeEk.js.map → checkbox-CHG-gT2P.js.map} +1 -1
- package/dist/{checkbox-8djp_8NK.cjs → checkbox-CsMLbxBY.cjs} +2 -2
- package/dist/{checkbox-8djp_8NK.cjs.map → checkbox-CsMLbxBY.cjs.map} +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/chips.cjs +1 -1
- package/dist/chips.js +2 -2
- package/dist/code-highlight.cjs +1 -1
- package/dist/code-highlight.js +1 -1
- package/dist/{code-preview-BFoEmN8y.cjs → code-preview-BgUU7bPR.cjs} +5 -5
- package/dist/{code-preview-BFoEmN8y.cjs.map → code-preview-BgUU7bPR.cjs.map} +1 -1
- package/dist/{code-preview-Z02-2suM.js → code-preview-Bp4OemTD.js} +8 -8
- package/dist/{code-preview-Z02-2suM.js.map → code-preview-Bp4OemTD.js.map} +1 -1
- package/dist/components.cjs +1 -1
- package/dist/components.js +1 -1
- package/dist/content-drawer.cjs +1 -1
- package/dist/content-drawer.js +1 -1
- package/dist/context-create-CA907mdD.cjs +2 -0
- package/dist/context-create-CA907mdD.cjs.map +1 -0
- package/dist/{context-object-BE1o2XB3.js → context-create-DCiujzV2.js} +262 -212
- package/dist/context-create-DCiujzV2.js.map +1 -0
- package/dist/{date-range-kFnTrnHN.js → date-range-BcJ0YN2n.js} +141 -140
- package/dist/{date-range-kFnTrnHN.js.map → date-range-BcJ0YN2n.js.map} +1 -1
- package/dist/{date-range-DoCtnpW6.cjs → date-range-D_DBil9n.cjs} +2 -2
- package/dist/{date-range-DoCtnpW6.cjs.map → date-range-D_DBil9n.cjs.map} +1 -1
- package/dist/date-range-inline-DQjOVUxD.cjs +44 -0
- package/dist/{date-range-inline-DNr7C5X-.cjs.map → date-range-inline-DQjOVUxD.cjs.map} +1 -1
- package/dist/{date-range-inline-BXeX6T7R.js → date-range-inline-Dqxqgu2s.js} +8 -7
- package/dist/{date-range-inline-BXeX6T7R.js.map → date-range-inline-Dqxqgu2s.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-CrdOikhP.cjs → delay-BbtlKEc4.cjs} +2 -2
- package/dist/{delay-CrdOikhP.cjs.map → delay-BbtlKEc4.cjs.map} +1 -1
- package/dist/{delay-Cz-9rZxi.js → delay-CC_14mn4.js} +2 -2
- package/dist/{delay-Cz-9rZxi.js.map → delay-CC_14mn4.js.map} +1 -1
- package/dist/delay.cjs +1 -1
- package/dist/delay.js +1 -1
- package/dist/{details-CsqhGMjL.cjs → details-CTdm7rbG.cjs} +2 -2
- package/dist/{details-CsqhGMjL.cjs.map → details-CTdm7rbG.cjs.map} +1 -1
- package/dist/{details-DeBtsJlp.js → details-dk2hnRIp.js} +3 -2
- package/dist/{details-DeBtsJlp.js.map → details-dk2hnRIp.js.map} +1 -1
- package/dist/details.cjs +1 -1
- package/dist/details.js +1 -1
- package/dist/{dialog-content-DTKdAF_l.js → dialog-content-BM-lfqHq.js} +4 -4
- package/dist/{dialog-content-DTKdAF_l.js.map → dialog-content-BM-lfqHq.js.map} +1 -1
- package/dist/{dialog-content-BzSQoM2J.cjs → dialog-content-BSZ5dwnP.cjs} +2 -2
- package/dist/{dialog-content-BzSQoM2J.cjs.map → dialog-content-BSZ5dwnP.cjs.map} +1 -1
- package/dist/dialog.cjs +1 -1
- package/dist/dialog.js +1 -1
- package/dist/discovery.cjs +2 -0
- package/dist/discovery.cjs.map +1 -0
- package/dist/discovery.js +6 -0
- package/dist/discovery.js.map +1 -0
- package/dist/discovery.service-BbYjU5x8.js +21 -0
- package/dist/discovery.service-BbYjU5x8.js.map +1 -0
- package/dist/discovery.service-BpGCuXPd.cjs +2 -0
- package/dist/discovery.service-BpGCuXPd.cjs.map +1 -0
- package/dist/{divider-7iyyEd8k.js → divider-BWVdeJm1.js} +4 -3
- package/dist/{divider-7iyyEd8k.js.map → divider-BWVdeJm1.js.map} +1 -1
- package/dist/divider-DgJXEKxB.cjs +2 -0
- package/dist/{divider-CNxOc8ep.cjs.map → divider-DgJXEKxB.cjs.map} +1 -1
- package/dist/divider.cjs +1 -1
- package/dist/divider.js +1 -1
- package/dist/{dropdown-content-_GMpqsNq.js → dropdown-content-BgLy9dwU.js} +4 -3
- package/dist/{dropdown-content-_GMpqsNq.js.map → dropdown-content-BgLy9dwU.js.map} +1 -1
- package/dist/{dropdown-content-De0OkNoq.cjs → dropdown-content-ZAB82v-h.cjs} +2 -2
- package/dist/{dropdown-content-De0OkNoq.cjs.map → dropdown-content-ZAB82v-h.cjs.map} +1 -1
- package/dist/dropdown.cjs +1 -1
- package/dist/dropdown.js +1 -1
- package/dist/{email-recipients-CPZlUiRR.js → email-recipients-IXQLqBaI.js} +6 -5
- package/dist/{email-recipients-CPZlUiRR.js.map → email-recipients-IXQLqBaI.js.map} +1 -1
- package/dist/{email-recipients-DS01C3V3.cjs → email-recipients-R7jCXy_I.cjs} +2 -2
- package/dist/{email-recipients-DS01C3V3.cjs.map → email-recipients-R7jCXy_I.cjs.map} +1 -1
- package/dist/extra.cjs +1 -1
- package/dist/extra.js +1 -1
- package/dist/{flex-BeSoRNTu.js → flex-Cp1nomar.js} +3 -2
- package/dist/{flex-BeSoRNTu.js.map → flex-Cp1nomar.js.map} +1 -1
- package/dist/{flex-CHf9Gc5V.cjs → flex-sAQsXdsk.cjs} +2 -2
- package/dist/{flex-CHf9Gc5V.cjs.map → flex-sAQsXdsk.cjs.map} +1 -1
- package/dist/form-DHTbrnEl.cjs +2 -0
- package/dist/{form-DzDksPgv.cjs.map → form-DHTbrnEl.cjs.map} +1 -1
- package/dist/{form-DNeKagke.js → form-Dtc128QU.js} +3 -2
- package/dist/{form-DNeKagke.js.map → form-Dtc128QU.js.map} +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.js +1 -1
- package/dist/{formField.mixin-BNj75WQ4.js → formField.mixin-CCB_CKYb.js} +2 -2
- package/dist/{formField.mixin-BNj75WQ4.js.map → formField.mixin-CCB_CKYb.js.map} +1 -1
- package/dist/{formField.mixin-D5YAYIS1.cjs → formField.mixin-CZQ7alVs.cjs} +2 -2
- package/dist/{formField.mixin-D5YAYIS1.cjs.map → formField.mixin-CZQ7alVs.cjs.map} +1 -1
- package/dist/{icon-CCMpTJTp.js → icon-BHhOyVjB.js} +9 -9
- package/dist/{icon-CCMpTJTp.js.map → icon-BHhOyVjB.js.map} +1 -1
- package/dist/{icon-DebIySqv.cjs → icon-CocdSdlX.cjs} +3 -3
- package/dist/{icon-DebIySqv.cjs.map → icon-CocdSdlX.cjs.map} +1 -1
- package/dist/{icon-button-D6DH52j4.js → icon-button-CjSaBrg0.js} +4 -3
- package/dist/{icon-button-D6DH52j4.js.map → icon-button-CjSaBrg0.js.map} +1 -1
- package/dist/{icon-button-DwnnW2oj.cjs → icon-button-m8kXxOvS.cjs} +2 -2
- package/dist/{icon-button-DwnnW2oj.cjs.map → icon-button-m8kXxOvS.cjs.map} +1 -1
- package/dist/icons.cjs +1 -1
- package/dist/icons.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +187 -182
- package/dist/index.js.map +1 -1
- package/dist/input-BuDPnk5e.cjs +51 -0
- package/dist/{input-C2Vz-51i.cjs.map → input-BuDPnk5e.cjs.map} +1 -1
- package/dist/{input-DtHPCCyd.js → input-D_gdNxxR.js} +4 -3
- package/dist/{input-DtHPCCyd.js.map → input-D_gdNxxR.js.map} +1 -1
- package/dist/{input-chip-B7ANrtLF.cjs → input-chip-CDLblIp9.cjs} +2 -2
- package/dist/{input-chip-B7ANrtLF.cjs.map → input-chip-CDLblIp9.cjs.map} +1 -1
- package/dist/{input-chip-DbIvSyvP.js → input-chip-CLnR4vSR.js} +2 -2
- package/dist/{input-chip-DbIvSyvP.js.map → input-chip-CLnR4vSR.js.map} +1 -1
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/layout.cjs +1 -1
- package/dist/layout.js +1 -1
- package/dist/{list-BBo0--_Q.js → list-C069T9ey.js} +3 -2
- package/dist/{list-BBo0--_Q.js.map → list-C069T9ey.js.map} +1 -1
- package/dist/{list-BH8OJ3Rv.cjs → list-KCakyWxw.cjs} +2 -2
- package/dist/{list-BH8OJ3Rv.cjs.map → list-KCakyWxw.cjs.map} +1 -1
- package/dist/list.cjs +1 -1
- package/dist/list.js +1 -1
- package/dist/{litElement.mixin-LplXbzd8.cjs → litElement.mixin-DoBMt4ia.cjs} +2 -2
- package/dist/{litElement.mixin-LplXbzd8.cjs.map → litElement.mixin-DoBMt4ia.cjs.map} +1 -1
- package/dist/{litElement.mixin-CzF0mNQd.js → litElement.mixin-Dp4mBSNw.js} +2 -2
- package/dist/{litElement.mixin-CzF0mNQd.js.map → litElement.mixin-Dp4mBSNw.js.map} +1 -1
- package/dist/mailbox.cjs +1 -1
- package/dist/mailbox.js +1 -1
- package/dist/{map-DeiCBxMP.js → map-pn_6ziZf.js} +19 -19
- package/dist/{map-DeiCBxMP.js.map → map-pn_6ziZf.js.map} +1 -1
- package/dist/{map-C7lxYU4A.cjs → map-vNMrrat-.cjs} +2 -2
- package/dist/{map-C7lxYU4A.cjs.map → map-vNMrrat-.cjs.map} +1 -1
- package/dist/map.cjs +1 -1
- package/dist/map.js +1 -1
- package/dist/{media-CsYVcfaX.cjs → media-CAtXPif3.cjs} +6 -6
- package/dist/{media-CsYVcfaX.cjs.map → media-CAtXPif3.cjs.map} +1 -1
- package/dist/{media-CEnaqjig.js → media-DC3r4y8-.js} +9 -8
- package/dist/{media-CEnaqjig.js.map → media-DC3r4y8-.js.map} +1 -1
- package/dist/{menu-wtkHGlyc.js → menu-BAs2snSu.js} +4 -3
- package/dist/{menu-wtkHGlyc.js.map → menu-BAs2snSu.js.map} +1 -1
- package/dist/{menu-Boqsyfmh.cjs → menu-C2ZKJe1g.cjs} +2 -2
- package/dist/{menu-Boqsyfmh.cjs.map → menu-C2ZKJe1g.cjs.map} +1 -1
- package/dist/menu.cjs +1 -1
- package/dist/menu.js +1 -1
- package/dist/mixins/baseElement.ts +33 -1
- package/dist/mixins/discovery.service.ts +60 -0
- 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-6ONc-XE-.cjs → navigation-rail-B0zofile.cjs} +14 -11
- package/dist/navigation-rail-B0zofile.cjs.map +1 -0
- package/dist/{navigation-rail-D-lK9oVd.js → navigation-rail-KdVjbO1I.js} +43 -31
- package/dist/navigation-rail-KdVjbO1I.js.map +1 -0
- package/dist/navigation-rail.cjs +1 -1
- package/dist/navigation-rail.js +1 -1
- package/dist/{notification-service-ZiGUSd63.js → notification-service-BOCdK7B0.js} +7 -6
- package/dist/{notification-service-ZiGUSd63.js.map → notification-service-BOCdK7B0.js.map} +1 -1
- package/dist/{notification-service-9HXSKWcw.cjs → notification-service-DXsySIdG.cjs} +2 -2
- package/dist/{notification-service-9HXSKWcw.cjs.map → notification-service-DXsySIdG.cjs.map} +1 -1
- package/dist/notification.cjs +1 -1
- package/dist/notification.js +2 -2
- package/dist/{notify-DbfX6Z2P.js → notify-Cglpgay3.js} +2 -2
- package/dist/{notify-DbfX6Z2P.js.map → notify-Cglpgay3.js.map} +1 -1
- package/dist/{notify-W-NrP0cC.cjs → notify-CvDL-o79.cjs} +2 -2
- package/dist/{notify-W-NrP0cC.cjs.map → notify-CvDL-o79.cjs.map} +1 -1
- package/dist/{option-D2bxihLu.cjs → option-ezGy71aI.cjs} +2 -2
- package/dist/{option-D2bxihLu.cjs.map → option-ezGy71aI.cjs.map} +1 -1
- package/dist/{option-BFlWiCu0.js → option-tDU1Z_vP.js} +11 -10
- package/dist/{option-BFlWiCu0.js.map → option-tDU1Z_vP.js.map} +1 -1
- package/dist/option.cjs +1 -1
- package/dist/option.js +1 -1
- package/dist/payment-card-form-B5b-LA2Y.cjs +74 -0
- package/dist/{payment-card-form--v94EhJF.cjs.map → payment-card-form-B5b-LA2Y.cjs.map} +1 -1
- package/dist/{payment-card-form-DLRNX9NX.js → payment-card-form-CZpc-zfO.js} +4 -3
- package/dist/{payment-card-form-DLRNX9NX.js.map → payment-card-form-CZpc-zfO.js.map} +1 -1
- package/dist/{progress-BYohUvYO.js → progress-Bqih11TQ.js} +10 -9
- package/dist/{progress-BYohUvYO.js.map → progress-Bqih11TQ.js.map} +1 -1
- package/dist/{progress-CjkD8QBy.cjs → progress-OMGbiNv5.cjs} +2 -2
- package/dist/{progress-CjkD8QBy.cjs.map → progress-OMGbiNv5.cjs.map} +1 -1
- package/dist/progress.cjs +1 -1
- package/dist/progress.js +1 -1
- package/dist/{radio-button-CGmGOAil.cjs → radio-button-BuSpPTO4.cjs} +2 -2
- package/dist/{radio-button-CGmGOAil.cjs.map → radio-button-BuSpPTO4.cjs.map} +1 -1
- package/dist/{radio-button-BlxeCjdq.js → radio-button-mHT1573u.js} +4 -3
- package/dist/{radio-button-BlxeCjdq.js.map → radio-button-mHT1573u.js.map} +1 -1
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/{schmancy-steps-container-CydL78yk.cjs → schmancy-steps-container-Bht_BlLU.cjs} +2 -2
- package/dist/{schmancy-steps-container-CydL78yk.cjs.map → schmancy-steps-container-Bht_BlLU.cjs.map} +1 -1
- package/dist/{schmancy-steps-container-BtAHCm73.js → schmancy-steps-container-DDMiJJyw.js} +2 -2
- package/dist/{schmancy-steps-container-BtAHCm73.js.map → schmancy-steps-container-DDMiJJyw.js.map} +1 -1
- package/dist/{select-BiN334GN.js → select-CKtpFPTr.js} +13 -13
- package/dist/{select-BiN334GN.js.map → select-CKtpFPTr.js.map} +1 -1
- package/dist/{select-CrB02cIO.cjs → select-HPtumqyg.cjs} +2 -2
- package/dist/{select-CrB02cIO.cjs.map → select-HPtumqyg.cjs.map} +1 -1
- package/dist/select.cjs +1 -1
- package/dist/select.js +1 -1
- package/dist/selector-hook-BWMY8npH.cjs +2 -0
- package/dist/selector-hook-BWMY8npH.cjs.map +1 -0
- package/dist/selector-hook-CKeyK4K-.js +313 -0
- package/dist/selector-hook-CKeyK4K-.js.map +1 -0
- package/dist/{sheet-DpJv4DRi.js → sheet-B-vTiTi8.js} +4 -3
- package/dist/{sheet-DpJv4DRi.js.map → sheet-B-vTiTi8.js.map} +1 -1
- package/dist/{sheet-sgVoRMi1.cjs → sheet-DP7nFOEo.cjs} +2 -2
- package/dist/{sheet-sgVoRMi1.cjs.map → sheet-DP7nFOEo.cjs.map} +1 -1
- package/dist/sheet.cjs +1 -1
- package/dist/sheet.js +1 -1
- package/dist/{slider-D7qdxfvX.js → slider-Bu7kQ0_w.js} +9 -9
- package/dist/{slider-D7qdxfvX.js.map → slider-Bu7kQ0_w.js.map} +1 -1
- package/dist/{slider-Dd1L6oYm.cjs → slider-Diqgkt3E.cjs} +4 -4
- package/dist/{slider-Dd1L6oYm.cjs.map → slider-Diqgkt3E.cjs.map} +1 -1
- package/dist/slider.cjs +1 -1
- package/dist/slider.js +1 -1
- package/dist/{spinner-CaXU45TV.cjs → spinner-b6hiAljR.cjs} +2 -2
- package/dist/{spinner-CaXU45TV.cjs.map → spinner-b6hiAljR.cjs.map} +1 -1
- package/dist/{spinner-XN4W5ihQ.js → spinner-paAzgY93.js} +3 -2
- package/dist/{spinner-XN4W5ihQ.js.map → spinner-paAzgY93.js.map} +1 -1
- package/dist/steps.cjs +1 -1
- package/dist/steps.js +1 -1
- package/dist/store.cjs +1 -1
- package/dist/store.js +26 -26
- package/dist/{suggestion-chip-PI24Hc3s.cjs → suggestion-chip--FVeCUSI.cjs} +2 -2
- package/dist/{suggestion-chip-PI24Hc3s.cjs.map → suggestion-chip--FVeCUSI.cjs.map} +1 -1
- package/dist/{suggestion-chip-CdhoATv9.js → suggestion-chip-DnnfUAqx.js} +3 -3
- package/dist/{suggestion-chip-CdhoATv9.js.map → suggestion-chip-DnnfUAqx.js.map} +1 -1
- package/dist/{surface-CKrYJ58l.js → surface-BBhAIoZq.js} +2 -2
- package/dist/{surface-CKrYJ58l.js.map → surface-BBhAIoZq.js.map} +1 -1
- package/dist/{surface-Ax6I7ldp.cjs → surface-SICYUsoB.cjs} +2 -2
- package/dist/{surface-Ax6I7ldp.cjs.map → surface-SICYUsoB.cjs.map} +1 -1
- package/dist/surface.cjs +1 -1
- package/dist/surface.js +1 -1
- package/dist/{table-CP6_NkPm.js → table-CepjNGT6.js} +2 -2
- package/dist/{table-CP6_NkPm.js.map → table-CepjNGT6.js.map} +1 -1
- package/dist/{table-BlwUyf_4.cjs → table-yYKET4qQ.cjs} +2 -2
- package/dist/{table-BlwUyf_4.cjs.map → table-yYKET4qQ.cjs.map} +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.js +1 -1
- package/dist/{tabs-compatibility-CX0cIu_Y.cjs → tabs-compatibility-BWaRkr9s.cjs} +4 -4
- package/dist/{tabs-compatibility-CX0cIu_Y.cjs.map → tabs-compatibility-BWaRkr9s.cjs.map} +1 -1
- package/dist/{tabs-compatibility-7QKuXX4i.js → tabs-compatibility-BXdyrybs.js} +7 -6
- package/dist/{tabs-compatibility-7QKuXX4i.js.map → tabs-compatibility-BXdyrybs.js.map} +1 -1
- package/dist/tabs.cjs +1 -1
- package/dist/tabs.js +1 -1
- package/dist/tailwind.mixin-CYhJgwwb.cjs +2 -0
- package/dist/tailwind.mixin-CYhJgwwb.cjs.map +1 -0
- package/dist/tailwind.mixin-Cn7vup-6.js +64 -0
- package/dist/tailwind.mixin-Cn7vup-6.js.map +1 -0
- package/dist/teleport.cjs +1 -1
- package/dist/teleport.js +1 -1
- package/dist/{textarea-DHrDn-O6.js → textarea-BpNEwBP9.js} +3 -2
- package/dist/{textarea-DHrDn-O6.js.map → textarea-BpNEwBP9.js.map} +1 -1
- package/dist/textarea-Xgbs3rjA.cjs +44 -0
- package/dist/{textarea-qLA0vP78.cjs.map → textarea-Xgbs3rjA.cjs.map} +1 -1
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.js +1 -1
- package/dist/{theme-button-BEUsbH5m.js → theme-button-77xbTIaH.js} +6 -5
- package/dist/{theme-button-BEUsbH5m.js.map → theme-button-77xbTIaH.js.map} +1 -1
- package/dist/theme-button-BsjsULjH.cjs +9 -0
- package/dist/{theme-button-D7fBEUGf.cjs.map → theme-button-BsjsULjH.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.controls-BeNS8iSM.cjs +67 -0
- package/dist/theme.controls-BeNS8iSM.cjs.map +1 -0
- package/dist/{theme.component-ByGua01V.js → theme.controls-DtcpHuz9.js} +367 -238
- package/dist/theme.controls-DtcpHuz9.js.map +1 -0
- package/dist/theme.js +13 -11
- package/dist/{timezone-BpDMR26D.js → timezone-CtH2a7Hw.js} +10 -9
- package/dist/{timezone-BpDMR26D.js.map → timezone-CtH2a7Hw.js.map} +1 -1
- package/dist/{timezone-Bw4EXBt7.cjs → timezone-D3kdUX6c.cjs} +2 -2
- package/dist/{timezone-Bw4EXBt7.cjs.map → timezone-D3kdUX6c.cjs.map} +1 -1
- package/dist/{tooltip-Dhs4HL3A.cjs → tooltip-BwZ_zIEI.cjs} +2 -2
- package/dist/{tooltip-Dhs4HL3A.cjs.map → tooltip-BwZ_zIEI.cjs.map} +1 -1
- package/dist/{tooltip-B1jynZOH.js → tooltip-DgGZouB5.js} +2 -2
- package/dist/{tooltip-B1jynZOH.js.map → tooltip-DgGZouB5.js.map} +1 -1
- package/dist/tooltip.cjs +1 -1
- package/dist/tooltip.js +1 -1
- package/dist/{tree-D-ezei_U.cjs → tree-B9fWtaGW.cjs} +4 -4
- package/dist/{tree-D-ezei_U.cjs.map → tree-B9fWtaGW.cjs.map} +1 -1
- package/dist/{tree-BH1qCJ_U.js → tree-BSENnhB2.js} +3 -2
- package/dist/{tree-BH1qCJ_U.js.map → tree-BSENnhB2.js.map} +1 -1
- package/dist/tree.cjs +1 -1
- package/dist/tree.js +1 -1
- package/dist/{typewriter-DQbpNPtY.js → typewriter-BCXtlffJ.js} +5 -4
- package/dist/{typewriter-DQbpNPtY.js.map → typewriter-BCXtlffJ.js.map} +1 -1
- package/dist/typewriter-DeNR2E_p.cjs +9 -0
- package/dist/{typewriter-CtPh4Pyj.cjs.map → typewriter-DeNR2E_p.cjs.map} +1 -1
- package/dist/typewriter.cjs +1 -1
- package/dist/typewriter.js +1 -1
- package/dist/{typography-BrIaOYmC.cjs → typography-Cm7pGqRe.cjs} +2 -2
- package/dist/{typography-BrIaOYmC.cjs.map → typography-Cm7pGqRe.cjs.map} +1 -1
- package/dist/{typography-D71cmr0R.js → typography-sxQLtA6a.js} +2 -2
- package/dist/{typography-D71cmr0R.js.map → typography-sxQLtA6a.js.map} +1 -1
- package/dist/typography.cjs +1 -1
- package/dist/typography.js +1 -1
- package/package.json +1 -1
- package/types/mixins/baseElement.d.ts +2 -1
- package/types/mixins/discovery.service.d.ts +17 -0
- package/types/src/boat/boat.d.ts +10 -5
- package/types/src/discovery/discovery.service.d.ts +17 -0
- package/types/src/discovery/index.d.ts +1 -0
- package/types/src/index.d.ts +1 -0
- package/types/src/navigation-bar/navigation-bar.d.ts +15 -1
- package/types/src/navigation-rail/navigation-rail.d.ts +13 -0
- package/types/src/theme/index.d.ts +1 -0
- package/types/src/theme/theme.controls.d.ts +27 -0
- package/types/src/theme/theme.service.d.ts +58 -2
- package/dist/area.component-Ch2Eaa4i.cjs +0 -12
- package/dist/avatar-CjjwZDsw.js.map +0 -1
- package/dist/avatar-DlhBTIc8.cjs +0 -303
- package/dist/avatar-DlhBTIc8.cjs.map +0 -1
- package/dist/boat-CUsJXaLf.js +0 -240
- package/dist/boat-CUsJXaLf.js.map +0 -1
- package/dist/boat-Dfx9-P8c.cjs +0 -83
- package/dist/boat-Dfx9-P8c.cjs.map +0 -1
- package/dist/context-object-BE1o2XB3.js.map +0 -1
- package/dist/context-object-DA9DM9QJ.cjs +0 -2
- package/dist/context-object-DA9DM9QJ.cjs.map +0 -1
- package/dist/date-range-inline-DNr7C5X-.cjs +0 -44
- package/dist/divider-CNxOc8ep.cjs +0 -2
- package/dist/form-DzDksPgv.cjs +0 -2
- package/dist/input-C2Vz-51i.cjs +0 -51
- package/dist/navigation-rail-6ONc-XE-.cjs.map +0 -1
- package/dist/navigation-rail-D-lK9oVd.js.map +0 -1
- package/dist/payment-card-form--v94EhJF.cjs +0 -74
- package/dist/selector-hook-DOsvFxG2.js +0 -364
- package/dist/selector-hook-DOsvFxG2.js.map +0 -1
- package/dist/selector-hook-DQ9zoDM4.cjs +0 -2
- package/dist/selector-hook-DQ9zoDM4.cjs.map +0 -1
- package/dist/tailwind.mixin-BjDGMGbj.js +0 -43
- package/dist/tailwind.mixin-BjDGMGbj.js.map +0 -1
- package/dist/tailwind.mixin-ClfV2_Nh.cjs +0 -2
- package/dist/tailwind.mixin-ClfV2_Nh.cjs.map +0 -1
- package/dist/textarea-qLA0vP78.cjs +0 -44
- package/dist/theme-button-D7fBEUGf.cjs +0 -9
- package/dist/theme.component-ByGua01V.js.map +0 -1
- package/dist/theme.component-CQ1trrZB.cjs +0 -3
- package/dist/theme.component-CQ1trrZB.cjs.map +0 -1
- package/dist/typewriter-CtPh4Pyj.cjs +0 -9
package/ai/theme.md
CHANGED
|
@@ -1,923 +1,986 @@
|
|
|
1
|
-
# Theme
|
|
1
|
+
# Theme Service
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Comprehensive Material Design 3 theme management with reactive observables, automatic persistence, and a complete token system for colors, typography, motion, and more.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Import
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
```typescript
|
|
8
|
+
import { theme } from '@schmancy/theme'
|
|
9
|
+
// Alternative: schmancyTheme
|
|
10
|
+
```
|
|
10
11
|
|
|
11
|
-
##
|
|
12
|
+
## Core Concepts
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
- **Scheme**: Color mode (`'dark'` | `'light'` | `'auto'`)
|
|
15
|
+
- **Resolved Scheme**: Actual theme after resolving `'auto'` based on system preferences
|
|
16
|
+
- **Color**: Primary theme color in hex format
|
|
17
|
+
- **Fullscreen**: Navigation visibility state
|
|
18
|
+
- **Theme Component**: Visual theme provider that registers with service
|
|
19
|
+
- **Material Design 3 Tokens**: Complete design system with colors, surfaces, typography, motion, and more
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
<!-- Basic theme with auto color -->
|
|
17
|
-
<schmancy-theme>
|
|
18
|
-
<div class="my-app">
|
|
19
|
-
<!-- All children inherit theme -->
|
|
20
|
-
</div>
|
|
21
|
-
</schmancy-theme>
|
|
21
|
+
## Properties (Synchronous)
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
<!-- Root-level theme -->
|
|
31
|
-
<schmancy-theme color="#00695C" root>
|
|
32
|
-
<!-- Theme applies to entire document -->
|
|
33
|
-
</schmancy-theme>
|
|
23
|
+
```typescript
|
|
24
|
+
theme.scheme // 'dark' | 'light' | 'auto'
|
|
25
|
+
theme.color // '#6200ee'
|
|
26
|
+
theme.fullscreen // boolean
|
|
27
|
+
theme.themeComponent // SchmancyThemeComponent | null
|
|
28
|
+
theme.theme // Partial<TSchmancyTheme> - Full M3 token system
|
|
34
29
|
```
|
|
35
30
|
|
|
36
|
-
|
|
31
|
+
## Observables
|
|
37
32
|
|
|
38
33
|
```typescript
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
// Scheme changes
|
|
35
|
+
theme.scheme$.subscribe(scheme => {
|
|
36
|
+
console.log(scheme) // 'dark' | 'light' | 'auto'
|
|
37
|
+
})
|
|
41
38
|
|
|
42
|
-
//
|
|
43
|
-
|
|
39
|
+
// Resolved scheme (auto → actual) - NEVER returns 'auto'
|
|
40
|
+
theme.resolvedScheme$.subscribe(scheme => {
|
|
41
|
+
console.log(scheme) // 'dark' | 'light' (automatically resolved)
|
|
42
|
+
})
|
|
44
43
|
|
|
45
|
-
//
|
|
46
|
-
|
|
44
|
+
// Color changes
|
|
45
|
+
theme.color$.subscribe(color => {
|
|
46
|
+
console.log(color) // '#6200ee'
|
|
47
|
+
})
|
|
47
48
|
|
|
48
|
-
//
|
|
49
|
-
|
|
49
|
+
// Fullscreen state
|
|
50
|
+
theme.fullscreen$.subscribe(isFullscreen => {
|
|
51
|
+
console.log(isFullscreen) // true/false
|
|
52
|
+
})
|
|
50
53
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
console.log(
|
|
54
|
+
// Complete theme configuration
|
|
55
|
+
theme.theme$.subscribe(themeConfig => {
|
|
56
|
+
console.log(themeConfig) // Full Material Design 3 theme object
|
|
54
57
|
})
|
|
55
58
|
```
|
|
56
59
|
|
|
57
|
-
##
|
|
58
|
-
|
|
59
|
-
| Property | Type | Default | Description |
|
|
60
|
-
|----------|------|---------|-------------|
|
|
61
|
-
| `color` | `string` | `random` | Source color for theme generation |
|
|
62
|
-
| `scheme` | `'dark' \| 'light' \| 'auto'` | `'auto'` | Color scheme mode |
|
|
63
|
-
| `root` | `boolean` | `false` | Apply theme to document root |
|
|
64
|
-
| `theme` | `Partial<TSchmancyTheme>` | `{}` | Custom theme overrides |
|
|
65
|
-
|
|
66
|
-
## Material Design 3 Integration
|
|
67
|
-
|
|
68
|
-
The component uses Google's Material Color Utilities to generate a complete color system:
|
|
60
|
+
## Methods
|
|
69
61
|
|
|
62
|
+
### `setScheme(scheme)`
|
|
63
|
+
Set color scheme with automatic persistence.
|
|
70
64
|
```typescript
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
const theme = themeFromSourceColor(argbFromHex('#6750A4'));
|
|
65
|
+
theme.setScheme('dark') // Force dark
|
|
66
|
+
theme.setScheme('light') // Force light
|
|
67
|
+
theme.setScheme('auto') // Follow system preferences
|
|
75
68
|
```
|
|
76
69
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
<!-- In your app root -->
|
|
82
|
-
<schmancy-theme color="#1976D2" root>
|
|
83
|
-
<schmancy-app>
|
|
84
|
-
<!-- Entire app uses this theme -->
|
|
85
|
-
</schmancy-app>
|
|
86
|
-
</schmancy-theme>
|
|
70
|
+
### `toggleScheme()`
|
|
71
|
+
Toggle between light/dark modes.
|
|
72
|
+
```typescript
|
|
73
|
+
theme.toggleScheme() // light → dark → light
|
|
87
74
|
```
|
|
88
75
|
|
|
89
|
-
###
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<schmancy-theme color="#00897B">
|
|
94
|
-
<section class="analytics">
|
|
95
|
-
<!-- Teal theme -->
|
|
96
|
-
</section>
|
|
97
|
-
</schmancy-theme>
|
|
98
|
-
|
|
99
|
-
<schmancy-theme color="#E53935">
|
|
100
|
-
<section class="alerts">
|
|
101
|
-
<!-- Red theme for alerts -->
|
|
102
|
-
</section>
|
|
103
|
-
</schmancy-theme>
|
|
104
|
-
</div>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Dark Mode Support
|
|
108
|
-
```html
|
|
109
|
-
<!-- Automatic dark/light switching -->
|
|
110
|
-
<schmancy-theme scheme="auto">
|
|
111
|
-
<schmancy-surface>
|
|
112
|
-
<p>Adapts to system preferences</p>
|
|
113
|
-
</schmancy-surface>
|
|
114
|
-
</schmancy-theme>
|
|
115
|
-
|
|
116
|
-
<!-- Force dark mode -->
|
|
117
|
-
<schmancy-theme scheme="dark" color="#673AB7">
|
|
118
|
-
<schmancy-card>
|
|
119
|
-
<h3>Always Dark</h3>
|
|
120
|
-
</schmancy-card>
|
|
121
|
-
</schmancy-theme>
|
|
76
|
+
### `setColor(color)`
|
|
77
|
+
Set primary color - automatically generates full M3 palette.
|
|
78
|
+
```typescript
|
|
79
|
+
theme.setColor('#6750A4') // Generates all tones and color roles
|
|
122
80
|
```
|
|
123
81
|
|
|
124
|
-
###
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
.
|
|
129
|
-
|
|
130
|
-
color: {
|
|
131
|
-
primary: {
|
|
132
|
-
default: '#FF5722',
|
|
133
|
-
onDefault: '#FFFFFF'
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}}"
|
|
138
|
-
>
|
|
139
|
-
<schmancy-button variant="filled">
|
|
140
|
-
Custom Themed Button
|
|
141
|
-
</schmancy-button>
|
|
142
|
-
</schmancy-theme>
|
|
82
|
+
### `isDarkMode()`
|
|
83
|
+
Observable that emits current dark mode state.
|
|
84
|
+
```typescript
|
|
85
|
+
theme.isDarkMode().subscribe(isDark => {
|
|
86
|
+
console.log(isDark) // true/false
|
|
87
|
+
})
|
|
143
88
|
```
|
|
144
89
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
--schmancy-sys-color-primary-default
|
|
152
|
-
--schmancy-sys-color-primary-onDefault
|
|
153
|
-
--schmancy-sys-color-primary-container
|
|
154
|
-
--schmancy-sys-color-primary-onContainer
|
|
90
|
+
### `setFullscreen(value)`
|
|
91
|
+
Control fullscreen mode for immersive experiences.
|
|
92
|
+
```typescript
|
|
93
|
+
theme.setFullscreen(true) // Hide navigation
|
|
94
|
+
theme.setFullscreen(false) // Show navigation
|
|
95
|
+
```
|
|
155
96
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
97
|
+
### `toggleFullscreen()`
|
|
98
|
+
Toggle fullscreen state.
|
|
99
|
+
```typescript
|
|
100
|
+
theme.toggleFullscreen()
|
|
101
|
+
```
|
|
161
102
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
103
|
+
### `next(values)`
|
|
104
|
+
Update multiple properties atomically.
|
|
105
|
+
```typescript
|
|
106
|
+
theme.next({
|
|
107
|
+
fullscreen: true,
|
|
108
|
+
scheme: 'dark',
|
|
109
|
+
color: '#6750A4'
|
|
110
|
+
})
|
|
111
|
+
```
|
|
165
112
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
--schmancy-
|
|
113
|
+
### `getCSSVariable(name)`
|
|
114
|
+
Get computed CSS variable value.
|
|
115
|
+
```typescript
|
|
116
|
+
const primary = theme.getCSSVariable('color-primary')
|
|
117
|
+
const elevation = theme.getCSSVariable('elevation-3')
|
|
118
|
+
// Returns computed value of --schmancy-{name}
|
|
119
|
+
```
|
|
172
120
|
|
|
173
|
-
|
|
121
|
+
### `watchCSSVariable(name)`
|
|
122
|
+
Watch CSS variable changes reactively.
|
|
123
|
+
```typescript
|
|
124
|
+
theme.watchCSSVariable('color-primary').subscribe(color => {
|
|
125
|
+
console.log('Primary changed:', color)
|
|
126
|
+
})
|
|
174
127
|
```
|
|
175
128
|
|
|
176
|
-
##
|
|
129
|
+
## Theme Controls Component
|
|
177
130
|
|
|
178
|
-
|
|
179
|
-
// Automatically detects system preference
|
|
180
|
-
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
131
|
+
Ready-to-use UI component for complete theme control:
|
|
181
132
|
|
|
182
|
-
|
|
183
|
-
|
|
133
|
+
```html
|
|
134
|
+
<schmancy-theme-controls
|
|
135
|
+
.customColors=${['#6750A4', '#0061A4', '#006E1C']}
|
|
136
|
+
></schmancy-theme-controls>
|
|
184
137
|
```
|
|
185
138
|
|
|
186
|
-
|
|
139
|
+
### Features
|
|
140
|
+
- **Color Picker**: Visual color selection with debounced input
|
|
141
|
+
- **Scheme Toggle**: Beautiful icons for light/dark/auto modes
|
|
142
|
+
- **Random Color**: Generate random theme colors
|
|
143
|
+
- **Custom Presets**: Define your own color palette
|
|
187
144
|
|
|
188
|
-
|
|
145
|
+
### Implementation Example
|
|
146
|
+
```typescript
|
|
147
|
+
import '@schmancy/theme-controls'
|
|
148
|
+
|
|
149
|
+
@customElement('my-settings')
|
|
150
|
+
export class MySettings extends $LitElement() {
|
|
151
|
+
private brandColors = [
|
|
152
|
+
'#6750A4', // Brand primary
|
|
153
|
+
'#0061A4', // Brand secondary
|
|
154
|
+
'#006E1C', // Brand success
|
|
155
|
+
'#BA1B1B' // Brand error
|
|
156
|
+
]
|
|
189
157
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
158
|
+
render() {
|
|
159
|
+
return html`
|
|
160
|
+
<schmancy-surface type="container" class="p-4">
|
|
161
|
+
<schmancy-typography type="title" token="medium">
|
|
162
|
+
Theme Settings
|
|
163
|
+
</schmancy-typography>
|
|
164
|
+
|
|
165
|
+
<schmancy-theme-controls
|
|
166
|
+
.customColors=${this.brandColors}
|
|
167
|
+
></schmancy-theme-controls>
|
|
168
|
+
</schmancy-surface>
|
|
169
|
+
`
|
|
170
|
+
}
|
|
194
171
|
}
|
|
195
172
|
```
|
|
196
173
|
|
|
197
|
-
##
|
|
198
|
-
|
|
199
|
-
The theme component provides its theme via Lit Context:
|
|
174
|
+
## Complete Material Design 3 Token System
|
|
200
175
|
|
|
201
|
-
|
|
202
|
-
import { consume } from '@lit/context';
|
|
203
|
-
import { themeContext } from '@schmancy/index';
|
|
204
|
-
// Or specific import: import { themeContext } from '@schmancy/index'
|
|
205
|
-
// Or specific import: import { themeContext } from '@schmancy/theme';
|
|
176
|
+
The theme service generates a COMPLETE M3 design system with hundreds of tokens:
|
|
206
177
|
|
|
207
|
-
|
|
208
|
-
@consume({ context: themeContext })
|
|
209
|
-
theme: TSchmancyTheme;
|
|
210
|
-
```
|
|
178
|
+
### Extended Color System
|
|
211
179
|
|
|
212
|
-
|
|
180
|
+
Beyond primary/secondary/tertiary/error, the theme includes:
|
|
213
181
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<schmancy-theme color="#F44336" scheme="dark">
|
|
221
|
-
<aside class="sidebar">
|
|
222
|
-
<!-- Red dark theme -->
|
|
223
|
-
</aside>
|
|
224
|
-
</schmancy-theme>
|
|
225
|
-
</div>
|
|
226
|
-
</schmancy-theme>
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Dynamic Theme Changes
|
|
230
|
-
```javascript
|
|
231
|
-
const themeEl = document.querySelector('schmancy-theme');
|
|
232
|
-
|
|
233
|
-
// Change color
|
|
234
|
-
themeEl.color = '#9C27B0';
|
|
182
|
+
```typescript
|
|
183
|
+
// Additional semantic colors
|
|
184
|
+
theme.theme.success // Success states (#006E1C base)
|
|
185
|
+
theme.theme.onSuccess // Text on success backgrounds
|
|
186
|
+
theme.theme.successContainer
|
|
187
|
+
theme.theme.onSuccessContainer
|
|
235
188
|
|
|
236
|
-
//
|
|
237
|
-
|
|
189
|
+
theme.theme.warning // Warning states (#FFB800 base)
|
|
190
|
+
theme.theme.onWarning
|
|
191
|
+
theme.theme.warningContainer
|
|
192
|
+
theme.theme.onWarningContainer
|
|
238
193
|
|
|
239
|
-
//
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
error: {
|
|
244
|
-
default: '#FF0000'
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
};
|
|
194
|
+
theme.theme.info // Info states (#0061A4 base)
|
|
195
|
+
theme.theme.onInfo
|
|
196
|
+
theme.theme.infoContainer
|
|
197
|
+
theme.theme.onInfoContainer
|
|
249
198
|
```
|
|
250
199
|
|
|
251
|
-
|
|
200
|
+
### Surface System
|
|
252
201
|
|
|
253
|
-
|
|
202
|
+
Complete surface hierarchy with proper elevation:
|
|
254
203
|
|
|
255
|
-
|
|
204
|
+
```typescript
|
|
205
|
+
// Base surfaces
|
|
206
|
+
theme.theme.surface // Default surface
|
|
207
|
+
theme.theme.surfaceDim // Dimmed surface
|
|
208
|
+
theme.theme.surfaceBright // Bright surface
|
|
256
209
|
|
|
257
|
-
|
|
258
|
-
|
|
210
|
+
// Container hierarchy
|
|
211
|
+
theme.theme.surfaceContainerLowest // Lowest elevation
|
|
212
|
+
theme.theme.surfaceContainerLow // Low elevation
|
|
213
|
+
theme.theme.surfaceContainer // Default container
|
|
214
|
+
theme.theme.surfaceContainerHigh // High elevation
|
|
215
|
+
theme.theme.surfaceContainerHighest // Highest elevation
|
|
259
216
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
217
|
+
// Fixed color variants (don't change with theme)
|
|
218
|
+
theme.theme.primaryFixed // Fixed primary
|
|
219
|
+
theme.theme.primaryFixedDim // Dimmed fixed primary
|
|
220
|
+
theme.theme.onPrimaryFixed // Text on fixed primary
|
|
221
|
+
theme.theme.onPrimaryFixedVariant
|
|
222
|
+
// (Same for secondary, tertiary)
|
|
265
223
|
```
|
|
266
224
|
|
|
267
|
-
|
|
268
|
-
|
|
225
|
+
### Typography System
|
|
226
|
+
|
|
227
|
+
Complete type scale with three axes:
|
|
269
228
|
|
|
270
229
|
```typescript
|
|
271
|
-
//
|
|
272
|
-
|
|
230
|
+
// Display - Largest, for hero text
|
|
231
|
+
theme.theme.typeface.scale.display.large // 57px
|
|
232
|
+
theme.theme.typeface.scale.display.medium // 45px
|
|
233
|
+
theme.theme.typeface.scale.display.small // 36px
|
|
273
234
|
|
|
274
|
-
//
|
|
275
|
-
|
|
235
|
+
// Headline - For section headers
|
|
236
|
+
theme.theme.typeface.scale.headline.large // 32px
|
|
237
|
+
theme.theme.typeface.scale.headline.medium // 28px
|
|
238
|
+
theme.theme.typeface.scale.headline.small // 24px
|
|
276
239
|
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
|
|
240
|
+
// Title - For cards and lists
|
|
241
|
+
theme.theme.typeface.scale.title.large // 22px
|
|
242
|
+
theme.theme.typeface.scale.title.medium // 16px
|
|
243
|
+
theme.theme.typeface.scale.title.small // 14px
|
|
280
244
|
|
|
281
|
-
|
|
282
|
-
|
|
245
|
+
// Body - For content
|
|
246
|
+
theme.theme.typeface.scale.body.large // 16px
|
|
247
|
+
theme.theme.typeface.scale.body.medium // 14px
|
|
248
|
+
theme.theme.typeface.scale.body.small // 12px
|
|
283
249
|
|
|
284
|
-
|
|
285
|
-
|
|
250
|
+
// Label - For UI elements
|
|
251
|
+
theme.theme.typeface.scale.label.large // 14px
|
|
252
|
+
theme.theme.typeface.scale.label.medium // 12px
|
|
253
|
+
theme.theme.typeface.scale.label.small // 11px
|
|
286
254
|
```
|
|
287
255
|
|
|
288
|
-
|
|
289
|
-
Sets the complete theme configuration at once.
|
|
256
|
+
### Motion System
|
|
290
257
|
|
|
291
|
-
|
|
292
|
-
themeService.setTheme({
|
|
293
|
-
mode: 'dark',
|
|
294
|
-
primaryColor: '#00897B',
|
|
295
|
-
fontFamily: 'Roboto',
|
|
296
|
-
borderRadius: 'medium'
|
|
297
|
-
})
|
|
298
|
-
```
|
|
258
|
+
Sophisticated animation tokens:
|
|
299
259
|
|
|
300
|
-
|
|
301
|
-
|
|
260
|
+
```typescript
|
|
261
|
+
// Easing curves
|
|
262
|
+
theme.theme.motion.easing.emphasized // Expressive motion
|
|
263
|
+
theme.theme.motion.easing.emphasizedDecelerate // Enter animations
|
|
264
|
+
theme.theme.motion.easing.emphasizedAccelerate // Exit animations
|
|
265
|
+
theme.theme.motion.easing.standard // Standard transitions
|
|
266
|
+
theme.theme.motion.easing.standardDecelerate
|
|
267
|
+
theme.theme.motion.easing.standardAccelerate
|
|
268
|
+
theme.theme.motion.easing.legacy // Backward compatibility
|
|
269
|
+
theme.theme.motion.easing.linear // Constant speed
|
|
270
|
+
|
|
271
|
+
// Duration scales (in ms)
|
|
272
|
+
theme.theme.motion.duration.short1 // 50ms - Micro interactions
|
|
273
|
+
theme.theme.motion.duration.short2 // 100ms
|
|
274
|
+
theme.theme.motion.duration.short3 // 150ms
|
|
275
|
+
theme.theme.motion.duration.short4 // 200ms
|
|
276
|
+
|
|
277
|
+
theme.theme.motion.duration.medium1 // 250ms - Standard transitions
|
|
278
|
+
theme.theme.motion.duration.medium2 // 300ms
|
|
279
|
+
theme.theme.motion.duration.medium3 // 350ms
|
|
280
|
+
theme.theme.motion.duration.medium4 // 400ms
|
|
281
|
+
|
|
282
|
+
theme.theme.motion.duration.long1 // 450ms - Complex animations
|
|
283
|
+
theme.theme.motion.duration.long2 // 500ms
|
|
284
|
+
theme.theme.motion.duration.long3 // 550ms
|
|
285
|
+
theme.theme.motion.duration.long4 // 600ms
|
|
286
|
+
|
|
287
|
+
theme.theme.motion.duration.extraLong1 // 700ms - Dramatic effects
|
|
288
|
+
theme.theme.motion.duration.extraLong2 // 800ms
|
|
289
|
+
theme.theme.motion.duration.extraLong3 // 900ms
|
|
290
|
+
theme.theme.motion.duration.extraLong4 // 1000ms
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Shape System
|
|
294
|
+
|
|
295
|
+
Corner radius tokens:
|
|
302
296
|
|
|
303
297
|
```typescript
|
|
304
|
-
|
|
298
|
+
theme.theme.shape.corner.none // 0px
|
|
299
|
+
theme.theme.shape.corner.extraSmall // 4px
|
|
300
|
+
theme.theme.shape.corner.small // 8px
|
|
301
|
+
theme.theme.shape.corner.medium // 12px
|
|
302
|
+
theme.theme.shape.corner.large // 16px
|
|
303
|
+
theme.theme.shape.corner.extraLarge // 28px
|
|
304
|
+
theme.theme.shape.corner.full // 9999px (pill shape)
|
|
305
305
|
```
|
|
306
306
|
|
|
307
|
-
###
|
|
307
|
+
### Elevation System
|
|
308
308
|
|
|
309
|
-
|
|
309
|
+
Elevation with tinted shadows in dark mode:
|
|
310
310
|
|
|
311
|
-
#### `theme$` - Complete Theme State
|
|
312
311
|
```typescript
|
|
313
|
-
|
|
312
|
+
theme.theme.elevation.level0 // Flat
|
|
313
|
+
theme.theme.elevation.level1 // Cards
|
|
314
|
+
theme.theme.elevation.level2 // Raised cards
|
|
315
|
+
theme.theme.elevation.level3 // Floating action buttons
|
|
316
|
+
theme.theme.elevation.level4 // Dialogs
|
|
317
|
+
theme.theme.elevation.level5 // Highest elevation
|
|
314
318
|
|
|
315
|
-
|
|
316
|
-
.pipe(takeUntil(this.disconnecting))
|
|
317
|
-
.subscribe(theme => {
|
|
318
|
-
console.log('Theme updated:', theme)
|
|
319
|
-
// theme.mode, theme.primaryColor, theme.isDark, etc.
|
|
320
|
-
})
|
|
319
|
+
// In dark mode, shadows are tinted with primary color
|
|
321
320
|
```
|
|
322
321
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
.pipe(takeUntil(this.disconnecting))
|
|
327
|
-
.subscribe(mode => {
|
|
328
|
-
console.log('Mode changed to:', mode)
|
|
329
|
-
})
|
|
330
|
-
```
|
|
322
|
+
### State Layer Opacities
|
|
323
|
+
|
|
324
|
+
Interaction state opacities:
|
|
331
325
|
|
|
332
|
-
#### `primaryColor$` - Color Changes Only
|
|
333
326
|
```typescript
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
.
|
|
337
|
-
|
|
338
|
-
|
|
327
|
+
theme.theme.states.hover.stateLayerOpacity // 0.08
|
|
328
|
+
theme.theme.states.focus.stateLayerOpacity // 0.1
|
|
329
|
+
theme.theme.states.pressed.stateLayerOpacity // 0.1
|
|
330
|
+
theme.theme.states.dragged.stateLayerOpacity // 0.15
|
|
331
|
+
theme.theme.states.disabled.containerOpacity // 0.12
|
|
332
|
+
theme.theme.states.disabled.contentOpacity // 0.38
|
|
339
333
|
```
|
|
340
334
|
|
|
341
|
-
###
|
|
335
|
+
### Spacing System
|
|
342
336
|
|
|
343
|
-
|
|
337
|
+
4dp grid spacing:
|
|
344
338
|
|
|
345
339
|
```typescript
|
|
346
|
-
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
//
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
<div>Primary: ${this.theme.primaryColor}</div>
|
|
360
|
-
`
|
|
361
|
-
}
|
|
362
|
-
}
|
|
340
|
+
theme.theme.spacing.size.none // 0px
|
|
341
|
+
theme.theme.spacing.size.s1 // 4px
|
|
342
|
+
theme.theme.spacing.size.s2 // 8px
|
|
343
|
+
theme.theme.spacing.size.s3 // 12px
|
|
344
|
+
theme.theme.spacing.size.s4 // 16px
|
|
345
|
+
theme.theme.spacing.size.s5 // 20px
|
|
346
|
+
theme.theme.spacing.size.s6 // 24px
|
|
347
|
+
theme.theme.spacing.size.s7 // 28px
|
|
348
|
+
theme.theme.spacing.size.s8 // 32px
|
|
349
|
+
theme.theme.spacing.size.s9 // 36px
|
|
350
|
+
theme.theme.spacing.size.s10 // 40px
|
|
351
|
+
theme.theme.spacing.size.s11 // 44px
|
|
352
|
+
theme.theme.spacing.size.s12 // 48px
|
|
363
353
|
```
|
|
364
354
|
|
|
365
|
-
|
|
355
|
+
## State Management & Persistence
|
|
356
|
+
|
|
357
|
+
The theme service uses a **persistent context** that automatically saves to localStorage:
|
|
366
358
|
|
|
367
|
-
#### Theme Toggle Button
|
|
368
359
|
```typescript
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
@state() private currentMode: 'light' | 'dark' | 'auto' = 'auto'
|
|
360
|
+
// No manual localStorage code needed!
|
|
361
|
+
// Settings persist automatically via context
|
|
372
362
|
|
|
373
|
-
|
|
374
|
-
|
|
363
|
+
// The context key 'schmancy-theme-settings' stores:
|
|
364
|
+
// - scheme: 'dark' | 'light' | 'auto'
|
|
365
|
+
// - color: hex color string
|
|
375
366
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
this.currentMode = mode
|
|
380
|
-
})
|
|
381
|
-
}
|
|
367
|
+
// Automatic restoration on page load
|
|
368
|
+
// Just use the service - persistence is handled
|
|
369
|
+
```
|
|
382
370
|
|
|
383
|
-
|
|
384
|
-
const modes: Array<'light' | 'dark' | 'auto'> = ['light', 'dark', 'auto']
|
|
385
|
-
const currentIndex = modes.indexOf(this.currentMode)
|
|
386
|
-
const nextMode = modes[(currentIndex + 1) % modes.length]
|
|
387
|
-
themeService.setMode(nextMode)
|
|
388
|
-
}
|
|
371
|
+
## Theme Discovery Pattern
|
|
389
372
|
|
|
390
|
-
|
|
391
|
-
const icon = this.currentMode === 'light' ? 'light_mode' :
|
|
392
|
-
this.currentMode === 'dark' ? 'dark_mode' : 'brightness_auto'
|
|
373
|
+
The service uses a sophisticated bidirectional event system:
|
|
393
374
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
375
|
+
```typescript
|
|
376
|
+
// Service dispatches discovery event
|
|
377
|
+
dispatchEvent(new CustomEvent('ThemeWhereAreYou'))
|
|
378
|
+
|
|
379
|
+
// Theme component responds
|
|
380
|
+
dispatchEvent(new CustomEvent('ThemeHereIAm', {
|
|
381
|
+
detail: themeComponent
|
|
382
|
+
}))
|
|
383
|
+
|
|
384
|
+
// Automatic registration with timeout
|
|
385
|
+
theme.discoverTheme().pipe(
|
|
386
|
+
timeout(1000), // 1 second timeout
|
|
387
|
+
catchError(() => of(null))
|
|
388
|
+
).subscribe(component => {
|
|
389
|
+
if (component) {
|
|
390
|
+
console.log('Theme component found and registered')
|
|
400
391
|
}
|
|
401
|
-
}
|
|
392
|
+
})
|
|
402
393
|
```
|
|
403
394
|
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
@customElement('color-picker')
|
|
407
|
-
export class ColorPicker extends LitElement {
|
|
408
|
-
@state() private selectedColor = '#6750A4'
|
|
395
|
+
## Advanced Patterns
|
|
409
396
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
]
|
|
397
|
+
### Activity Logging for Debugging
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
@customElement('theme-debugger')
|
|
401
|
+
export class ThemeDebugger extends $LitElement() {
|
|
402
|
+
@state() private activities: string[] = []
|
|
417
403
|
|
|
418
404
|
connectedCallback() {
|
|
419
405
|
super.connectedCallback()
|
|
420
406
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
.
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
407
|
+
// Log all theme changes
|
|
408
|
+
combineLatest([
|
|
409
|
+
theme.scheme$,
|
|
410
|
+
theme.color$,
|
|
411
|
+
theme.fullscreen$
|
|
412
|
+
]).pipe(
|
|
413
|
+
tap(([scheme, color, fullscreen]) => {
|
|
414
|
+
const activity = `[${new Date().toLocaleTimeString()}] ` +
|
|
415
|
+
`Scheme: ${scheme}, Color: ${color}, Fullscreen: ${fullscreen}`
|
|
416
|
+
this.activities = [...this.activities, activity].slice(-10)
|
|
417
|
+
}),
|
|
418
|
+
takeUntil(this.disconnecting)
|
|
419
|
+
).subscribe()
|
|
430
420
|
}
|
|
431
421
|
|
|
432
422
|
render() {
|
|
433
423
|
return html`
|
|
434
|
-
<div class="
|
|
435
|
-
${this.
|
|
436
|
-
<button
|
|
437
|
-
@click=${() => this.selectColor(color.value)}
|
|
438
|
-
style="background-color: ${color.value}"
|
|
439
|
-
class="w-10 h-10 rounded-full border-2 transition-all ${
|
|
440
|
-
this.selectedColor === color.value ?
|
|
441
|
-
'border-white shadow-lg scale-110' :
|
|
442
|
-
'border-transparent'
|
|
443
|
-
}"
|
|
444
|
-
title=${color.name}
|
|
445
|
-
></button>
|
|
446
|
-
`)}
|
|
424
|
+
<div class="font-mono text-xs">
|
|
425
|
+
${this.activities.map(a => html`<div>${a}</div>`)}
|
|
447
426
|
</div>
|
|
448
427
|
`
|
|
449
428
|
}
|
|
450
429
|
}
|
|
451
430
|
```
|
|
452
431
|
|
|
453
|
-
|
|
454
|
-
```typescript
|
|
455
|
-
import { debounceTime } from 'rxjs'
|
|
432
|
+
### Custom Color Presets with Categories
|
|
456
433
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
434
|
+
```typescript
|
|
435
|
+
interface ColorPreset {
|
|
436
|
+
category: string
|
|
437
|
+
colors: Array<{ name: string; value: string }>
|
|
438
|
+
}
|
|
462
439
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
440
|
+
const presets: ColorPreset[] = [
|
|
441
|
+
{
|
|
442
|
+
category: 'Brand',
|
|
443
|
+
colors: [
|
|
444
|
+
{ name: 'Primary', value: '#6750A4' },
|
|
445
|
+
{ name: 'Secondary', value: '#625B71' }
|
|
446
|
+
]
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
category: 'Semantic',
|
|
450
|
+
colors: [
|
|
451
|
+
{ name: 'Success', value: '#006E1C' },
|
|
452
|
+
{ name: 'Warning', value: '#FFB800' },
|
|
453
|
+
{ name: 'Error', value: '#BA1B1B' },
|
|
454
|
+
{ name: 'Info', value: '#0061A4' }
|
|
455
|
+
]
|
|
471
456
|
}
|
|
457
|
+
]
|
|
458
|
+
|
|
459
|
+
// Use in component
|
|
460
|
+
html`
|
|
461
|
+
${presets.map(preset => html`
|
|
462
|
+
<div>
|
|
463
|
+
<h3>${preset.category}</h3>
|
|
464
|
+
${preset.colors.map(color => html`
|
|
465
|
+
<button
|
|
466
|
+
style="background: ${color.value}"
|
|
467
|
+
@click=${() => theme.setColor(color.value)}
|
|
468
|
+
title=${color.name}
|
|
469
|
+
></button>
|
|
470
|
+
`)}
|
|
471
|
+
</div>
|
|
472
|
+
`)}
|
|
473
|
+
`
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Animated Theme Transitions
|
|
472
477
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
console.error('Failed to load saved theme', e)
|
|
481
|
-
}
|
|
482
|
-
}
|
|
478
|
+
```typescript
|
|
479
|
+
@customElement('smooth-theme')
|
|
480
|
+
export class SmoothTheme extends $LitElement(css`
|
|
481
|
+
:host {
|
|
482
|
+
transition: background-color
|
|
483
|
+
var(--schmancy-motion-duration-medium2)
|
|
484
|
+
var(--schmancy-motion-easing-standard);
|
|
483
485
|
}
|
|
486
|
+
`) {
|
|
487
|
+
connectedCallback() {
|
|
488
|
+
super.connectedCallback()
|
|
484
489
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
+
// Apply smooth transitions using motion tokens
|
|
491
|
+
theme.resolvedScheme$.pipe(
|
|
492
|
+
tap(() => {
|
|
493
|
+
// Background transitions automatically via CSS variables
|
|
494
|
+
this.style.setProperty('background-color',
|
|
495
|
+
'var(--schmancy-color-surface)')
|
|
496
|
+
}),
|
|
497
|
+
takeUntil(this.disconnecting)
|
|
498
|
+
).subscribe()
|
|
490
499
|
}
|
|
491
500
|
}
|
|
492
|
-
|
|
493
|
-
// Initialize once in your app
|
|
494
|
-
new ThemePersistence()
|
|
495
501
|
```
|
|
496
502
|
|
|
497
|
-
|
|
498
|
-
```typescript
|
|
499
|
-
@customElement('system-aware')
|
|
500
|
-
export class SystemAware extends LitElement {
|
|
501
|
-
@state() private isDark = false
|
|
502
|
-
@state() private isAuto = false
|
|
503
|
+
### Responsive Theme Based on Time
|
|
503
504
|
|
|
505
|
+
```typescript
|
|
506
|
+
@customElement('time-aware-theme')
|
|
507
|
+
export class TimeAwareTheme extends $LitElement() {
|
|
504
508
|
connectedCallback() {
|
|
505
509
|
super.connectedCallback()
|
|
506
510
|
|
|
507
|
-
//
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
|
|
517
|
-
mediaQuery.addEventListener('change', (e) => {
|
|
518
|
-
if (this.isAuto) {
|
|
519
|
-
this.isDark = e.matches
|
|
520
|
-
}
|
|
521
|
-
})
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
render() {
|
|
525
|
-
return html`
|
|
526
|
-
<div class="p-4">
|
|
527
|
-
<p>Mode: ${this.isAuto ? 'Auto' : this.isDark ? 'Dark' : 'Light'}</p>
|
|
528
|
-
<p>System prefers: ${
|
|
529
|
-
window.matchMedia('(prefers-color-scheme: dark)').matches ?
|
|
530
|
-
'Dark' : 'Light'
|
|
531
|
-
}</p>
|
|
532
|
-
</div>
|
|
533
|
-
`
|
|
511
|
+
// Auto-switch theme based on time
|
|
512
|
+
interval(60000).pipe( // Check every minute
|
|
513
|
+
startWith(0),
|
|
514
|
+
map(() => new Date().getHours()),
|
|
515
|
+
map(hour => hour >= 6 && hour < 18 ? 'light' : 'dark'),
|
|
516
|
+
distinctUntilChanged(),
|
|
517
|
+
tap(scheme => theme.setScheme(scheme)),
|
|
518
|
+
takeUntil(this.disconnecting)
|
|
519
|
+
).subscribe()
|
|
534
520
|
}
|
|
535
521
|
}
|
|
536
522
|
```
|
|
537
523
|
|
|
538
|
-
|
|
524
|
+
### Theme-Aware Data Visualization
|
|
539
525
|
|
|
540
526
|
```typescript
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
}
|
|
527
|
+
@customElement('theme-chart')
|
|
528
|
+
export class ThemeChart extends $LitElement() {
|
|
529
|
+
@state() private chartColors = {
|
|
530
|
+
primary: '',
|
|
531
|
+
surface: '',
|
|
532
|
+
error: ''
|
|
533
|
+
}
|
|
548
534
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
isAuto: boolean
|
|
552
|
-
systemPreference: 'light' | 'dark'
|
|
553
|
-
theme: TSchmancyTheme // Full Material Design 3 theme object
|
|
554
|
-
}
|
|
535
|
+
connectedCallback() {
|
|
536
|
+
super.connectedCallback()
|
|
555
537
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
538
|
+
// Update chart colors when theme changes
|
|
539
|
+
theme.theme$.pipe(
|
|
540
|
+
tap(themeData => {
|
|
541
|
+
this.chartColors = {
|
|
542
|
+
primary: themeData.primary,
|
|
543
|
+
surface: themeData.surface,
|
|
544
|
+
error: themeData.error
|
|
545
|
+
}
|
|
546
|
+
this.updateChart()
|
|
547
|
+
}),
|
|
548
|
+
takeUntil(this.disconnecting)
|
|
549
|
+
).subscribe()
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
private updateChart() {
|
|
553
|
+
// Use theme colors in charts/visualizations
|
|
554
|
+
// Colors automatically adapt to light/dark mode
|
|
555
|
+
}
|
|
568
556
|
}
|
|
569
557
|
```
|
|
570
558
|
|
|
571
|
-
##
|
|
572
|
-
|
|
573
|
-
1. **Root Theme**: Use one root theme for consistency
|
|
574
|
-
2. **Color Choice**: Pick colors with good contrast ratios
|
|
575
|
-
3. **Scheme Handling**: Respect user preferences with 'auto'
|
|
576
|
-
4. **Performance**: Limit nested themes, debounce theme changes
|
|
577
|
-
5. **Accessibility**: Test themes with contrast checkers
|
|
578
|
-
6. **Persistence**: Save user preferences to localStorage
|
|
579
|
-
7. **Cleanup**: Always use `takeUntil(this.disconnecting)` in components
|
|
580
|
-
8. **Type Safety**: Use provided TypeScript interfaces
|
|
559
|
+
## Complete CSS Variable Reference
|
|
581
560
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
### Using Theme Variables in Styles
|
|
561
|
+
All tokens are available as CSS variables with `--schmancy-` prefix:
|
|
585
562
|
|
|
563
|
+
### Color Variables
|
|
564
|
+
```css
|
|
565
|
+
/* Core colors */
|
|
566
|
+
--schmancy-color-primary
|
|
567
|
+
--schmancy-color-onPrimary
|
|
568
|
+
--schmancy-color-primaryContainer
|
|
569
|
+
--schmancy-color-onPrimaryContainer
|
|
570
|
+
|
|
571
|
+
--schmancy-color-secondary
|
|
572
|
+
--schmancy-color-onSecondary
|
|
573
|
+
--schmancy-color-secondaryContainer
|
|
574
|
+
--schmancy-color-onSecondaryContainer
|
|
575
|
+
|
|
576
|
+
--schmancy-color-tertiary
|
|
577
|
+
--schmancy-color-onTertiary
|
|
578
|
+
--schmancy-color-tertiaryContainer
|
|
579
|
+
--schmancy-color-onTertiaryContainer
|
|
580
|
+
|
|
581
|
+
--schmancy-color-error
|
|
582
|
+
--schmancy-color-onError
|
|
583
|
+
--schmancy-color-errorContainer
|
|
584
|
+
--schmancy-color-onErrorContainer
|
|
585
|
+
|
|
586
|
+
/* Extended semantic colors */
|
|
587
|
+
--schmancy-color-success
|
|
588
|
+
--schmancy-color-onSuccess
|
|
589
|
+
--schmancy-color-successContainer
|
|
590
|
+
--schmancy-color-onSuccessContainer
|
|
591
|
+
|
|
592
|
+
--schmancy-color-warning
|
|
593
|
+
--schmancy-color-onWarning
|
|
594
|
+
--schmancy-color-warningContainer
|
|
595
|
+
--schmancy-color-onWarningContainer
|
|
596
|
+
|
|
597
|
+
--schmancy-color-info
|
|
598
|
+
--schmancy-color-onInfo
|
|
599
|
+
--schmancy-color-infoContainer
|
|
600
|
+
--schmancy-color-onInfoContainer
|
|
601
|
+
|
|
602
|
+
/* Surface hierarchy */
|
|
603
|
+
--schmancy-color-surface
|
|
604
|
+
--schmancy-color-onSurface
|
|
605
|
+
--schmancy-color-surfaceVariant
|
|
606
|
+
--schmancy-color-onSurfaceVariant
|
|
607
|
+
--schmancy-color-surfaceDim
|
|
608
|
+
--schmancy-color-surfaceBright
|
|
609
|
+
--schmancy-color-surfaceContainerLowest
|
|
610
|
+
--schmancy-color-surfaceContainerLow
|
|
611
|
+
--schmancy-color-surfaceContainer
|
|
612
|
+
--schmancy-color-surfaceContainerHigh
|
|
613
|
+
--schmancy-color-surfaceContainerHighest
|
|
614
|
+
|
|
615
|
+
/* Fixed variants */
|
|
616
|
+
--schmancy-color-primaryFixed
|
|
617
|
+
--schmancy-color-primaryFixedDim
|
|
618
|
+
--schmancy-color-onPrimaryFixed
|
|
619
|
+
--schmancy-color-onPrimaryFixedVariant
|
|
620
|
+
/* (Same pattern for secondary, tertiary) */
|
|
621
|
+
|
|
622
|
+
/* Other */
|
|
623
|
+
--schmancy-color-outline
|
|
624
|
+
--schmancy-color-outlineVariant
|
|
625
|
+
--schmancy-color-shadow
|
|
626
|
+
--schmancy-color-scrim
|
|
627
|
+
--schmancy-color-inverseSurface
|
|
628
|
+
--schmancy-color-inverseOnSurface
|
|
629
|
+
--schmancy-color-inversePrimary
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Typography Variables
|
|
586
633
|
```css
|
|
587
|
-
/*
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
634
|
+
/* Display scale */
|
|
635
|
+
--schmancy-typeface-scale-display-large
|
|
636
|
+
--schmancy-typeface-scale-display-medium
|
|
637
|
+
--schmancy-typeface-scale-display-small
|
|
591
638
|
|
|
592
|
-
|
|
593
|
-
|
|
639
|
+
/* Headline scale */
|
|
640
|
+
--schmancy-typeface-scale-headline-large
|
|
641
|
+
--schmancy-typeface-scale-headline-medium
|
|
642
|
+
--schmancy-typeface-scale-headline-small
|
|
594
643
|
|
|
595
|
-
|
|
596
|
-
|
|
644
|
+
/* Title scale */
|
|
645
|
+
--schmancy-typeface-scale-title-large
|
|
646
|
+
--schmancy-typeface-scale-title-medium
|
|
647
|
+
--schmancy-typeface-scale-title-small
|
|
597
648
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
649
|
+
/* Body scale */
|
|
650
|
+
--schmancy-typeface-scale-body-large
|
|
651
|
+
--schmancy-typeface-scale-body-medium
|
|
652
|
+
--schmancy-typeface-scale-body-small
|
|
601
653
|
|
|
602
|
-
/*
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
.error-message {
|
|
609
|
-
background: var(--schmancy-sys-color-error-container);
|
|
610
|
-
color: var(--schmancy-sys-color-error-onContainer);
|
|
611
|
-
}
|
|
654
|
+
/* Label scale */
|
|
655
|
+
--schmancy-typeface-scale-label-large
|
|
656
|
+
--schmancy-typeface-scale-label-medium
|
|
657
|
+
--schmancy-typeface-scale-label-small
|
|
612
658
|
```
|
|
613
659
|
|
|
614
|
-
###
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
660
|
+
### Motion Variables
|
|
661
|
+
```css
|
|
662
|
+
/* Easing curves */
|
|
663
|
+
--schmancy-motion-easing-emphasized
|
|
664
|
+
--schmancy-motion-easing-emphasizedDecelerate
|
|
665
|
+
--schmancy-motion-easing-emphasizedAccelerate
|
|
666
|
+
--schmancy-motion-easing-standard
|
|
667
|
+
--schmancy-motion-easing-standardDecelerate
|
|
668
|
+
--schmancy-motion-easing-standardAccelerate
|
|
669
|
+
--schmancy-motion-easing-legacy
|
|
670
|
+
--schmancy-motion-easing-linear
|
|
671
|
+
|
|
672
|
+
/* Duration scales */
|
|
673
|
+
--schmancy-motion-duration-short1 /* 50ms */
|
|
674
|
+
--schmancy-motion-duration-short2 /* 100ms */
|
|
675
|
+
--schmancy-motion-duration-short3 /* 150ms */
|
|
676
|
+
--schmancy-motion-duration-short4 /* 200ms */
|
|
677
|
+
|
|
678
|
+
--schmancy-motion-duration-medium1 /* 250ms */
|
|
679
|
+
--schmancy-motion-duration-medium2 /* 300ms */
|
|
680
|
+
--schmancy-motion-duration-medium3 /* 350ms */
|
|
681
|
+
--schmancy-motion-duration-medium4 /* 400ms */
|
|
682
|
+
|
|
683
|
+
--schmancy-motion-duration-long1 /* 450ms */
|
|
684
|
+
--schmancy-motion-duration-long2 /* 500ms */
|
|
685
|
+
--schmancy-motion-duration-long3 /* 550ms */
|
|
686
|
+
--schmancy-motion-duration-long4 /* 600ms */
|
|
687
|
+
|
|
688
|
+
--schmancy-motion-duration-extraLong1 /* 700ms */
|
|
689
|
+
--schmancy-motion-duration-extraLong2 /* 800ms */
|
|
690
|
+
--schmancy-motion-duration-extraLong3 /* 900ms */
|
|
691
|
+
--schmancy-motion-duration-extraLong4 /* 1000ms */
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
### Shape Variables
|
|
695
|
+
```css
|
|
696
|
+
--schmancy-shape-corner-none /* 0px */
|
|
697
|
+
--schmancy-shape-corner-extraSmall /* 4px */
|
|
698
|
+
--schmancy-shape-corner-small /* 8px */
|
|
699
|
+
--schmancy-shape-corner-medium /* 12px */
|
|
700
|
+
--schmancy-shape-corner-large /* 16px */
|
|
701
|
+
--schmancy-shape-corner-extraLarge /* 28px */
|
|
702
|
+
--schmancy-shape-corner-full /* 9999px */
|
|
703
|
+
```
|
|
656
704
|
|
|
657
|
-
###
|
|
705
|
+
### Elevation Variables
|
|
706
|
+
```css
|
|
707
|
+
--schmancy-elevation-level0
|
|
708
|
+
--schmancy-elevation-level1
|
|
709
|
+
--schmancy-elevation-level2
|
|
710
|
+
--schmancy-elevation-level3
|
|
711
|
+
--schmancy-elevation-level4
|
|
712
|
+
--schmancy-elevation-level5
|
|
713
|
+
```
|
|
658
714
|
|
|
715
|
+
### State Variables
|
|
659
716
|
```css
|
|
660
|
-
/*
|
|
661
|
-
.
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
717
|
+
--schmancy-states-hover-stateLayerOpacity /* 0.08 */
|
|
718
|
+
--schmancy-states-focus-stateLayerOpacity /* 0.1 */
|
|
719
|
+
--schmancy-states-pressed-stateLayerOpacity /* 0.1 */
|
|
720
|
+
--schmancy-states-dragged-stateLayerOpacity /* 0.15 */
|
|
721
|
+
--schmancy-states-disabled-containerOpacity /* 0.12 */
|
|
722
|
+
--schmancy-states-disabled-contentOpacity /* 0.38 */
|
|
723
|
+
```
|
|
666
724
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
725
|
+
### Spacing Variables
|
|
726
|
+
```css
|
|
727
|
+
--schmancy-spacing-size-none /* 0px */
|
|
728
|
+
--schmancy-spacing-size-s1 /* 4px */
|
|
729
|
+
--schmancy-spacing-size-s2 /* 8px */
|
|
730
|
+
--schmancy-spacing-size-s3 /* 12px */
|
|
731
|
+
--schmancy-spacing-size-s4 /* 16px */
|
|
732
|
+
--schmancy-spacing-size-s5 /* 20px */
|
|
733
|
+
--schmancy-spacing-size-s6 /* 24px */
|
|
734
|
+
--schmancy-spacing-size-s7 /* 28px */
|
|
735
|
+
--schmancy-spacing-size-s8 /* 32px */
|
|
736
|
+
--schmancy-spacing-size-s9 /* 36px */
|
|
737
|
+
--schmancy-spacing-size-s10 /* 40px */
|
|
738
|
+
--schmancy-spacing-size-s11 /* 44px */
|
|
739
|
+
--schmancy-spacing-size-s12 /* 48px */
|
|
673
740
|
```
|
|
674
741
|
|
|
675
|
-
|
|
742
|
+
## Fullscreen Integration
|
|
743
|
+
|
|
744
|
+
Navigation components automatically respond to fullscreen:
|
|
676
745
|
|
|
677
746
|
```typescript
|
|
678
|
-
//
|
|
679
|
-
|
|
680
|
-
card: {
|
|
681
|
-
backgroundColor: theme.colors.background,
|
|
682
|
-
color: theme.colors.text
|
|
683
|
-
}
|
|
684
|
-
}
|
|
747
|
+
// Enter fullscreen (hides navigation)
|
|
748
|
+
theme.setFullscreen(true)
|
|
685
749
|
|
|
686
|
-
//
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
750
|
+
// Custom component integration
|
|
751
|
+
fromEvent(window, 'fullscreen').pipe(
|
|
752
|
+
tap((e: CustomEvent) => {
|
|
753
|
+
this.hidden = e.detail
|
|
754
|
+
}),
|
|
755
|
+
takeUntil(this.disconnecting)
|
|
756
|
+
).subscribe()
|
|
693
757
|
```
|
|
694
758
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
```typescript
|
|
698
|
-
// Before - Manual dark mode handling
|
|
699
|
-
@state() isDark = false
|
|
759
|
+
## System Preference Detection
|
|
700
760
|
|
|
701
|
-
|
|
702
|
-
return html`
|
|
703
|
-
<div class=${this.isDark ? 'dark-theme' : 'light-theme'}>
|
|
704
|
-
<!-- content -->
|
|
705
|
-
</div>
|
|
706
|
-
`
|
|
707
|
-
}
|
|
761
|
+
Auto mode follows system preferences with automatic updates:
|
|
708
762
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
763
|
+
```typescript
|
|
764
|
+
// Set to auto - follows system preference
|
|
765
|
+
theme.setScheme('auto')
|
|
766
|
+
|
|
767
|
+
// resolvedScheme$ automatically updates when system changes
|
|
768
|
+
// Uses MediaQueryList with listeners for real-time updates
|
|
769
|
+
theme.resolvedScheme$.subscribe(scheme => {
|
|
770
|
+
// Always 'dark' or 'light', never 'auto'
|
|
771
|
+
// Updates immediately when user changes OS theme
|
|
772
|
+
})
|
|
718
773
|
```
|
|
719
774
|
|
|
720
|
-
##
|
|
775
|
+
## Best Practices
|
|
721
776
|
|
|
722
|
-
|
|
777
|
+
1. **Always use observables** for reactive updates
|
|
778
|
+
2. **Prefer `resolvedScheme$`** over `scheme$` for UI logic (never returns 'auto')
|
|
779
|
+
3. **Use `next()` method** for batch updates to avoid multiple emissions
|
|
780
|
+
4. **Let theme persist automatically** - no manual localStorage needed
|
|
781
|
+
5. **Use motion tokens** for consistent animations across the app
|
|
782
|
+
6. **Leverage extended colors** (success, warning, info) for semantic meaning
|
|
783
|
+
7. **Use surface hierarchy** for proper elevation and depth
|
|
784
|
+
8. **Apply state opacities** for consistent interaction feedback
|
|
785
|
+
9. **Call `super.connectedCallback()`** when subscribing to observables
|
|
786
|
+
10. **Use `takeUntil(this.disconnecting)`** for proper cleanup
|
|
723
787
|
|
|
724
|
-
|
|
725
|
-
@customElement('themed-card')
|
|
726
|
-
export class ThemedCard extends LitElement {
|
|
727
|
-
@select(themeContext) theme!: ThemeState
|
|
788
|
+
## Common Patterns
|
|
728
789
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
padding: 16px;
|
|
736
|
-
transition: all 200ms ease-in-out;
|
|
737
|
-
}
|
|
790
|
+
### Complete Theme Toggle Component
|
|
791
|
+
```typescript
|
|
792
|
+
@customElement('advanced-theme-toggle')
|
|
793
|
+
export class AdvancedThemeToggle extends $LitElement() {
|
|
794
|
+
@state() private resolvedScheme: 'dark' | 'light' = 'light'
|
|
795
|
+
@state() private actualScheme: string = 'auto'
|
|
738
796
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
}
|
|
797
|
+
connectedCallback() {
|
|
798
|
+
super.connectedCallback()
|
|
742
799
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
800
|
+
// Track both actual and resolved scheme
|
|
801
|
+
combineLatest([
|
|
802
|
+
theme.scheme$,
|
|
803
|
+
theme.resolvedScheme$
|
|
804
|
+
]).pipe(
|
|
805
|
+
tap(([scheme, resolved]) => {
|
|
806
|
+
this.actualScheme = scheme
|
|
807
|
+
this.resolvedScheme = resolved
|
|
808
|
+
}),
|
|
809
|
+
takeUntil(this.disconnecting)
|
|
810
|
+
).subscribe()
|
|
811
|
+
}
|
|
748
812
|
|
|
749
813
|
render() {
|
|
750
814
|
return html`
|
|
751
|
-
<div class="
|
|
752
|
-
<
|
|
815
|
+
<div class="flex gap-2">
|
|
816
|
+
<button
|
|
817
|
+
@click=${() => theme.setScheme('light')}
|
|
818
|
+
class=${this.actualScheme === 'light' ? 'active' : ''}
|
|
819
|
+
>
|
|
820
|
+
☀️ Light
|
|
821
|
+
</button>
|
|
822
|
+
<button
|
|
823
|
+
@click=${() => theme.setScheme('dark')}
|
|
824
|
+
class=${this.actualScheme === 'dark' ? 'active' : ''}
|
|
825
|
+
>
|
|
826
|
+
🌙 Dark
|
|
827
|
+
</button>
|
|
828
|
+
<button
|
|
829
|
+
@click=${() => theme.setScheme('auto')}
|
|
830
|
+
class=${this.actualScheme === 'auto' ? 'active' : ''}
|
|
831
|
+
>
|
|
832
|
+
🔄 Auto (${this.resolvedScheme})
|
|
833
|
+
</button>
|
|
753
834
|
</div>
|
|
754
|
-
<slot></slot>
|
|
755
835
|
`
|
|
756
836
|
}
|
|
757
837
|
}
|
|
758
838
|
```
|
|
759
839
|
|
|
760
|
-
###
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
class
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
borderRadius: 'small'
|
|
770
|
-
},
|
|
771
|
-
|
|
772
|
-
vibrant: {
|
|
773
|
-
mode: 'auto' as const,
|
|
774
|
-
primaryColor: '#FF6B6B',
|
|
775
|
-
fontFamily: 'Poppins, sans-serif',
|
|
776
|
-
borderRadius: 'large'
|
|
777
|
-
},
|
|
778
|
-
|
|
779
|
-
minimal: {
|
|
780
|
-
mode: 'auto' as const,
|
|
781
|
-
primaryColor: '#2C3E50',
|
|
782
|
-
fontFamily: 'system-ui',
|
|
783
|
-
borderRadius: 'none'
|
|
784
|
-
},
|
|
785
|
-
|
|
786
|
-
accessibility: {
|
|
787
|
-
mode: 'light' as const,
|
|
788
|
-
primaryColor: '#0055AA',
|
|
789
|
-
contrast: 'high',
|
|
790
|
-
fontFamily: 'Arial, sans-serif',
|
|
791
|
-
borderRadius: 'medium'
|
|
792
|
-
}
|
|
840
|
+
### Fullscreen Video Player
|
|
841
|
+
```typescript
|
|
842
|
+
@customElement('video-player')
|
|
843
|
+
export class VideoPlayer extends $LitElement() {
|
|
844
|
+
private videoRef = createRef<HTMLVideoElement>()
|
|
845
|
+
|
|
846
|
+
private enterFullscreen() {
|
|
847
|
+
theme.setFullscreen(true)
|
|
848
|
+
this.videoRef.value?.requestFullscreen()
|
|
793
849
|
}
|
|
794
850
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
851
|
+
private exitFullscreen() {
|
|
852
|
+
theme.setFullscreen(false)
|
|
853
|
+
document.exitFullscreen()
|
|
798
854
|
}
|
|
799
|
-
}
|
|
800
855
|
|
|
801
|
-
|
|
802
|
-
|
|
856
|
+
render() {
|
|
857
|
+
return html`
|
|
858
|
+
<video ${ref(this.videoRef)}>
|
|
859
|
+
<!-- Video content -->
|
|
860
|
+
</video>
|
|
861
|
+
`
|
|
862
|
+
}
|
|
863
|
+
}
|
|
803
864
|
```
|
|
804
865
|
|
|
805
|
-
###
|
|
806
|
-
|
|
866
|
+
### Dynamic Motion Timing
|
|
807
867
|
```typescript
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
primaryColor: '#6750A4',
|
|
812
|
-
logo: '/assets/main-logo.svg'
|
|
813
|
-
},
|
|
814
|
-
partner: {
|
|
815
|
-
primaryColor: '#00897B',
|
|
816
|
-
logo: '/assets/partner-logo.svg'
|
|
817
|
-
}
|
|
818
|
-
}
|
|
868
|
+
@customElement('animated-component')
|
|
869
|
+
export class AnimatedComponent extends $LitElement() {
|
|
870
|
+
@state() private isExpanded = false
|
|
819
871
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
872
|
+
render() {
|
|
873
|
+
return html`
|
|
874
|
+
<style>
|
|
875
|
+
.panel {
|
|
876
|
+
transition: height
|
|
877
|
+
var(--schmancy-motion-duration-medium2)
|
|
878
|
+
var(--schmancy-motion-easing-emphasized);
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
.fade-in {
|
|
882
|
+
animation: fadeIn
|
|
883
|
+
var(--schmancy-motion-duration-short3)
|
|
884
|
+
var(--schmancy-motion-easing-emphasizedDecelerate);
|
|
885
|
+
}
|
|
826
886
|
|
|
827
|
-
|
|
828
|
-
|
|
887
|
+
@keyframes fadeIn {
|
|
888
|
+
from { opacity: 0; }
|
|
889
|
+
to { opacity: 1; }
|
|
890
|
+
}
|
|
891
|
+
</style>
|
|
892
|
+
|
|
893
|
+
<div class="panel ${this.isExpanded ? 'expanded' : ''}">
|
|
894
|
+
<!-- Content with smooth animations -->
|
|
895
|
+
</div>
|
|
896
|
+
`
|
|
829
897
|
}
|
|
830
898
|
}
|
|
831
899
|
```
|
|
832
900
|
|
|
833
|
-
##
|
|
901
|
+
## Integration with Theme Component
|
|
834
902
|
|
|
835
|
-
|
|
836
|
-
// Test component in different themes
|
|
837
|
-
describe('ThemedComponent', () => {
|
|
838
|
-
beforeEach(() => {
|
|
839
|
-
themeService.reset()
|
|
840
|
-
})
|
|
903
|
+
The service works bidirectionally with `<schmancy-theme>` component:
|
|
841
904
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
it('renders correctly in dark mode', async () => {
|
|
849
|
-
themeService.setMode('dark')
|
|
850
|
-
const el = await fixture(html`<themed-component></themed-component>`)
|
|
851
|
-
// Test dark mode rendering
|
|
852
|
-
})
|
|
905
|
+
```html
|
|
906
|
+
<schmancy-theme color="#6750A4" scheme="auto">
|
|
907
|
+
<!-- All children have access to theme tokens -->
|
|
908
|
+
</schmancy-theme>
|
|
909
|
+
```
|
|
853
910
|
|
|
854
|
-
|
|
855
|
-
|
|
911
|
+
Component automatically:
|
|
912
|
+
- Registers with service via discovery events
|
|
913
|
+
- Syncs state bidirectionally
|
|
914
|
+
- Generates full M3 token system
|
|
915
|
+
- Updates CSS variables in real-time
|
|
916
|
+
- Persists settings to localStorage
|
|
856
917
|
|
|
857
|
-
|
|
858
|
-
await el.updateComplete
|
|
918
|
+
## Error Handling
|
|
859
919
|
|
|
860
|
-
|
|
920
|
+
```typescript
|
|
921
|
+
// Graceful fallback when theme component is missing
|
|
922
|
+
theme.discoverTheme().pipe(
|
|
923
|
+
timeout(1000),
|
|
924
|
+
catchError(() => {
|
|
925
|
+
console.warn('Theme component not found, using defaults')
|
|
926
|
+
return of(null)
|
|
861
927
|
})
|
|
862
|
-
|
|
928
|
+
).subscribe()
|
|
929
|
+
|
|
930
|
+
// Validate color input
|
|
931
|
+
const isValidHex = (color: string) => /^#[0-9A-F]{6}$/i.test(color)
|
|
932
|
+
|
|
933
|
+
if (isValidHex(newColor)) {
|
|
934
|
+
theme.setColor(newColor)
|
|
935
|
+
} else {
|
|
936
|
+
console.error('Invalid color format')
|
|
937
|
+
}
|
|
863
938
|
```
|
|
864
939
|
|
|
865
|
-
## Performance
|
|
940
|
+
## Performance Considerations
|
|
866
941
|
|
|
867
|
-
|
|
942
|
+
1. **Token Generation**: Full M3 theme is generated once per color change
|
|
943
|
+
2. **CSS Variables**: Updated atomically via `adoptedStyleSheets`
|
|
944
|
+
3. **Persistence**: Debounced writes to localStorage (via context)
|
|
945
|
+
4. **Discovery**: One-time discovery with 1s timeout
|
|
946
|
+
5. **MediaQuery**: Single listener for system preference changes
|
|
947
|
+
6. **Observables**: Multicast for efficient subscriptions
|
|
868
948
|
|
|
949
|
+
## Migration Guide
|
|
950
|
+
|
|
951
|
+
From manual theme management:
|
|
869
952
|
```typescript
|
|
870
|
-
|
|
953
|
+
// Old way
|
|
954
|
+
localStorage.setItem('theme', 'dark')
|
|
955
|
+
document.body.classList.add('dark-theme')
|
|
871
956
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
debounceTime(300), // Debounce rapid changes
|
|
875
|
-
distinctUntilChanged((a, b) =>
|
|
876
|
-
a.primaryColor === b.primaryColor &&
|
|
877
|
-
a.mode === b.mode
|
|
878
|
-
),
|
|
879
|
-
takeUntil(this.disconnecting)
|
|
880
|
-
)
|
|
881
|
-
.subscribe(theme => {
|
|
882
|
-
// Handle theme changes
|
|
883
|
-
})
|
|
957
|
+
// New way
|
|
958
|
+
theme.setScheme('dark') // Automatic persistence & styling
|
|
884
959
|
```
|
|
885
960
|
|
|
886
|
-
|
|
887
|
-
|
|
961
|
+
From custom CSS variables:
|
|
888
962
|
```typescript
|
|
889
|
-
//
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
const settings = new ThemeSettings()
|
|
893
|
-
document.body.appendChild(settings)
|
|
963
|
+
// Old way
|
|
964
|
+
:root {
|
|
965
|
+
--primary: #6750A4;
|
|
894
966
|
}
|
|
895
|
-
```
|
|
896
|
-
|
|
897
|
-
## Troubleshooting
|
|
898
967
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
2. **CSS variables undefined**: Check that schmancy-theme is imported before use
|
|
903
|
-
3. **Dark mode not working**: Verify `scheme="auto"` and system preferences
|
|
904
|
-
4. **Performance issues**: Use debouncing and avoid excessive nesting
|
|
905
|
-
5. **Colors not updating**: Ensure using CSS variables, not hardcoded values
|
|
906
|
-
|
|
907
|
-
## Related Components
|
|
968
|
+
// New way - Full M3 system generated
|
|
969
|
+
theme.setColor('#6750A4') // Generates 100+ tokens
|
|
970
|
+
```
|
|
908
971
|
|
|
909
|
-
|
|
910
|
-
- [Surface](./surface.md) - Themed containers
|
|
911
|
-
- [Button](./button.md) - Themed interactions
|
|
912
|
-
- [Card](./card.md) - Themed content
|
|
972
|
+
## Summary
|
|
913
973
|
|
|
914
|
-
|
|
974
|
+
The theme service provides a complete Material Design 3 implementation with:
|
|
975
|
+
- 🎨 **Extended color system** with semantic colors
|
|
976
|
+
- 📐 **Complete surface hierarchy** for proper elevation
|
|
977
|
+
- 🔤 **Full typography scale** across 5 categories
|
|
978
|
+
- 🎬 **Sophisticated motion system** with easing and duration
|
|
979
|
+
- 🔲 **Shape tokens** for consistent corner radii
|
|
980
|
+
- 💾 **Automatic persistence** via context
|
|
981
|
+
- 🔍 **Smart discovery** with bidirectional events
|
|
982
|
+
- 🌓 **System preference detection** with real-time updates
|
|
983
|
+
- 🎯 **Ready-to-use controls** component
|
|
984
|
+
- ⚡ **Reactive observables** for all properties
|
|
915
985
|
|
|
916
|
-
|
|
917
|
-
2. **White-Label**: Dynamic branding for multiple clients
|
|
918
|
-
3. **User Preferences**: Personalized themes saved per user
|
|
919
|
-
4. **Section Theming**: Different themes for app sections
|
|
920
|
-
5. **A/B Testing**: Theme variations for testing
|
|
921
|
-
6. **Accessibility**: High contrast modes for better readability
|
|
922
|
-
7. **Dark Mode**: Automatic or manual dark mode support
|
|
923
|
-
8. **Brand Compliance**: Enforce brand colors across components
|
|
986
|
+
Use the theme service as your single source of truth for all design tokens and theming needs.
|