@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.
Files changed (385) hide show
  1. package/ai/content-drawer.md +114 -140
  2. package/ai/navigation-bar.md +30 -4
  3. package/ai/navigation-rail.md +72 -0
  4. package/ai/theme.md +779 -716
  5. package/dist/ai/content-drawer.md +114 -140
  6. package/dist/ai/navigation-bar.md +30 -4
  7. package/dist/ai/navigation-rail.md +72 -0
  8. package/dist/ai/theme.md +779 -716
  9. package/dist/{animated-text-COvhr8E3.js → animated-text-Cfs1zx2e.js} +4 -3
  10. package/dist/{animated-text-COvhr8E3.js.map → animated-text-Cfs1zx2e.js.map} +1 -1
  11. package/dist/{animated-text-BZUrBdvN.cjs → animated-text-DoLx8YhT.cjs} +2 -2
  12. package/dist/{animated-text-BZUrBdvN.cjs.map → animated-text-DoLx8YhT.cjs.map} +1 -1
  13. package/dist/animated-text.cjs +1 -1
  14. package/dist/animated-text.js +1 -1
  15. package/dist/area.cjs +1 -1
  16. package/dist/{area.component-BHtBHWVt.js → area.component-A6Xw-dfF.js} +4 -3
  17. package/dist/{area.component-BHtBHWVt.js.map → area.component-A6Xw-dfF.js.map} +1 -1
  18. package/dist/area.component-DMRF1lD-.cjs +12 -0
  19. package/dist/{area.component-Ch2Eaa4i.cjs.map → area.component-DMRF1lD-.cjs.map} +1 -1
  20. package/dist/area.js +1 -1
  21. package/dist/{autocomplete-9RkU9LmA.js → autocomplete-C5DIxpTG.js} +18 -18
  22. package/dist/{autocomplete-9RkU9LmA.js.map → autocomplete-C5DIxpTG.js.map} +1 -1
  23. package/dist/{autocomplete-CenwFcT1.cjs → autocomplete-DkJqOYTg.cjs} +2 -2
  24. package/dist/{autocomplete-CenwFcT1.cjs.map → autocomplete-DkJqOYTg.cjs.map} +1 -1
  25. package/dist/autocomplete.cjs +1 -1
  26. package/dist/autocomplete.js +1 -1
  27. package/dist/{avatar-CjjwZDsw.js → avatar-BDy0wAek.js} +144 -134
  28. package/dist/avatar-BDy0wAek.js.map +1 -0
  29. package/dist/avatar-BmcocEQ4.cjs +306 -0
  30. package/dist/avatar-BmcocEQ4.cjs.map +1 -0
  31. package/dist/badge.cjs +1 -1
  32. package/dist/badge.js +1 -1
  33. package/dist/boat-CfIXRMn-.cjs +78 -0
  34. package/dist/boat-CfIXRMn-.cjs.map +1 -0
  35. package/dist/boat-DumUFcmT.js +276 -0
  36. package/dist/boat-DumUFcmT.js.map +1 -0
  37. package/dist/boat.cjs +1 -1
  38. package/dist/boat.js +1 -1
  39. package/dist/busy.cjs +1 -1
  40. package/dist/busy.js +1 -1
  41. package/dist/button.cjs +1 -1
  42. package/dist/button.js +1 -1
  43. package/dist/card.cjs +1 -1
  44. package/dist/card.js +1 -1
  45. package/dist/{checkbox-D6-WQeEk.js → checkbox-CHG-gT2P.js} +3 -2
  46. package/dist/{checkbox-D6-WQeEk.js.map → checkbox-CHG-gT2P.js.map} +1 -1
  47. package/dist/{checkbox-8djp_8NK.cjs → checkbox-CsMLbxBY.cjs} +2 -2
  48. package/dist/{checkbox-8djp_8NK.cjs.map → checkbox-CsMLbxBY.cjs.map} +1 -1
  49. package/dist/checkbox.cjs +1 -1
  50. package/dist/checkbox.js +1 -1
  51. package/dist/chips.cjs +1 -1
  52. package/dist/chips.js +2 -2
  53. package/dist/code-highlight.cjs +1 -1
  54. package/dist/code-highlight.js +1 -1
  55. package/dist/{code-preview-BFoEmN8y.cjs → code-preview-BgUU7bPR.cjs} +5 -5
  56. package/dist/{code-preview-BFoEmN8y.cjs.map → code-preview-BgUU7bPR.cjs.map} +1 -1
  57. package/dist/{code-preview-Z02-2suM.js → code-preview-Bp4OemTD.js} +8 -8
  58. package/dist/{code-preview-Z02-2suM.js.map → code-preview-Bp4OemTD.js.map} +1 -1
  59. package/dist/components.cjs +1 -1
  60. package/dist/components.js +1 -1
  61. package/dist/content-drawer.cjs +1 -1
  62. package/dist/content-drawer.js +1 -1
  63. package/dist/context-create-CA907mdD.cjs +2 -0
  64. package/dist/context-create-CA907mdD.cjs.map +1 -0
  65. package/dist/{context-object-BE1o2XB3.js → context-create-DCiujzV2.js} +262 -212
  66. package/dist/context-create-DCiujzV2.js.map +1 -0
  67. package/dist/{date-range-kFnTrnHN.js → date-range-BcJ0YN2n.js} +141 -140
  68. package/dist/{date-range-kFnTrnHN.js.map → date-range-BcJ0YN2n.js.map} +1 -1
  69. package/dist/{date-range-DoCtnpW6.cjs → date-range-D_DBil9n.cjs} +2 -2
  70. package/dist/{date-range-DoCtnpW6.cjs.map → date-range-D_DBil9n.cjs.map} +1 -1
  71. package/dist/date-range-inline-DQjOVUxD.cjs +44 -0
  72. package/dist/{date-range-inline-DNr7C5X-.cjs.map → date-range-inline-DQjOVUxD.cjs.map} +1 -1
  73. package/dist/{date-range-inline-BXeX6T7R.js → date-range-inline-Dqxqgu2s.js} +8 -7
  74. package/dist/{date-range-inline-BXeX6T7R.js.map → date-range-inline-Dqxqgu2s.js.map} +1 -1
  75. package/dist/date-range-inline.cjs +1 -1
  76. package/dist/date-range-inline.js +1 -1
  77. package/dist/date-range.cjs +1 -1
  78. package/dist/date-range.js +1 -1
  79. package/dist/{delay-CrdOikhP.cjs → delay-BbtlKEc4.cjs} +2 -2
  80. package/dist/{delay-CrdOikhP.cjs.map → delay-BbtlKEc4.cjs.map} +1 -1
  81. package/dist/{delay-Cz-9rZxi.js → delay-CC_14mn4.js} +2 -2
  82. package/dist/{delay-Cz-9rZxi.js.map → delay-CC_14mn4.js.map} +1 -1
  83. package/dist/delay.cjs +1 -1
  84. package/dist/delay.js +1 -1
  85. package/dist/{details-CsqhGMjL.cjs → details-CTdm7rbG.cjs} +2 -2
  86. package/dist/{details-CsqhGMjL.cjs.map → details-CTdm7rbG.cjs.map} +1 -1
  87. package/dist/{details-DeBtsJlp.js → details-dk2hnRIp.js} +3 -2
  88. package/dist/{details-DeBtsJlp.js.map → details-dk2hnRIp.js.map} +1 -1
  89. package/dist/details.cjs +1 -1
  90. package/dist/details.js +1 -1
  91. package/dist/{dialog-content-DTKdAF_l.js → dialog-content-BM-lfqHq.js} +4 -4
  92. package/dist/{dialog-content-DTKdAF_l.js.map → dialog-content-BM-lfqHq.js.map} +1 -1
  93. package/dist/{dialog-content-BzSQoM2J.cjs → dialog-content-BSZ5dwnP.cjs} +2 -2
  94. package/dist/{dialog-content-BzSQoM2J.cjs.map → dialog-content-BSZ5dwnP.cjs.map} +1 -1
  95. package/dist/dialog.cjs +1 -1
  96. package/dist/dialog.js +1 -1
  97. package/dist/discovery.cjs +2 -0
  98. package/dist/discovery.cjs.map +1 -0
  99. package/dist/discovery.js +6 -0
  100. package/dist/discovery.js.map +1 -0
  101. package/dist/discovery.service-BbYjU5x8.js +21 -0
  102. package/dist/discovery.service-BbYjU5x8.js.map +1 -0
  103. package/dist/discovery.service-BpGCuXPd.cjs +2 -0
  104. package/dist/discovery.service-BpGCuXPd.cjs.map +1 -0
  105. package/dist/{divider-7iyyEd8k.js → divider-BWVdeJm1.js} +4 -3
  106. package/dist/{divider-7iyyEd8k.js.map → divider-BWVdeJm1.js.map} +1 -1
  107. package/dist/divider-DgJXEKxB.cjs +2 -0
  108. package/dist/{divider-CNxOc8ep.cjs.map → divider-DgJXEKxB.cjs.map} +1 -1
  109. package/dist/divider.cjs +1 -1
  110. package/dist/divider.js +1 -1
  111. package/dist/{dropdown-content-_GMpqsNq.js → dropdown-content-BgLy9dwU.js} +4 -3
  112. package/dist/{dropdown-content-_GMpqsNq.js.map → dropdown-content-BgLy9dwU.js.map} +1 -1
  113. package/dist/{dropdown-content-De0OkNoq.cjs → dropdown-content-ZAB82v-h.cjs} +2 -2
  114. package/dist/{dropdown-content-De0OkNoq.cjs.map → dropdown-content-ZAB82v-h.cjs.map} +1 -1
  115. package/dist/dropdown.cjs +1 -1
  116. package/dist/dropdown.js +1 -1
  117. package/dist/{email-recipients-CPZlUiRR.js → email-recipients-IXQLqBaI.js} +6 -5
  118. package/dist/{email-recipients-CPZlUiRR.js.map → email-recipients-IXQLqBaI.js.map} +1 -1
  119. package/dist/{email-recipients-DS01C3V3.cjs → email-recipients-R7jCXy_I.cjs} +2 -2
  120. package/dist/{email-recipients-DS01C3V3.cjs.map → email-recipients-R7jCXy_I.cjs.map} +1 -1
  121. package/dist/extra.cjs +1 -1
  122. package/dist/extra.js +1 -1
  123. package/dist/{flex-BeSoRNTu.js → flex-Cp1nomar.js} +3 -2
  124. package/dist/{flex-BeSoRNTu.js.map → flex-Cp1nomar.js.map} +1 -1
  125. package/dist/{flex-CHf9Gc5V.cjs → flex-sAQsXdsk.cjs} +2 -2
  126. package/dist/{flex-CHf9Gc5V.cjs.map → flex-sAQsXdsk.cjs.map} +1 -1
  127. package/dist/form-DHTbrnEl.cjs +2 -0
  128. package/dist/{form-DzDksPgv.cjs.map → form-DHTbrnEl.cjs.map} +1 -1
  129. package/dist/{form-DNeKagke.js → form-Dtc128QU.js} +3 -2
  130. package/dist/{form-DNeKagke.js.map → form-Dtc128QU.js.map} +1 -1
  131. package/dist/form.cjs +1 -1
  132. package/dist/form.js +1 -1
  133. package/dist/{formField.mixin-BNj75WQ4.js → formField.mixin-CCB_CKYb.js} +2 -2
  134. package/dist/{formField.mixin-BNj75WQ4.js.map → formField.mixin-CCB_CKYb.js.map} +1 -1
  135. package/dist/{formField.mixin-D5YAYIS1.cjs → formField.mixin-CZQ7alVs.cjs} +2 -2
  136. package/dist/{formField.mixin-D5YAYIS1.cjs.map → formField.mixin-CZQ7alVs.cjs.map} +1 -1
  137. package/dist/{icon-CCMpTJTp.js → icon-BHhOyVjB.js} +9 -9
  138. package/dist/{icon-CCMpTJTp.js.map → icon-BHhOyVjB.js.map} +1 -1
  139. package/dist/{icon-DebIySqv.cjs → icon-CocdSdlX.cjs} +3 -3
  140. package/dist/{icon-DebIySqv.cjs.map → icon-CocdSdlX.cjs.map} +1 -1
  141. package/dist/{icon-button-D6DH52j4.js → icon-button-CjSaBrg0.js} +4 -3
  142. package/dist/{icon-button-D6DH52j4.js.map → icon-button-CjSaBrg0.js.map} +1 -1
  143. package/dist/{icon-button-DwnnW2oj.cjs → icon-button-m8kXxOvS.cjs} +2 -2
  144. package/dist/{icon-button-DwnnW2oj.cjs.map → icon-button-m8kXxOvS.cjs.map} +1 -1
  145. package/dist/icons.cjs +1 -1
  146. package/dist/icons.js +1 -1
  147. package/dist/index.cjs +1 -1
  148. package/dist/index.js +187 -182
  149. package/dist/index.js.map +1 -1
  150. package/dist/input-BuDPnk5e.cjs +51 -0
  151. package/dist/{input-C2Vz-51i.cjs.map → input-BuDPnk5e.cjs.map} +1 -1
  152. package/dist/{input-DtHPCCyd.js → input-D_gdNxxR.js} +4 -3
  153. package/dist/{input-DtHPCCyd.js.map → input-D_gdNxxR.js.map} +1 -1
  154. package/dist/{input-chip-B7ANrtLF.cjs → input-chip-CDLblIp9.cjs} +2 -2
  155. package/dist/{input-chip-B7ANrtLF.cjs.map → input-chip-CDLblIp9.cjs.map} +1 -1
  156. package/dist/{input-chip-DbIvSyvP.js → input-chip-CLnR4vSR.js} +2 -2
  157. package/dist/{input-chip-DbIvSyvP.js.map → input-chip-CLnR4vSR.js.map} +1 -1
  158. package/dist/input.cjs +1 -1
  159. package/dist/input.js +1 -1
  160. package/dist/layout.cjs +1 -1
  161. package/dist/layout.js +1 -1
  162. package/dist/{list-BBo0--_Q.js → list-C069T9ey.js} +3 -2
  163. package/dist/{list-BBo0--_Q.js.map → list-C069T9ey.js.map} +1 -1
  164. package/dist/{list-BH8OJ3Rv.cjs → list-KCakyWxw.cjs} +2 -2
  165. package/dist/{list-BH8OJ3Rv.cjs.map → list-KCakyWxw.cjs.map} +1 -1
  166. package/dist/list.cjs +1 -1
  167. package/dist/list.js +1 -1
  168. package/dist/{litElement.mixin-LplXbzd8.cjs → litElement.mixin-DoBMt4ia.cjs} +2 -2
  169. package/dist/{litElement.mixin-LplXbzd8.cjs.map → litElement.mixin-DoBMt4ia.cjs.map} +1 -1
  170. package/dist/{litElement.mixin-CzF0mNQd.js → litElement.mixin-Dp4mBSNw.js} +2 -2
  171. package/dist/{litElement.mixin-CzF0mNQd.js.map → litElement.mixin-Dp4mBSNw.js.map} +1 -1
  172. package/dist/mailbox.cjs +1 -1
  173. package/dist/mailbox.js +1 -1
  174. package/dist/{map-DeiCBxMP.js → map-pn_6ziZf.js} +19 -19
  175. package/dist/{map-DeiCBxMP.js.map → map-pn_6ziZf.js.map} +1 -1
  176. package/dist/{map-C7lxYU4A.cjs → map-vNMrrat-.cjs} +2 -2
  177. package/dist/{map-C7lxYU4A.cjs.map → map-vNMrrat-.cjs.map} +1 -1
  178. package/dist/map.cjs +1 -1
  179. package/dist/map.js +1 -1
  180. package/dist/{media-CsYVcfaX.cjs → media-CAtXPif3.cjs} +6 -6
  181. package/dist/{media-CsYVcfaX.cjs.map → media-CAtXPif3.cjs.map} +1 -1
  182. package/dist/{media-CEnaqjig.js → media-DC3r4y8-.js} +9 -8
  183. package/dist/{media-CEnaqjig.js.map → media-DC3r4y8-.js.map} +1 -1
  184. package/dist/{menu-wtkHGlyc.js → menu-BAs2snSu.js} +4 -3
  185. package/dist/{menu-wtkHGlyc.js.map → menu-BAs2snSu.js.map} +1 -1
  186. package/dist/{menu-Boqsyfmh.cjs → menu-C2ZKJe1g.cjs} +2 -2
  187. package/dist/{menu-Boqsyfmh.cjs.map → menu-C2ZKJe1g.cjs.map} +1 -1
  188. package/dist/menu.cjs +1 -1
  189. package/dist/menu.js +1 -1
  190. package/dist/mixins/baseElement.ts +33 -1
  191. package/dist/mixins/discovery.service.ts +60 -0
  192. package/dist/nav-drawer.cjs +1 -1
  193. package/dist/nav-drawer.js +1 -1
  194. package/dist/navigation-bar.cjs +1 -1
  195. package/dist/navigation-bar.js +1 -1
  196. package/dist/{navigation-rail-6ONc-XE-.cjs → navigation-rail-B0zofile.cjs} +14 -11
  197. package/dist/navigation-rail-B0zofile.cjs.map +1 -0
  198. package/dist/{navigation-rail-D-lK9oVd.js → navigation-rail-KdVjbO1I.js} +43 -31
  199. package/dist/navigation-rail-KdVjbO1I.js.map +1 -0
  200. package/dist/navigation-rail.cjs +1 -1
  201. package/dist/navigation-rail.js +1 -1
  202. package/dist/{notification-service-ZiGUSd63.js → notification-service-BOCdK7B0.js} +7 -6
  203. package/dist/{notification-service-ZiGUSd63.js.map → notification-service-BOCdK7B0.js.map} +1 -1
  204. package/dist/{notification-service-9HXSKWcw.cjs → notification-service-DXsySIdG.cjs} +2 -2
  205. package/dist/{notification-service-9HXSKWcw.cjs.map → notification-service-DXsySIdG.cjs.map} +1 -1
  206. package/dist/notification.cjs +1 -1
  207. package/dist/notification.js +2 -2
  208. package/dist/{notify-DbfX6Z2P.js → notify-Cglpgay3.js} +2 -2
  209. package/dist/{notify-DbfX6Z2P.js.map → notify-Cglpgay3.js.map} +1 -1
  210. package/dist/{notify-W-NrP0cC.cjs → notify-CvDL-o79.cjs} +2 -2
  211. package/dist/{notify-W-NrP0cC.cjs.map → notify-CvDL-o79.cjs.map} +1 -1
  212. package/dist/{option-D2bxihLu.cjs → option-ezGy71aI.cjs} +2 -2
  213. package/dist/{option-D2bxihLu.cjs.map → option-ezGy71aI.cjs.map} +1 -1
  214. package/dist/{option-BFlWiCu0.js → option-tDU1Z_vP.js} +11 -10
  215. package/dist/{option-BFlWiCu0.js.map → option-tDU1Z_vP.js.map} +1 -1
  216. package/dist/option.cjs +1 -1
  217. package/dist/option.js +1 -1
  218. package/dist/payment-card-form-B5b-LA2Y.cjs +74 -0
  219. package/dist/{payment-card-form--v94EhJF.cjs.map → payment-card-form-B5b-LA2Y.cjs.map} +1 -1
  220. package/dist/{payment-card-form-DLRNX9NX.js → payment-card-form-CZpc-zfO.js} +4 -3
  221. package/dist/{payment-card-form-DLRNX9NX.js.map → payment-card-form-CZpc-zfO.js.map} +1 -1
  222. package/dist/{progress-BYohUvYO.js → progress-Bqih11TQ.js} +10 -9
  223. package/dist/{progress-BYohUvYO.js.map → progress-Bqih11TQ.js.map} +1 -1
  224. package/dist/{progress-CjkD8QBy.cjs → progress-OMGbiNv5.cjs} +2 -2
  225. package/dist/{progress-CjkD8QBy.cjs.map → progress-OMGbiNv5.cjs.map} +1 -1
  226. package/dist/progress.cjs +1 -1
  227. package/dist/progress.js +1 -1
  228. package/dist/{radio-button-CGmGOAil.cjs → radio-button-BuSpPTO4.cjs} +2 -2
  229. package/dist/{radio-button-CGmGOAil.cjs.map → radio-button-BuSpPTO4.cjs.map} +1 -1
  230. package/dist/{radio-button-BlxeCjdq.js → radio-button-mHT1573u.js} +4 -3
  231. package/dist/{radio-button-BlxeCjdq.js.map → radio-button-mHT1573u.js.map} +1 -1
  232. package/dist/radio-group.cjs +1 -1
  233. package/dist/radio-group.js +1 -1
  234. package/dist/{schmancy-steps-container-CydL78yk.cjs → schmancy-steps-container-Bht_BlLU.cjs} +2 -2
  235. package/dist/{schmancy-steps-container-CydL78yk.cjs.map → schmancy-steps-container-Bht_BlLU.cjs.map} +1 -1
  236. package/dist/{schmancy-steps-container-BtAHCm73.js → schmancy-steps-container-DDMiJJyw.js} +2 -2
  237. package/dist/{schmancy-steps-container-BtAHCm73.js.map → schmancy-steps-container-DDMiJJyw.js.map} +1 -1
  238. package/dist/{select-BiN334GN.js → select-CKtpFPTr.js} +13 -13
  239. package/dist/{select-BiN334GN.js.map → select-CKtpFPTr.js.map} +1 -1
  240. package/dist/{select-CrB02cIO.cjs → select-HPtumqyg.cjs} +2 -2
  241. package/dist/{select-CrB02cIO.cjs.map → select-HPtumqyg.cjs.map} +1 -1
  242. package/dist/select.cjs +1 -1
  243. package/dist/select.js +1 -1
  244. package/dist/selector-hook-BWMY8npH.cjs +2 -0
  245. package/dist/selector-hook-BWMY8npH.cjs.map +1 -0
  246. package/dist/selector-hook-CKeyK4K-.js +313 -0
  247. package/dist/selector-hook-CKeyK4K-.js.map +1 -0
  248. package/dist/{sheet-DpJv4DRi.js → sheet-B-vTiTi8.js} +4 -3
  249. package/dist/{sheet-DpJv4DRi.js.map → sheet-B-vTiTi8.js.map} +1 -1
  250. package/dist/{sheet-sgVoRMi1.cjs → sheet-DP7nFOEo.cjs} +2 -2
  251. package/dist/{sheet-sgVoRMi1.cjs.map → sheet-DP7nFOEo.cjs.map} +1 -1
  252. package/dist/sheet.cjs +1 -1
  253. package/dist/sheet.js +1 -1
  254. package/dist/{slider-D7qdxfvX.js → slider-Bu7kQ0_w.js} +9 -9
  255. package/dist/{slider-D7qdxfvX.js.map → slider-Bu7kQ0_w.js.map} +1 -1
  256. package/dist/{slider-Dd1L6oYm.cjs → slider-Diqgkt3E.cjs} +4 -4
  257. package/dist/{slider-Dd1L6oYm.cjs.map → slider-Diqgkt3E.cjs.map} +1 -1
  258. package/dist/slider.cjs +1 -1
  259. package/dist/slider.js +1 -1
  260. package/dist/{spinner-CaXU45TV.cjs → spinner-b6hiAljR.cjs} +2 -2
  261. package/dist/{spinner-CaXU45TV.cjs.map → spinner-b6hiAljR.cjs.map} +1 -1
  262. package/dist/{spinner-XN4W5ihQ.js → spinner-paAzgY93.js} +3 -2
  263. package/dist/{spinner-XN4W5ihQ.js.map → spinner-paAzgY93.js.map} +1 -1
  264. package/dist/steps.cjs +1 -1
  265. package/dist/steps.js +1 -1
  266. package/dist/store.cjs +1 -1
  267. package/dist/store.js +26 -26
  268. package/dist/{suggestion-chip-PI24Hc3s.cjs → suggestion-chip--FVeCUSI.cjs} +2 -2
  269. package/dist/{suggestion-chip-PI24Hc3s.cjs.map → suggestion-chip--FVeCUSI.cjs.map} +1 -1
  270. package/dist/{suggestion-chip-CdhoATv9.js → suggestion-chip-DnnfUAqx.js} +3 -3
  271. package/dist/{suggestion-chip-CdhoATv9.js.map → suggestion-chip-DnnfUAqx.js.map} +1 -1
  272. package/dist/{surface-CKrYJ58l.js → surface-BBhAIoZq.js} +2 -2
  273. package/dist/{surface-CKrYJ58l.js.map → surface-BBhAIoZq.js.map} +1 -1
  274. package/dist/{surface-Ax6I7ldp.cjs → surface-SICYUsoB.cjs} +2 -2
  275. package/dist/{surface-Ax6I7ldp.cjs.map → surface-SICYUsoB.cjs.map} +1 -1
  276. package/dist/surface.cjs +1 -1
  277. package/dist/surface.js +1 -1
  278. package/dist/{table-CP6_NkPm.js → table-CepjNGT6.js} +2 -2
  279. package/dist/{table-CP6_NkPm.js.map → table-CepjNGT6.js.map} +1 -1
  280. package/dist/{table-BlwUyf_4.cjs → table-yYKET4qQ.cjs} +2 -2
  281. package/dist/{table-BlwUyf_4.cjs.map → table-yYKET4qQ.cjs.map} +1 -1
  282. package/dist/table.cjs +1 -1
  283. package/dist/table.js +1 -1
  284. package/dist/{tabs-compatibility-CX0cIu_Y.cjs → tabs-compatibility-BWaRkr9s.cjs} +4 -4
  285. package/dist/{tabs-compatibility-CX0cIu_Y.cjs.map → tabs-compatibility-BWaRkr9s.cjs.map} +1 -1
  286. package/dist/{tabs-compatibility-7QKuXX4i.js → tabs-compatibility-BXdyrybs.js} +7 -6
  287. package/dist/{tabs-compatibility-7QKuXX4i.js.map → tabs-compatibility-BXdyrybs.js.map} +1 -1
  288. package/dist/tabs.cjs +1 -1
  289. package/dist/tabs.js +1 -1
  290. package/dist/tailwind.mixin-CYhJgwwb.cjs +2 -0
  291. package/dist/tailwind.mixin-CYhJgwwb.cjs.map +1 -0
  292. package/dist/tailwind.mixin-Cn7vup-6.js +64 -0
  293. package/dist/tailwind.mixin-Cn7vup-6.js.map +1 -0
  294. package/dist/teleport.cjs +1 -1
  295. package/dist/teleport.js +1 -1
  296. package/dist/{textarea-DHrDn-O6.js → textarea-BpNEwBP9.js} +3 -2
  297. package/dist/{textarea-DHrDn-O6.js.map → textarea-BpNEwBP9.js.map} +1 -1
  298. package/dist/textarea-Xgbs3rjA.cjs +44 -0
  299. package/dist/{textarea-qLA0vP78.cjs.map → textarea-Xgbs3rjA.cjs.map} +1 -1
  300. package/dist/textarea.cjs +1 -1
  301. package/dist/textarea.js +1 -1
  302. package/dist/{theme-button-BEUsbH5m.js → theme-button-77xbTIaH.js} +6 -5
  303. package/dist/{theme-button-BEUsbH5m.js.map → theme-button-77xbTIaH.js.map} +1 -1
  304. package/dist/theme-button-BsjsULjH.cjs +9 -0
  305. package/dist/{theme-button-D7fBEUGf.cjs.map → theme-button-BsjsULjH.cjs.map} +1 -1
  306. package/dist/theme-button.cjs +1 -1
  307. package/dist/theme-button.js +1 -1
  308. package/dist/theme.cjs +1 -1
  309. package/dist/theme.controls-BeNS8iSM.cjs +67 -0
  310. package/dist/theme.controls-BeNS8iSM.cjs.map +1 -0
  311. package/dist/{theme.component-ByGua01V.js → theme.controls-DtcpHuz9.js} +367 -238
  312. package/dist/theme.controls-DtcpHuz9.js.map +1 -0
  313. package/dist/theme.js +13 -11
  314. package/dist/{timezone-BpDMR26D.js → timezone-CtH2a7Hw.js} +10 -9
  315. package/dist/{timezone-BpDMR26D.js.map → timezone-CtH2a7Hw.js.map} +1 -1
  316. package/dist/{timezone-Bw4EXBt7.cjs → timezone-D3kdUX6c.cjs} +2 -2
  317. package/dist/{timezone-Bw4EXBt7.cjs.map → timezone-D3kdUX6c.cjs.map} +1 -1
  318. package/dist/{tooltip-Dhs4HL3A.cjs → tooltip-BwZ_zIEI.cjs} +2 -2
  319. package/dist/{tooltip-Dhs4HL3A.cjs.map → tooltip-BwZ_zIEI.cjs.map} +1 -1
  320. package/dist/{tooltip-B1jynZOH.js → tooltip-DgGZouB5.js} +2 -2
  321. package/dist/{tooltip-B1jynZOH.js.map → tooltip-DgGZouB5.js.map} +1 -1
  322. package/dist/tooltip.cjs +1 -1
  323. package/dist/tooltip.js +1 -1
  324. package/dist/{tree-D-ezei_U.cjs → tree-B9fWtaGW.cjs} +4 -4
  325. package/dist/{tree-D-ezei_U.cjs.map → tree-B9fWtaGW.cjs.map} +1 -1
  326. package/dist/{tree-BH1qCJ_U.js → tree-BSENnhB2.js} +3 -2
  327. package/dist/{tree-BH1qCJ_U.js.map → tree-BSENnhB2.js.map} +1 -1
  328. package/dist/tree.cjs +1 -1
  329. package/dist/tree.js +1 -1
  330. package/dist/{typewriter-DQbpNPtY.js → typewriter-BCXtlffJ.js} +5 -4
  331. package/dist/{typewriter-DQbpNPtY.js.map → typewriter-BCXtlffJ.js.map} +1 -1
  332. package/dist/typewriter-DeNR2E_p.cjs +9 -0
  333. package/dist/{typewriter-CtPh4Pyj.cjs.map → typewriter-DeNR2E_p.cjs.map} +1 -1
  334. package/dist/typewriter.cjs +1 -1
  335. package/dist/typewriter.js +1 -1
  336. package/dist/{typography-BrIaOYmC.cjs → typography-Cm7pGqRe.cjs} +2 -2
  337. package/dist/{typography-BrIaOYmC.cjs.map → typography-Cm7pGqRe.cjs.map} +1 -1
  338. package/dist/{typography-D71cmr0R.js → typography-sxQLtA6a.js} +2 -2
  339. package/dist/{typography-D71cmr0R.js.map → typography-sxQLtA6a.js.map} +1 -1
  340. package/dist/typography.cjs +1 -1
  341. package/dist/typography.js +1 -1
  342. package/package.json +1 -1
  343. package/types/mixins/baseElement.d.ts +2 -1
  344. package/types/mixins/discovery.service.d.ts +17 -0
  345. package/types/src/boat/boat.d.ts +10 -5
  346. package/types/src/discovery/discovery.service.d.ts +17 -0
  347. package/types/src/discovery/index.d.ts +1 -0
  348. package/types/src/index.d.ts +1 -0
  349. package/types/src/navigation-bar/navigation-bar.d.ts +15 -1
  350. package/types/src/navigation-rail/navigation-rail.d.ts +13 -0
  351. package/types/src/theme/index.d.ts +1 -0
  352. package/types/src/theme/theme.controls.d.ts +27 -0
  353. package/types/src/theme/theme.service.d.ts +58 -2
  354. package/dist/area.component-Ch2Eaa4i.cjs +0 -12
  355. package/dist/avatar-CjjwZDsw.js.map +0 -1
  356. package/dist/avatar-DlhBTIc8.cjs +0 -303
  357. package/dist/avatar-DlhBTIc8.cjs.map +0 -1
  358. package/dist/boat-CUsJXaLf.js +0 -240
  359. package/dist/boat-CUsJXaLf.js.map +0 -1
  360. package/dist/boat-Dfx9-P8c.cjs +0 -83
  361. package/dist/boat-Dfx9-P8c.cjs.map +0 -1
  362. package/dist/context-object-BE1o2XB3.js.map +0 -1
  363. package/dist/context-object-DA9DM9QJ.cjs +0 -2
  364. package/dist/context-object-DA9DM9QJ.cjs.map +0 -1
  365. package/dist/date-range-inline-DNr7C5X-.cjs +0 -44
  366. package/dist/divider-CNxOc8ep.cjs +0 -2
  367. package/dist/form-DzDksPgv.cjs +0 -2
  368. package/dist/input-C2Vz-51i.cjs +0 -51
  369. package/dist/navigation-rail-6ONc-XE-.cjs.map +0 -1
  370. package/dist/navigation-rail-D-lK9oVd.js.map +0 -1
  371. package/dist/payment-card-form--v94EhJF.cjs +0 -74
  372. package/dist/selector-hook-DOsvFxG2.js +0 -364
  373. package/dist/selector-hook-DOsvFxG2.js.map +0 -1
  374. package/dist/selector-hook-DQ9zoDM4.cjs +0 -2
  375. package/dist/selector-hook-DQ9zoDM4.cjs.map +0 -1
  376. package/dist/tailwind.mixin-BjDGMGbj.js +0 -43
  377. package/dist/tailwind.mixin-BjDGMGbj.js.map +0 -1
  378. package/dist/tailwind.mixin-ClfV2_Nh.cjs +0 -2
  379. package/dist/tailwind.mixin-ClfV2_Nh.cjs.map +0 -1
  380. package/dist/textarea-qLA0vP78.cjs +0 -44
  381. package/dist/theme-button-D7fBEUGf.cjs +0 -9
  382. package/dist/theme.component-ByGua01V.js.map +0 -1
  383. package/dist/theme.component-CQ1trrZB.cjs +0 -3
  384. package/dist/theme.component-CQ1trrZB.cjs.map +0 -1
  385. package/dist/typewriter-CtPh4Pyj.cjs +0 -9
package/ai/theme.md CHANGED
@@ -1,923 +1,986 @@
1
- # Theme System Documentation
1
+ # Theme Service
2
2
 
3
- A comprehensive theming system that provides both a visual configuration component and a programmatic service API. Built on Material Design 3 principles, it generates complete color schemes with automatic dark/light mode support and CSS custom property injection.
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
- ## Overview
5
+ ## Import
6
6
 
7
- The Schmancy theme system consists of two main parts:
8
- 1. **Theme Component** (`<schmancy-theme>`) - Visual theme configuration interface
9
- 2. **Theme Service API** (`themeService`) - Programmatic theme management and subscriptions
7
+ ```typescript
8
+ import { theme } from '@schmancy/theme'
9
+ // Alternative: schmancyTheme
10
+ ```
10
11
 
11
- ## Quick Start
12
+ ## Core Concepts
12
13
 
13
- ### Using the Theme Component
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
- ```html
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
- <!-- Custom color theme -->
24
- <schmancy-theme color="#6750A4" scheme="light">
25
- <schmancy-card>
26
- <h2>Themed Content</h2>
27
- </schmancy-card>
28
- </schmancy-theme>
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
- ### Using the Theme Service
31
+ ## Observables
37
32
 
38
33
  ```typescript
39
- import { themeService } from '@schmancy/index'
40
- // Or specific import: import { themeService } from '@schmancy/theme'
34
+ // Scheme changes
35
+ theme.scheme$.subscribe(scheme => {
36
+ console.log(scheme) // 'dark' | 'light' | 'auto'
37
+ })
41
38
 
42
- // Get current theme
43
- const theme = themeService.getCurrentTheme()
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
- // Set theme mode
46
- themeService.setMode('dark')
44
+ // Color changes
45
+ theme.color$.subscribe(color => {
46
+ console.log(color) // '#6200ee'
47
+ })
47
48
 
48
- // Set primary color
49
- themeService.setPrimaryColor('#6750A4')
49
+ // Fullscreen state
50
+ theme.fullscreen$.subscribe(isFullscreen => {
51
+ console.log(isFullscreen) // true/false
52
+ })
50
53
 
51
- // Subscribe to theme changes
52
- themeService.theme$.subscribe(theme => {
53
- console.log('Theme updated:', theme)
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
- ## Component Properties
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
- import { argbFromHex, themeFromSourceColor } from '@material/material-color-utilities';
72
-
73
- // Generates full MD3 color palette
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
- ## Examples
78
-
79
- ### App-Wide Theme
80
- ```html
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
- ### Component-Level Theming
90
- ```html
91
- <!-- Different sections with different themes -->
92
- <div class="dashboard">
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
- ### Theme Overrides
125
- ```html
126
- <schmancy-theme
127
- color="#FF5722"
128
- .theme="${{
129
- sys: {
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
- ## Generated CSS Properties
146
-
147
- The theme generates a comprehensive set of CSS custom properties:
148
-
149
- ```css
150
- /* Primary colors */
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
- /* Secondary colors */
157
- --schmancy-sys-color-secondary-default
158
- --schmancy-sys-color-secondary-onDefault
159
- --schmancy-sys-color-secondary-container
160
- --schmancy-sys-color-secondary-onContainer
97
+ ### `toggleFullscreen()`
98
+ Toggle fullscreen state.
99
+ ```typescript
100
+ theme.toggleFullscreen()
101
+ ```
161
102
 
162
- /* Tertiary colors */
163
- --schmancy-sys-color-tertiary-default
164
- --schmancy-sys-color-tertiary-onDefault
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
- /* Surface colors */
167
- --schmancy-sys-color-surface-default
168
- --schmancy-sys-color-surface-on
169
- --schmancy-sys-color-surface-container
170
- --schmancy-sys-color-surface-containerHigh
171
- --schmancy-sys-color-surface-containerHighest
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
- /* And many more... */
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
- ## Auto Color Scheme Detection
129
+ ## Theme Controls Component
177
130
 
178
- ```javascript
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
- // Reactive updates when system preference changes
183
- scheme === 'auto' && mediaQuery.addEventListener('change', updateTheme);
133
+ ```html
134
+ <schmancy-theme-controls
135
+ .customColors=${['#6750A4', '#0061A4', '#006E1C']}
136
+ ></schmancy-theme-controls>
184
137
  ```
185
138
 
186
- ## Random Color Generation
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
- When no color is specified, generates a random color:
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
- ```javascript
191
- generateRandomColor() {
192
- const randomColor = Math.floor(Math.random() * 16777215).toString(16);
193
- return '#' + randomColor.padStart(6, '0');
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
- ## Context Provider
198
-
199
- The theme component provides its theme via Lit Context:
174
+ ## Complete Material Design 3 Token System
200
175
 
201
- ```javascript
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
- // In child components
208
- @consume({ context: themeContext })
209
- theme: TSchmancyTheme;
210
- ```
178
+ ### Extended Color System
211
179
 
212
- ## Advanced Usage
180
+ Beyond primary/secondary/tertiary/error, the theme includes:
213
181
 
214
- ### Nested Themes
215
- ```html
216
- <schmancy-theme color="#2196F3" scheme="light">
217
- <div class="main-content">
218
- <!-- Blue light theme -->
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
- // Switch scheme
237
- themeEl.scheme = 'dark';
189
+ theme.theme.warning // Warning states (#FFB800 base)
190
+ theme.theme.onWarning
191
+ theme.theme.warningContainer
192
+ theme.theme.onWarningContainer
238
193
 
239
- // Apply custom overrides
240
- themeEl.theme = {
241
- sys: {
242
- color: {
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
- ## Theme Service API
200
+ ### Surface System
252
201
 
253
- The theme service provides programmatic control over the theme system with reactive observables for state management.
202
+ Complete surface hierarchy with proper elevation:
254
203
 
255
- ### Service Methods
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
- #### `getCurrentTheme()`
258
- Returns the current theme configuration.
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
- ```typescript
261
- const theme = themeService.getCurrentTheme()
262
- console.log(theme.mode) // 'light' | 'dark' | 'auto'
263
- console.log(theme.primaryColor) // hex color string
264
- console.log(theme.isDark) // boolean
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
- #### `setMode(mode: 'light' | 'dark' | 'auto')`
268
- Sets the theme mode.
225
+ ### Typography System
226
+
227
+ Complete type scale with three axes:
269
228
 
270
229
  ```typescript
271
- // Force light mode
272
- themeService.setMode('light')
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
- // Force dark mode
275
- themeService.setMode('dark')
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
- // Auto mode (follows system preference)
278
- themeService.setMode('auto')
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
- #### `setPrimaryColor(color: string)`
282
- Sets the primary color and regenerates the theme palette.
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
- ```typescript
285
- themeService.setPrimaryColor('#6750A4')
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
- #### `setTheme(theme: ThemeConfig)`
289
- Sets the complete theme configuration at once.
256
+ ### Motion System
290
257
 
291
- ```typescript
292
- themeService.setTheme({
293
- mode: 'dark',
294
- primaryColor: '#00897B',
295
- fontFamily: 'Roboto',
296
- borderRadius: 'medium'
297
- })
298
- ```
258
+ Sophisticated animation tokens:
299
259
 
300
- #### `reset()`
301
- Resets the theme to default settings.
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
- themeService.reset()
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
- ### Reactive Subscriptions
307
+ ### Elevation System
308
308
 
309
- The theme service exposes RxJS observables for reactive updates:
309
+ Elevation with tinted shadows in dark mode:
310
310
 
311
- #### `theme$` - Complete Theme State
312
311
  ```typescript
313
- import { takeUntil } from 'rxjs'
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
- themeService.theme$
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
- #### `mode$` - Mode Changes Only
324
- ```typescript
325
- themeService.mode$
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
- themeService.primaryColor$
335
- .pipe(takeUntil(this.disconnecting))
336
- .subscribe(color => {
337
- console.log('Primary color changed to:', color)
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
- ### Using with Lit Context
335
+ ### Spacing System
342
336
 
343
- Components can also access theme state via context:
337
+ 4dp grid spacing:
344
338
 
345
339
  ```typescript
346
- import { select } from '@schmancy/index'
347
- // Or specific import: import { select } from '@schmancy/store'
348
- import { themeContext } from '@schmancy/index'
349
- // Or specific import: import { themeContext } from '@schmancy/theme'
350
-
351
- @customElement('my-component')
352
- class MyComponent extends LitElement {
353
- @select(themeContext) theme!: ThemeState
354
-
355
- render() {
356
- return html`
357
- <div>Current mode: ${this.theme.mode}</div>
358
- <div>Is dark: ${this.theme.isDark}</div>
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
- ### Practical Examples
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
- @customElement('theme-toggle')
370
- export class ThemeToggle extends LitElement {
371
- @state() private currentMode: 'light' | 'dark' | 'auto' = 'auto'
360
+ // No manual localStorage code needed!
361
+ // Settings persist automatically via context
372
362
 
373
- connectedCallback() {
374
- super.connectedCallback()
363
+ // The context key 'schmancy-theme-settings' stores:
364
+ // - scheme: 'dark' | 'light' | 'auto'
365
+ // - color: hex color string
375
366
 
376
- themeService.mode$
377
- .pipe(takeUntil(this.disconnecting))
378
- .subscribe(mode => {
379
- this.currentMode = mode
380
- })
381
- }
367
+ // Automatic restoration on page load
368
+ // Just use the service - persistence is handled
369
+ ```
382
370
 
383
- private toggleMode() {
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
- render() {
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
- return html`
395
- <schmancy-button @click=${this.toggleMode}>
396
- <schmancy-icon slot="leading">${icon}</schmancy-icon>
397
- ${this.currentMode}
398
- </schmancy-button>
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
- #### Dynamic Color Picker
405
- ```typescript
406
- @customElement('color-picker')
407
- export class ColorPicker extends LitElement {
408
- @state() private selectedColor = '#6750A4'
395
+ ## Advanced Patterns
409
396
 
410
- private colors = [
411
- { name: 'Purple', value: '#6750A4' },
412
- { name: 'Blue', value: '#0061A4' },
413
- { name: 'Green', value: '#006E1C' },
414
- { name: 'Orange', value: '#D84315' },
415
- { name: 'Pink', value: '#C2185B' }
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
- themeService.primaryColor$
422
- .pipe(takeUntil(this.disconnecting))
423
- .subscribe(color => {
424
- this.selectedColor = color
425
- })
426
- }
427
-
428
- private selectColor(color: string) {
429
- themeService.setPrimaryColor(color)
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="flex gap-2 p-4">
435
- ${this.colors.map(color => html`
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
- #### Persisting Theme Preferences
454
- ```typescript
455
- import { debounceTime } from 'rxjs'
432
+ ### Custom Color Presets with Categories
456
433
 
457
- // Save theme to localStorage
458
- class ThemePersistence {
459
- constructor() {
460
- // Load saved theme on initialization
461
- this.loadTheme()
434
+ ```typescript
435
+ interface ColorPreset {
436
+ category: string
437
+ colors: Array<{ name: string; value: string }>
438
+ }
462
439
 
463
- // Save theme changes
464
- themeService.theme$
465
- .pipe(
466
- debounceTime(500) // Debounce to avoid excessive saves
467
- )
468
- .subscribe(theme => {
469
- this.saveTheme(theme)
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
- private loadTheme() {
474
- const saved = localStorage.getItem('user-theme')
475
- if (saved) {
476
- try {
477
- const theme = JSON.parse(saved)
478
- themeService.setTheme(theme)
479
- } catch (e) {
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
- private saveTheme(theme: ThemeState) {
486
- localStorage.setItem('user-theme', JSON.stringify({
487
- mode: theme.mode,
488
- primaryColor: theme.primaryColor
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
- #### Responding to System Preferences
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
- // Subscribe to theme changes
508
- themeService.theme$
509
- .pipe(takeUntil(this.disconnecting))
510
- .subscribe(theme => {
511
- this.isAuto = theme.mode === 'auto'
512
- this.isDark = theme.isDark
513
- })
514
-
515
- // Listen to system preference changes
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
- ## TypeScript Types
524
+ ### Theme-Aware Data Visualization
539
525
 
540
526
  ```typescript
541
- interface ThemeConfig {
542
- mode: 'light' | 'dark' | 'auto'
543
- primaryColor: string
544
- fontFamily?: string
545
- borderRadius?: 'none' | 'small' | 'medium' | 'large' | 'full'
546
- contrast?: 'standard' | 'medium' | 'high'
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
- interface ThemeState extends ThemeConfig {
550
- isDark: boolean
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
- interface ThemeService {
557
- // Observables
558
- theme$: Observable<ThemeState>
559
- mode$: Observable<'light' | 'dark' | 'auto'>
560
- primaryColor$: Observable<string>
561
-
562
- // Methods
563
- getCurrentTheme(): ThemeState
564
- setMode(mode: 'light' | 'dark' | 'auto'): void
565
- setPrimaryColor(color: string): void
566
- setTheme(theme: ThemeConfig): void
567
- reset(): void
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
- ## Best Practices
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
- ## CSS Variables Reference
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
- /* Always use CSS variables for theme-aware styling */
588
- .my-component {
589
- /* Backgrounds */
590
- background: var(--schmancy-sys-color-surface-default);
634
+ /* Display scale */
635
+ --schmancy-typeface-scale-display-large
636
+ --schmancy-typeface-scale-display-medium
637
+ --schmancy-typeface-scale-display-small
591
638
 
592
- /* Text colors */
593
- color: var(--schmancy-sys-color-surface-on);
639
+ /* Headline scale */
640
+ --schmancy-typeface-scale-headline-large
641
+ --schmancy-typeface-scale-headline-medium
642
+ --schmancy-typeface-scale-headline-small
594
643
 
595
- /* Borders */
596
- border: 1px solid var(--schmancy-sys-color-outline);
644
+ /* Title scale */
645
+ --schmancy-typeface-scale-title-large
646
+ --schmancy-typeface-scale-title-medium
647
+ --schmancy-typeface-scale-title-small
597
648
 
598
- /* Elevation/shadows */
599
- box-shadow: var(--schmancy-sys-elevation-1);
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
- /* Semantic color usage */
603
- .primary-action {
604
- background: var(--schmancy-sys-color-primary-default);
605
- color: var(--schmancy-sys-color-primary-onDefault);
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
- ### Complete Variable List
615
-
616
- #### Primary Colors
617
- - `--schmancy-sys-color-primary-default`
618
- - `--schmancy-sys-color-primary-onDefault`
619
- - `--schmancy-sys-color-primary-container`
620
- - `--schmancy-sys-color-primary-onContainer`
621
-
622
- #### Secondary Colors
623
- - `--schmancy-sys-color-secondary-default`
624
- - `--schmancy-sys-color-secondary-onDefault`
625
- - `--schmancy-sys-color-secondary-container`
626
- - `--schmancy-sys-color-secondary-onContainer`
627
-
628
- #### Tertiary Colors
629
- - `--schmancy-sys-color-tertiary-default`
630
- - `--schmancy-sys-color-tertiary-onDefault`
631
- - `--schmancy-sys-color-tertiary-container`
632
- - `--schmancy-sys-color-tertiary-onContainer`
633
-
634
- #### Error Colors
635
- - `--schmancy-sys-color-error-default`
636
- - `--schmancy-sys-color-error-onDefault`
637
- - `--schmancy-sys-color-error-container`
638
- - `--schmancy-sys-color-error-onContainer`
639
-
640
- #### Surface Colors
641
- - `--schmancy-sys-color-surface-default`
642
- - `--schmancy-sys-color-surface-on`
643
- - `--schmancy-sys-color-surface-onVariant`
644
- - `--schmancy-sys-color-surface-container`
645
- - `--schmancy-sys-color-surface-containerLow`
646
- - `--schmancy-sys-color-surface-containerHigh`
647
- - `--schmancy-sys-color-surface-containerHighest`
648
-
649
- #### Background & Outline
650
- - `--schmancy-sys-color-background-default`
651
- - `--schmancy-sys-color-background-on`
652
- - `--schmancy-sys-color-outline-default`
653
- - `--schmancy-sys-color-outline-variant`
654
-
655
- ## Migration Guide
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
- ### From Hardcoded Colors
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
- /* Before - Hardcoded colors */
661
- .card {
662
- background: #ffffff;
663
- color: #000000;
664
- border: 1px solid #e0e0e0;
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
- /* After - Theme-aware */
668
- .card {
669
- background: var(--schmancy-sys-color-surface-default);
670
- color: var(--schmancy-sys-color-surface-on);
671
- border: 1px solid var(--schmancy-sys-color-outline-variant);
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
- ### From CSS-in-JS
742
+ ## Fullscreen Integration
743
+
744
+ Navigation components automatically respond to fullscreen:
676
745
 
677
746
  ```typescript
678
- // Before - CSS-in-JS theme object
679
- const styles = {
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
- // After - CSS with variables
687
- static styles = css`
688
- .card {
689
- background: var(--schmancy-sys-color-surface-default);
690
- color: var(--schmancy-sys-color-surface-on);
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
- ### From Manual Dark Mode
696
-
697
- ```typescript
698
- // Before - Manual dark mode handling
699
- @state() isDark = false
759
+ ## System Preference Detection
700
760
 
701
- render() {
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
- // After - Automatic with theme service
710
- render() {
711
- // CSS variables automatically update
712
- return html`
713
- <div>
714
- <!-- content automatically themed -->
715
- </div>
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
- ## Advanced Patterns
775
+ ## Best Practices
721
776
 
722
- ### Theme-Aware Component
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
- ```typescript
725
- @customElement('themed-card')
726
- export class ThemedCard extends LitElement {
727
- @select(themeContext) theme!: ThemeState
788
+ ## Common Patterns
728
789
 
729
- static styles = css`
730
- :host {
731
- display: block;
732
- background: var(--schmancy-sys-color-surface-container);
733
- color: var(--schmancy-sys-color-surface-on);
734
- border-radius: var(--schmancy-sys-shape-corner-medium);
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
- :host([elevated]) {
740
- box-shadow: var(--schmancy-sys-elevation-2);
741
- }
797
+ connectedCallback() {
798
+ super.connectedCallback()
742
799
 
743
- .header {
744
- color: var(--schmancy-sys-color-primary-default);
745
- font-size: var(--schmancy-sys-typescale-headline-small-size);
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="header">
752
- <slot name="header"></slot>
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
- ### Theme Presets
761
-
762
- ```typescript
763
- class ThemePresets {
764
- static readonly presets = {
765
- corporate: {
766
- mode: 'light' as const,
767
- primaryColor: '#003D82',
768
- fontFamily: 'Inter, system-ui',
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
- static apply(presetName: keyof typeof ThemePresets.presets) {
796
- const preset = ThemePresets.presets[presetName]
797
- themeService.setTheme(preset)
851
+ private exitFullscreen() {
852
+ theme.setFullscreen(false)
853
+ document.exitFullscreen()
798
854
  }
799
- }
800
855
 
801
- // Usage
802
- ThemePresets.apply('corporate')
856
+ render() {
857
+ return html`
858
+ <video ${ref(this.videoRef)}>
859
+ <!-- Video content -->
860
+ </video>
861
+ `
862
+ }
863
+ }
803
864
  ```
804
865
 
805
- ### Multi-Brand Support
806
-
866
+ ### Dynamic Motion Timing
807
867
  ```typescript
808
- class BrandManager {
809
- private brands = {
810
- main: {
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
- switchBrand(brandKey: keyof typeof this.brands) {
821
- const brand = this.brands[brandKey]
822
- themeService.setPrimaryColor(brand.primaryColor)
823
- // Update logo and other brand assets
824
- this.updateBrandAssets(brand)
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
- private updateBrandAssets(brand: any) {
828
- // Update logos, fonts, etc.
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
- ## Testing Themes
901
+ ## Integration with Theme Component
834
902
 
835
- ```typescript
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
- it('renders correctly in light mode', async () => {
843
- themeService.setMode('light')
844
- const el = await fixture(html`<themed-component></themed-component>`)
845
- // Test light mode rendering
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
- it('responds to theme changes', async () => {
855
- const el = await fixture(html`<themed-component></themed-component>`)
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
- themeService.setPrimaryColor('#FF5722')
858
- await el.updateComplete
918
+ ## Error Handling
859
919
 
860
- // Verify component updated with new theme
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 Optimization
940
+ ## Performance Considerations
866
941
 
867
- ### Debouncing Theme Changes
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
- import { debounceTime, distinctUntilChanged } from 'rxjs'
953
+ // Old way
954
+ localStorage.setItem('theme', 'dark')
955
+ document.body.classList.add('dark-theme')
871
956
 
872
- themeService.theme$
873
- .pipe(
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
- ### Lazy Loading Theme Components
887
-
961
+ From custom CSS variables:
888
962
  ```typescript
889
- // Only load theme UI when needed
890
- async function openThemeSettings() {
891
- const { ThemeSettings } = await import('./theme-settings')
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
- ### Common Issues
900
-
901
- 1. **Theme not applying**: Ensure theme component or service is initialized at app root
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
- - [Theme Button](./theme-button.md) - Theme switcher
910
- - [Surface](./surface.md) - Themed containers
911
- - [Button](./button.md) - Themed interactions
912
- - [Card](./card.md) - Themed content
972
+ ## Summary
913
973
 
914
- ## Use Cases
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
- 1. **App Theming**: Consistent app-wide styling
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.