@mhmo91/schmancy 0.10.15 → 0.10.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (572) hide show
  1. package/custom-elements.json +2554 -3086
  2. package/dist/active-host-BP0zy_Y9.js +63 -0
  3. package/dist/{active-host-CvNYoprt.js.map → active-host-BP0zy_Y9.js.map} +1 -1
  4. package/dist/active-host-jH3iloCR.cjs +1 -0
  5. package/dist/{active-host-CcIa2tmW.cjs.map → active-host-jH3iloCR.cjs.map} +1 -1
  6. package/dist/agent/flow-CvG1fLW5.js.map +1 -1
  7. package/dist/agent/schmancy.agent.js +5694 -5500
  8. package/dist/agent/schmancy.agent.js.map +1 -1
  9. package/dist/agent/schmancy.manifest.json +971 -1189
  10. package/dist/agent/vendor-material-color-DcL7ZPxx.js.map +1 -1
  11. package/dist/{animation-CO_Csq84.cjs.map → animation-CCOIW4wJ.cjs.map} +1 -1
  12. package/dist/{animation-BK-8BwY8.js.map → animation-DCznELuT.js.map} +1 -1
  13. package/dist/{area-C_kgZZhN.js → area-ChxsDTu_.js} +2 -2
  14. package/dist/{area-C_kgZZhN.js.map → area-ChxsDTu_.js.map} +1 -1
  15. package/dist/{area-DFPtKzWy.cjs → area-Qt6yUnuA.cjs} +3 -3
  16. package/dist/{area-DFPtKzWy.cjs.map → area-Qt6yUnuA.cjs.map} +1 -1
  17. package/dist/area.cjs +1 -1
  18. package/dist/area.js +2 -2
  19. package/dist/{audio-CluX8Qpq.cjs → audio-D-TZzpXF.cjs} +1 -1
  20. package/dist/{audio-CluX8Qpq.cjs.map → audio-D-TZzpXF.cjs.map} +1 -1
  21. package/dist/{audio-DcXphulJ.js → audio-DS43uoRA.js} +1 -1
  22. package/dist/{audio-DcXphulJ.js.map → audio-DS43uoRA.js.map} +1 -1
  23. package/dist/audio.cjs +1 -1
  24. package/dist/audio.js +2 -2
  25. package/dist/{autocomplete-DWSuwSRS.js → autocomplete-CXvUjMD-.js} +46 -71
  26. package/dist/autocomplete-CXvUjMD-.js.map +1 -0
  27. package/dist/autocomplete-Ck2zbdF9.cjs +115 -0
  28. package/dist/autocomplete-Ck2zbdF9.cjs.map +1 -0
  29. package/dist/autocomplete.cjs +1 -1
  30. package/dist/autocomplete.js +1 -1
  31. package/dist/avatar.cjs +2 -2
  32. package/dist/avatar.cjs.map +1 -1
  33. package/dist/avatar.js +3 -3
  34. package/dist/avatar.js.map +1 -1
  35. package/dist/badge.cjs +1 -1
  36. package/dist/badge.js +1 -1
  37. package/dist/{boat-CZma2ojF.js → boat-Bj0wVcZi.js} +5 -5
  38. package/dist/{boat-CZma2ojF.js.map → boat-Bj0wVcZi.js.map} +1 -1
  39. package/dist/{boat-Dy6cc3hB.cjs → boat-DpFkILFF.cjs} +2 -2
  40. package/dist/{boat-Dy6cc3hB.cjs.map → boat-DpFkILFF.cjs.map} +1 -1
  41. package/dist/boat.cjs +1 -1
  42. package/dist/boat.js +1 -1
  43. package/dist/breadcrumb.cjs +3 -3
  44. package/dist/breadcrumb.cjs.map +1 -1
  45. package/dist/breadcrumb.js +2 -2
  46. package/dist/breadcrumb.js.map +1 -1
  47. package/dist/{busy-DCsqryvq.cjs → busy-CtcnclA3.cjs} +3 -3
  48. package/dist/{busy-DCsqryvq.cjs.map → busy-CtcnclA3.cjs.map} +1 -1
  49. package/dist/{busy-DeV2ByMw.js → busy-CyZSBnZP.js} +2 -2
  50. package/dist/{busy-DeV2ByMw.js.map → busy-CyZSBnZP.js.map} +1 -1
  51. package/dist/busy.cjs +1 -1
  52. package/dist/busy.js +1 -1
  53. package/dist/button.cjs +4 -4
  54. package/dist/button.cjs.map +1 -1
  55. package/dist/button.js +19 -4
  56. package/dist/button.js.map +1 -1
  57. package/dist/{card--GgSX4X5.cjs → card-Cl6jp1yX.cjs} +5 -5
  58. package/dist/{card--GgSX4X5.cjs.map → card-Cl6jp1yX.cjs.map} +1 -1
  59. package/dist/{card-BTTsHzJJ.js → card-nYZCKmOO.js} +3 -3
  60. package/dist/{card-BTTsHzJJ.js.map → card-nYZCKmOO.js.map} +1 -1
  61. package/dist/card.cjs +1 -1
  62. package/dist/card.js +1 -1
  63. package/dist/{checkbox-NNReP9s_.cjs → checkbox-BeNo0ZGt.cjs} +4 -4
  64. package/dist/{checkbox-Cj5j-ppk.js.map → checkbox-BeNo0ZGt.cjs.map} +1 -1
  65. package/dist/{checkbox-Cj5j-ppk.js → checkbox-DiUrZiyc.js} +17 -30
  66. package/dist/checkbox-DiUrZiyc.js.map +1 -0
  67. package/dist/checkbox.cjs +1 -1
  68. package/dist/checkbox.js +1 -1
  69. package/dist/{chips-CP-CbfoZ.js → chips-CfPFXv7Z.js} +5 -5
  70. package/dist/{chips-CP-CbfoZ.js.map → chips-CfPFXv7Z.js.map} +1 -1
  71. package/dist/{chips-iporOXxK.cjs → chips-DK6m-VCM.cjs} +5 -5
  72. package/dist/{chips-iporOXxK.cjs.map → chips-DK6m-VCM.cjs.map} +1 -1
  73. package/dist/chips.cjs +1 -1
  74. package/dist/chips.js +2 -2
  75. package/dist/connectivity.cjs +2 -2
  76. package/dist/connectivity.cjs.map +1 -1
  77. package/dist/connectivity.js +3 -3
  78. package/dist/connectivity.js.map +1 -1
  79. package/dist/content-drawer.cjs +1 -1
  80. package/dist/content-drawer.js +1 -1
  81. package/dist/{context-DJTJnSK4.js.map → context-6oXCZmZN.js.map} +1 -1
  82. package/dist/{context-BpCETidA.cjs.map → context-CRZeiCqq.cjs.map} +1 -1
  83. package/dist/{cursor-glow-Bulq-38P.cjs → cursor-glow-C8LgCxpI.cjs} +1 -1
  84. package/dist/{cursor-glow-Bulq-38P.cjs.map → cursor-glow-C8LgCxpI.cjs.map} +1 -1
  85. package/dist/{cursor-glow-Ah7VXSj7.js → cursor-glow-Cs2XLDB9.js} +1 -1
  86. package/dist/{cursor-glow-Ah7VXSj7.js.map → cursor-glow-Cs2XLDB9.js.map} +1 -1
  87. package/dist/date-range-DA6anfcF.cjs +131 -0
  88. package/dist/date-range-DA6anfcF.cjs.map +1 -0
  89. package/dist/{date-range-CgNujP8r.js → date-range-DjlF2u7o.js} +124 -89
  90. package/dist/date-range-DjlF2u7o.js.map +1 -0
  91. package/dist/date-range-inline-BfYK795W.cjs +43 -0
  92. package/dist/{date-range-inline-D4IjOOO0.cjs.map → date-range-inline-BfYK795W.cjs.map} +1 -1
  93. package/dist/{date-range-inline-C2PXX_GY.js → date-range-inline-n7y_H6PJ.js} +2 -2
  94. package/dist/{date-range-inline-C2PXX_GY.js.map → date-range-inline-n7y_H6PJ.js.map} +1 -1
  95. package/dist/date-range-inline.cjs +1 -1
  96. package/dist/date-range-inline.js +1 -1
  97. package/dist/date-range.cjs +1 -1
  98. package/dist/date-range.js +1 -1
  99. package/dist/delay.cjs +2 -2
  100. package/dist/delay.cjs.map +1 -1
  101. package/dist/delay.js +3 -3
  102. package/dist/delay.js.map +1 -1
  103. package/dist/{details-DT2b3xOn.cjs → details-BdAVsLl-.cjs} +2 -2
  104. package/dist/{details-DT2b3xOn.cjs.map → details-BdAVsLl-.cjs.map} +1 -1
  105. package/dist/{details-VjaNwtfd.js → details-CS_ToAOj.js} +6 -6
  106. package/dist/{details-VjaNwtfd.js.map → details-CS_ToAOj.js.map} +1 -1
  107. package/dist/details.cjs +1 -1
  108. package/dist/details.js +1 -1
  109. package/dist/directives.cjs +1 -1
  110. package/dist/directives.cjs.map +1 -1
  111. package/dist/directives.js +5 -5
  112. package/dist/directives.js.map +1 -1
  113. package/dist/discovery.js.map +1 -1
  114. package/dist/{divider-BMO8pzEO.js → divider-COLK0RbT.js} +2 -2
  115. package/dist/{divider-BMO8pzEO.js.map → divider-COLK0RbT.js.map} +1 -1
  116. package/dist/{divider-BW33TZ-X.cjs → divider-CvWAnvdO.cjs} +2 -2
  117. package/dist/{divider-BW33TZ-X.cjs.map → divider-CvWAnvdO.cjs.map} +1 -1
  118. package/dist/divider.cjs +1 -1
  119. package/dist/divider.js +1 -1
  120. package/dist/dropdown.cjs +3 -3
  121. package/dist/dropdown.cjs.map +1 -1
  122. package/dist/dropdown.js +2 -2
  123. package/dist/dropdown.js.map +1 -1
  124. package/dist/{expand-DbELKKOt.js → expand-D9LzmpoV.js} +5 -5
  125. package/dist/{expand-DbELKKOt.js.map → expand-D9LzmpoV.js.map} +1 -1
  126. package/dist/{expand-_f5EUKWB.cjs → expand-r2sATPUJ.cjs} +3 -3
  127. package/dist/{expand-_f5EUKWB.cjs.map → expand-r2sATPUJ.cjs.map} +1 -1
  128. package/dist/expand.cjs +1 -1
  129. package/dist/expand.js +1 -1
  130. package/dist/float-2nHYuBx-.cjs +1 -0
  131. package/dist/{float-CKmd-0-t.cjs.map → float-2nHYuBx-.cjs.map} +1 -1
  132. package/dist/{float-B6RBb2dN.js → float-BWy39CXr.js} +2 -2
  133. package/dist/{float-B6RBb2dN.js.map → float-BWy39CXr.js.map} +1 -1
  134. package/dist/float.cjs +1 -1
  135. package/dist/float.js +1 -1
  136. package/dist/form-D1iJOLVb.js +267 -0
  137. package/dist/form-D1iJOLVb.js.map +1 -0
  138. package/dist/form-D9K1GhlP.cjs +42 -0
  139. package/dist/form-D9K1GhlP.cjs.map +1 -0
  140. package/dist/form.cjs +1 -1
  141. package/dist/form.js +9 -2
  142. package/dist/handover/agent-runtime-followups.md +1 -1
  143. package/dist/handover/agent-runtime-v1.md +3 -3
  144. package/dist/{hashContent-Bobsobip.cjs.map → hashContent-Ck6laKlk.cjs.map} +1 -1
  145. package/dist/{hashContent-BU6jl5ih.js.map → hashContent-dJrI-9sc.js.map} +1 -1
  146. package/dist/{icons-r-S17M8U.cjs → icons-BXp4vbnW.cjs} +2 -2
  147. package/dist/{icons-r-S17M8U.cjs.map → icons-BXp4vbnW.cjs.map} +1 -1
  148. package/dist/{icons-CoDo95Cu.js → icons-COrlmBPB.js} +3 -3
  149. package/dist/{icons-CoDo95Cu.js.map → icons-COrlmBPB.js.map} +1 -1
  150. package/dist/icons.cjs +1 -1
  151. package/dist/icons.js +1 -1
  152. package/dist/{iframe-P9c_qg1-.cjs → iframe-BwXj6mLp.cjs} +2 -2
  153. package/dist/{iframe-P9c_qg1-.cjs.map → iframe-BwXj6mLp.cjs.map} +1 -1
  154. package/dist/{iframe-k4oI-TIj.js → iframe-CPNsIy7k.js} +2 -2
  155. package/dist/{iframe-k4oI-TIj.js.map → iframe-CPNsIy7k.js.map} +1 -1
  156. package/dist/iframe.cjs +1 -1
  157. package/dist/iframe.js +1 -1
  158. package/dist/index.cjs +1 -1
  159. package/dist/index.js +60 -60
  160. package/dist/input-BGrF2qVq.cjs +52 -0
  161. package/dist/input-BGrF2qVq.cjs.map +1 -0
  162. package/dist/{input-D95GjINh.js → input-C1SnMNuQ.js} +103 -104
  163. package/dist/input-C1SnMNuQ.js.map +1 -0
  164. package/dist/{input-chip-DpC_XEKN.js → input-chip-CtQ0pH5b.js} +2 -2
  165. package/dist/{input-chip-DpC_XEKN.js.map → input-chip-CtQ0pH5b.js.map} +1 -1
  166. package/dist/{input-chip-D0ZXqTt5.cjs → input-chip-DZktYohr.cjs} +2 -2
  167. package/dist/{input-chip-D0ZXqTt5.cjs.map → input-chip-DZktYohr.cjs.map} +1 -1
  168. package/dist/input.cjs +1 -1
  169. package/dist/input.js +1 -1
  170. package/dist/json.cjs +2 -2
  171. package/dist/json.cjs.map +1 -1
  172. package/dist/json.js +3 -3
  173. package/dist/json.js.map +1 -1
  174. package/dist/kbd.cjs +2 -2
  175. package/dist/kbd.cjs.map +1 -1
  176. package/dist/kbd.js +2 -2
  177. package/dist/kbd.js.map +1 -1
  178. package/dist/{layout-CXPNsUIo.js → layout-BH28sKGc.js} +1 -1
  179. package/dist/{layout-CXPNsUIo.js.map → layout-BH28sKGc.js.map} +1 -1
  180. package/dist/{layout-Zhe7wSZ_.cjs → layout-Delq-QvR.cjs} +1 -1
  181. package/dist/{layout-Zhe7wSZ_.cjs.map → layout-Delq-QvR.cjs.map} +1 -1
  182. package/dist/layout.cjs +1 -1
  183. package/dist/layout.js +1 -1
  184. package/dist/{lazy-Dq9mRRjT.cjs.map → lazy-CayEFyC3.cjs.map} +1 -1
  185. package/dist/{lazy-B0ia54tT.js.map → lazy-D-bO2r4m.js.map} +1 -1
  186. package/dist/{lightbox-CovQtmyn.js → lightbox-CLwpaiai.js} +9 -9
  187. package/dist/{lightbox-CovQtmyn.js.map → lightbox-CLwpaiai.js.map} +1 -1
  188. package/dist/{lightbox-C-yHeoK0.cjs → lightbox-Ck6BpN5u.cjs} +3 -3
  189. package/dist/{lightbox-C-yHeoK0.cjs.map → lightbox-Ck6BpN5u.cjs.map} +1 -1
  190. package/dist/lightbox.cjs +1 -1
  191. package/dist/lightbox.js +1 -1
  192. package/dist/{list-C1pR9vhu.js → list-Bmce1Rb8.js} +2 -2
  193. package/dist/{list-C1pR9vhu.js.map → list-Bmce1Rb8.js.map} +1 -1
  194. package/dist/{list-CAijuky4.cjs → list-EmRwSpTU.cjs} +3 -3
  195. package/dist/{list-CAijuky4.cjs.map → list-EmRwSpTU.cjs.map} +1 -1
  196. package/dist/list.cjs +1 -1
  197. package/dist/list.js +1 -1
  198. package/dist/{magnetic-BJgB1dVi.cjs → magnetic-Bgh7aHHI.cjs} +1 -1
  199. package/dist/{magnetic-BJgB1dVi.cjs.map → magnetic-Bgh7aHHI.cjs.map} +1 -1
  200. package/dist/{magnetic-YwCNvtbB.js → magnetic-DxvoEz8_.js} +2 -2
  201. package/dist/{magnetic-YwCNvtbB.js.map → magnetic-DxvoEz8_.js.map} +1 -1
  202. package/dist/{menu-B59vZv9n.js → menu-BA_B7QOG.js} +3 -3
  203. package/dist/{menu-B59vZv9n.js.map → menu-BA_B7QOG.js.map} +1 -1
  204. package/dist/{menu-BaHO3Cip.cjs → menu-BTU3wGP6.cjs} +3 -3
  205. package/dist/{menu-BaHO3Cip.cjs.map → menu-BTU3wGP6.cjs.map} +1 -1
  206. package/dist/menu.cjs +1 -1
  207. package/dist/menu.js +1 -1
  208. package/dist/mixins-BOOu6q2n.cjs +298 -0
  209. package/dist/mixins-BOOu6q2n.cjs.map +1 -0
  210. package/dist/mixins-BWb9_e1s.js +680 -0
  211. package/dist/mixins-BWb9_e1s.js.map +1 -0
  212. package/dist/mixins.cjs +1 -1
  213. package/dist/mixins.js +2 -2
  214. package/dist/nav-drawer.cjs +1 -1
  215. package/dist/nav-drawer.js +1 -1
  216. package/dist/navigation-bar.cjs +1 -1
  217. package/dist/navigation-bar.js +1 -1
  218. package/dist/navigation-rail.cjs +3 -3
  219. package/dist/navigation-rail.cjs.map +1 -1
  220. package/dist/navigation-rail.js +2 -2
  221. package/dist/navigation-rail.js.map +1 -1
  222. package/dist/notification-CliGbcfU.cjs +23 -0
  223. package/dist/{notification-BC9nG8Sr.cjs.map → notification-CliGbcfU.cjs.map} +1 -1
  224. package/dist/{notification-BeLoVa47.js → notification-R2_Mf1HR.js} +4 -4
  225. package/dist/{notification-BeLoVa47.js.map → notification-R2_Mf1HR.js.map} +1 -1
  226. package/dist/notification.cjs +1 -1
  227. package/dist/notification.js +1 -1
  228. package/dist/{option-UvlSAcC4.js → option-DU1X4SDu.js} +2 -2
  229. package/dist/{option-UvlSAcC4.js.map → option-DU1X4SDu.js.map} +1 -1
  230. package/dist/{option-BWF4GBp-.cjs → option-Db98Ndzv.cjs} +2 -2
  231. package/dist/{option-BWF4GBp-.cjs.map → option-Db98Ndzv.cjs.map} +1 -1
  232. package/dist/option.cjs +1 -1
  233. package/dist/option.js +1 -1
  234. package/dist/{overlay-stack-DCDS17uj.js.map → overlay-stack-BR4iYivO.js.map} +1 -1
  235. package/dist/{overlay-stack-DPIe_aYv.cjs.map → overlay-stack-Dk0xETTy.cjs.map} +1 -1
  236. package/dist/overlay.cjs +2 -2
  237. package/dist/overlay.cjs.map +1 -1
  238. package/dist/{overlay.confirm-body-URtE1gI3.cjs → overlay.confirm-body-BkhNvr0c.cjs} +2 -2
  239. package/dist/{overlay.confirm-body-URtE1gI3.cjs.map → overlay.confirm-body-BkhNvr0c.cjs.map} +1 -1
  240. package/dist/{overlay.confirm-body-9W0B5QGv.js → overlay.confirm-body-uFp-0Zfh.js} +2 -2
  241. package/dist/{overlay.confirm-body-9W0B5QGv.js.map → overlay.confirm-body-uFp-0Zfh.js.map} +1 -1
  242. package/dist/overlay.js +8 -8
  243. package/dist/overlay.js.map +1 -1
  244. package/dist/{overlay.service-DnZTcKyJ.cjs → overlay.service-1YWfUD2S.cjs} +1 -1
  245. package/dist/{overlay.service-DnZTcKyJ.cjs.map → overlay.service-1YWfUD2S.cjs.map} +1 -1
  246. package/dist/{overlay.service-CVqs2Gu1.js → overlay.service-BcF12kGb.js} +2 -2
  247. package/dist/{overlay.service-CVqs2Gu1.js.map → overlay.service-BcF12kGb.js.map} +1 -1
  248. package/dist/page.cjs +2 -2
  249. package/dist/page.cjs.map +1 -1
  250. package/dist/page.js +5 -5
  251. package/dist/page.js.map +1 -1
  252. package/dist/{progress-C29Uw-WJ.js → progress-C9Y2D5cm.js} +2 -2
  253. package/dist/{progress-C29Uw-WJ.js.map → progress-C9Y2D5cm.js.map} +1 -1
  254. package/dist/{progress-CwzwY8Oe.cjs → progress-DiVTGAXa.cjs} +2 -2
  255. package/dist/{progress-CwzwY8Oe.cjs.map → progress-DiVTGAXa.cjs.map} +1 -1
  256. package/dist/progress.cjs +1 -1
  257. package/dist/progress.js +1 -1
  258. package/dist/{radio-group-CW8airhZ.js → radio-group-CAzjBI2n.js} +4 -4
  259. package/dist/radio-group-CAzjBI2n.js.map +1 -0
  260. package/dist/radio-group-DIRJyYv6.cjs +40 -0
  261. package/dist/radio-group-DIRJyYv6.cjs.map +1 -0
  262. package/dist/radio-group.cjs +1 -1
  263. package/dist/radio-group.js +1 -1
  264. package/dist/range.cjs +6 -4
  265. package/dist/range.cjs.map +1 -1
  266. package/dist/range.js +19 -15
  267. package/dist/range.js.map +1 -1
  268. package/dist/{reduced-motion-D-L12p7G.js.map → reduced-motion-D7LqTUMn.js.map} +1 -1
  269. package/dist/{reduced-motion-Ds-HjMzn.cjs.map → reduced-motion-Dzfp_w5x.cjs.map} +1 -1
  270. package/dist/{rxjs-utils-DCUHg_Ml.cjs.map → rxjs-utils-BKB2UM_j.cjs.map} +1 -1
  271. package/dist/{rxjs-utils-CVeJQ9KG.js.map → rxjs-utils-Dv9T9IpA.js.map} +1 -1
  272. package/dist/rxjs-utils.cjs +1 -1
  273. package/dist/rxjs-utils.js +1 -1
  274. package/dist/{scroll-BotoGcMU.js → scroll-BFHUtZOa.js} +2 -2
  275. package/dist/{scroll-BotoGcMU.js.map → scroll-BFHUtZOa.js.map} +1 -1
  276. package/dist/{scroll-CmhmUebp.cjs → scroll-nIZyoEMt.cjs} +2 -2
  277. package/dist/{scroll-CmhmUebp.cjs.map → scroll-nIZyoEMt.cjs.map} +1 -1
  278. package/dist/{search-BLCRsxIC.cjs.map → search-DPKoC-dT.cjs.map} +1 -1
  279. package/dist/{search-BTz7-Rev.js.map → search-MvIBA93K.js.map} +1 -1
  280. package/dist/{select-Dbn-CImU.js → select-7WqaUWBU.js} +52 -73
  281. package/dist/select-7WqaUWBU.js.map +1 -0
  282. package/dist/select-DTuf6p6T.cjs +56 -0
  283. package/dist/select-DTuf6p6T.cjs.map +1 -0
  284. package/dist/select.cjs +1 -1
  285. package/dist/select.js +1 -1
  286. package/dist/skeleton.cjs +2 -2
  287. package/dist/skeleton.cjs.map +1 -1
  288. package/dist/skeleton.js +2 -2
  289. package/dist/skeleton.js.map +1 -1
  290. package/dist/skills/SKILL.md +3 -0
  291. package/dist/skills/autocomplete.md +16 -3
  292. package/dist/skills/button.md +19 -0
  293. package/dist/skills/checkbox.md +19 -0
  294. package/dist/skills/date-range.md +19 -0
  295. package/dist/skills/form-ux-rules.md +55 -0
  296. package/dist/skills/form.md +121 -25
  297. package/dist/skills/input.md +19 -4
  298. package/dist/skills/range.md +15 -1
  299. package/dist/skills/schmancy/SKILL.md +3 -0
  300. package/dist/skills/schmancy/autocomplete.md +16 -3
  301. package/dist/skills/schmancy/button.md +19 -0
  302. package/dist/skills/schmancy/checkbox.md +19 -0
  303. package/dist/skills/schmancy/date-range.md +19 -0
  304. package/dist/skills/schmancy/form-ux-rules.md +55 -0
  305. package/dist/skills/schmancy/form.md +121 -25
  306. package/dist/skills/schmancy/input.md +19 -4
  307. package/dist/skills/schmancy/range.md +15 -1
  308. package/dist/skills/schmancy/select.md +13 -1
  309. package/dist/skills/schmancy/switch.md +21 -2
  310. package/dist/skills/schmancy/textarea.md +13 -0
  311. package/dist/skills/select.md +13 -1
  312. package/dist/skills/switch.md +21 -2
  313. package/dist/skills/textarea.md +13 -0
  314. package/dist/slider.cjs +3 -3
  315. package/dist/slider.cjs.map +1 -1
  316. package/dist/slider.js +2 -2
  317. package/dist/slider.js.map +1 -1
  318. package/dist/{sound.service-kKfsN0m-.js → sound.service-BIN2W7Rv.js} +1 -1
  319. package/dist/{sound.service-kKfsN0m-.js.map → sound.service-BIN2W7Rv.js.map} +1 -1
  320. package/dist/{sound.service-BGs6m0Cm.cjs → sound.service-DyY78ukR.cjs} +1 -1
  321. package/dist/{sound.service-BGs6m0Cm.cjs.map → sound.service-DyY78ukR.cjs.map} +1 -1
  322. package/dist/{splash-screen-DtkjCJYo.js → splash-screen-BcjjJSlK.js} +2 -2
  323. package/dist/{splash-screen-DtkjCJYo.js.map → splash-screen-BcjjJSlK.js.map} +1 -1
  324. package/dist/{splash-screen-DlQUv-kV.cjs → splash-screen-Kr1sPtME.cjs} +2 -2
  325. package/dist/{splash-screen-DlQUv-kV.cjs.map → splash-screen-Kr1sPtME.cjs.map} +1 -1
  326. package/dist/splash-screen.cjs +1 -1
  327. package/dist/splash-screen.js +1 -1
  328. package/dist/{src-DEUjlTsX.cjs → src-BbMJeLk9.cjs} +11 -11
  329. package/dist/{src-DEUjlTsX.cjs.map → src-BbMJeLk9.cjs.map} +1 -1
  330. package/dist/{src-D6e0adHi.js → src-DCu_mEk4.js} +40 -40
  331. package/dist/{src-D6e0adHi.js.map → src-DCu_mEk4.js.map} +1 -1
  332. package/dist/state-avic94Ft.cjs +1 -0
  333. package/dist/{state-DNdCPITt.cjs.map → state-avic94Ft.cjs.map} +1 -1
  334. package/dist/{state-BusMG6sM.js → state-nm8yzMPp.js} +1 -2
  335. package/dist/{state-BusMG6sM.js.map → state-nm8yzMPp.js.map} +1 -1
  336. package/dist/state.cjs +1 -1
  337. package/dist/state.js +2 -2
  338. package/dist/steps.cjs +3 -3
  339. package/dist/steps.cjs.map +1 -1
  340. package/dist/steps.js +2 -2
  341. package/dist/steps.js.map +1 -1
  342. package/dist/{surface-A82O1kgu.js → surface-BtMMHKol.js} +2 -2
  343. package/dist/{surface-A82O1kgu.js.map → surface-BtMMHKol.js.map} +1 -1
  344. package/dist/surface-CgXeKdGL.cjs +7 -0
  345. package/dist/{surface-BpppoNXN.cjs.map → surface-CgXeKdGL.cjs.map} +1 -1
  346. package/dist/surface.cjs +1 -1
  347. package/dist/surface.js +1 -1
  348. package/dist/switch.cjs +3 -3
  349. package/dist/switch.cjs.map +1 -1
  350. package/dist/switch.js +27 -43
  351. package/dist/switch.js.map +1 -1
  352. package/dist/table.cjs +3 -3
  353. package/dist/table.cjs.map +1 -1
  354. package/dist/table.js +2 -2
  355. package/dist/table.js.map +1 -1
  356. package/dist/{tabs-cVHHd1dY.js → tabs-81ADWQqa.js} +2 -2
  357. package/dist/{tabs-cVHHd1dY.js.map → tabs-81ADWQqa.js.map} +1 -1
  358. package/dist/{tabs-TO3UiBsm.cjs → tabs-DnG3K0bu.cjs} +2 -2
  359. package/dist/{tabs-TO3UiBsm.cjs.map → tabs-DnG3K0bu.cjs.map} +1 -1
  360. package/dist/tabs.cjs +1 -1
  361. package/dist/tabs.js +1 -1
  362. package/dist/teleport.cjs +1 -1
  363. package/dist/teleport.js +1 -1
  364. package/dist/textarea-3mWewuAf.js +186 -0
  365. package/dist/textarea-3mWewuAf.js.map +1 -0
  366. package/dist/textarea-BenjiTXB.cjs +43 -0
  367. package/dist/textarea-BenjiTXB.cjs.map +1 -0
  368. package/dist/textarea.cjs +1 -1
  369. package/dist/textarea.js +1 -1
  370. package/dist/{theme-CT408FqH.js → theme-CFPJW933.js} +9 -9
  371. package/dist/{theme-CT408FqH.js.map → theme-CFPJW933.js.map} +1 -1
  372. package/dist/theme-DNymrucy.cjs +181 -0
  373. package/dist/{theme-CpuF3D3q.cjs.map → theme-DNymrucy.cjs.map} +1 -1
  374. package/dist/{theme-button-pTb5-Wxx.js → theme-button-DC_shZ_7.js} +2 -2
  375. package/dist/{theme-button-pTb5-Wxx.js.map → theme-button-DC_shZ_7.js.map} +1 -1
  376. package/dist/theme-button-ENKa3TPT.cjs +8 -0
  377. package/dist/{theme-button-B6Xf-EiH.cjs.map → theme-button-ENKa3TPT.cjs.map} +1 -1
  378. package/dist/theme-button.cjs +1 -1
  379. package/dist/theme-button.js +1 -1
  380. package/dist/theme.cjs +1 -1
  381. package/dist/{theme.interface-B9TjbSBF.js.map → theme.interface-C2XNgsLB.js.map} +1 -1
  382. package/dist/{theme.interface-BujperTo.cjs.map → theme.interface-D4NeufQA.cjs.map} +1 -1
  383. package/dist/theme.js +4 -4
  384. package/dist/{theme.service-DIUo1mBP.js → theme.service-BOWIT_5k.js} +1 -1
  385. package/dist/{theme.service-DIUo1mBP.js.map → theme.service-BOWIT_5k.js.map} +1 -1
  386. package/dist/{theme.service-Cfk88qHK.cjs → theme.service-DkdH1t60.cjs} +1 -1
  387. package/dist/{theme.service-Cfk88qHK.cjs.map → theme.service-DkdH1t60.cjs.map} +1 -1
  388. package/dist/tooltip.js.map +1 -1
  389. package/dist/tree.cjs +2 -2
  390. package/dist/tree.cjs.map +1 -1
  391. package/dist/tree.js +2 -2
  392. package/dist/tree.js.map +1 -1
  393. package/dist/types.js.map +1 -1
  394. package/dist/typewriter.cjs.map +1 -1
  395. package/dist/typewriter.js.map +1 -1
  396. package/dist/typography.cjs +2 -2
  397. package/dist/typography.cjs.map +1 -1
  398. package/dist/typography.js +2 -2
  399. package/dist/typography.js.map +1 -1
  400. package/dist/{utils-kND2Z9Xg.js → utils-Cj_nRRyx.js} +2 -2
  401. package/dist/{utils-kND2Z9Xg.js.map → utils-Cj_nRRyx.js.map} +1 -1
  402. package/dist/{utils-Dt5PpmaQ.cjs → utils-D2QUu4-g.cjs} +1 -1
  403. package/dist/{utils-Dt5PpmaQ.cjs.map → utils-D2QUu4-g.cjs.map} +1 -1
  404. package/dist/utils.cjs +1 -1
  405. package/dist/utils.js +4 -4
  406. package/dist/visually-hidden.cjs +2 -2
  407. package/dist/visually-hidden.cjs.map +1 -1
  408. package/dist/visually-hidden.js +2 -2
  409. package/dist/visually-hidden.js.map +1 -1
  410. package/dist/{window-CuBcOxbc.js → window-BTecgE_U.js} +7 -7
  411. package/dist/{window-CuBcOxbc.js.map → window-BTecgE_U.js.map} +1 -1
  412. package/dist/{window-CSKvv4Ts.cjs → window-DGydMS0g.cjs} +2 -2
  413. package/dist/{window-CSKvv4Ts.cjs.map → window-DGydMS0g.cjs.map} +1 -1
  414. package/dist/window.cjs +1 -1
  415. package/dist/window.js +1 -1
  416. package/package.json +1 -1
  417. package/skills/schmancy/SKILL.md +3 -0
  418. package/skills/schmancy/autocomplete.md +16 -3
  419. package/skills/schmancy/button.md +19 -0
  420. package/skills/schmancy/checkbox.md +19 -0
  421. package/skills/schmancy/date-range.md +19 -0
  422. package/skills/schmancy/form-ux-rules.md +55 -0
  423. package/skills/schmancy/form.md +121 -25
  424. package/skills/schmancy/input.md +19 -4
  425. package/skills/schmancy/range.md +15 -1
  426. package/skills/schmancy/select.md +13 -1
  427. package/skills/schmancy/switch.md +21 -2
  428. package/skills/schmancy/textarea.md +13 -0
  429. package/src/button/button.test.ts +122 -0
  430. package/src/button/button.ts +36 -0
  431. package/src/{autocomplete → form/fields/autocomplete}/autocomplete.ts +48 -75
  432. package/src/{checkbox → form/fields/checkbox}/checkbox.test.ts +1 -1
  433. package/src/form/fields/checkbox/checkbox.ts +126 -0
  434. package/src/form/fields/date-range/date-range.test.ts +102 -0
  435. package/src/{date-range → form/fields/date-range}/date-range.ts +90 -7
  436. package/src/form/fields/index.ts +9 -0
  437. package/src/form/fields/input/input.test.ts +201 -0
  438. package/src/{input → form/fields/input}/input.ts +153 -238
  439. package/src/{radio-group → form/fields/radio-group}/radio-button.ts +1 -1
  440. package/src/{radio-group → form/fields/radio-group}/radio-group.ts +1 -1
  441. package/src/form/fields/range/range.test.ts +90 -0
  442. package/src/{range → form/fields/range}/range.ts +34 -13
  443. package/src/{select → form/fields/select}/select.ts +77 -108
  444. package/src/{switch → form/fields/switch}/switch.test.ts +1 -1
  445. package/src/{switch → form/fields/switch}/switch.ts +71 -51
  446. package/src/form/fields/textarea/textarea.test.ts +54 -0
  447. package/src/{textarea → form/fields/textarea}/textarea.ts +33 -72
  448. package/src/form/form-state.ts +31 -0
  449. package/src/form/form-summary.test.ts +105 -0
  450. package/src/form/form-summary.ts +171 -0
  451. package/src/form/form.test.ts +218 -35
  452. package/src/form/form.ts +330 -99
  453. package/src/form/index.ts +3 -0
  454. package/src/index.ts +9 -9
  455. package/types/mixins/formField.mixin.d.ts +90 -0
  456. package/types/src/button/button.d.ts +9 -0
  457. package/types/src/button/button.test.d.ts +3 -0
  458. package/types/src/{autocomplete → form/fields/autocomplete}/autocomplete.d.ts +6 -15
  459. package/types/src/form/fields/checkbox/checkbox.d.ts +47 -0
  460. package/types/src/{date-range → form/fields/date-range}/date-range.d.ts +22 -4
  461. package/types/src/form/fields/date-range/date-range.test.d.ts +1 -0
  462. package/types/src/form/fields/index.d.ts +9 -0
  463. package/types/src/{input → form/fields/input}/input.d.ts +20 -45
  464. package/types/src/form/fields/input/input.test.d.ts +1 -0
  465. package/types/src/{radio-group → form/fields/radio-group}/radio-button.d.ts +1 -1
  466. package/types/src/{radio-group → form/fields/radio-group}/radio-group.d.ts +1 -1
  467. package/types/src/form/fields/range/range.d.ts +28 -0
  468. package/types/src/form/fields/range/range.test.d.ts +1 -0
  469. package/types/src/{select → form/fields/select}/select.d.ts +23 -24
  470. package/types/src/form/fields/switch/switch.d.ts +57 -0
  471. package/types/src/{textarea → form/fields/textarea}/textarea.d.ts +6 -39
  472. package/types/src/form/fields/textarea/textarea.test.d.ts +1 -0
  473. package/types/src/form/form-state.d.ts +22 -0
  474. package/types/src/form/form-summary.d.ts +42 -0
  475. package/types/src/form/form-summary.test.d.ts +4 -0
  476. package/types/src/form/form.d.ts +79 -34
  477. package/types/src/form/form.test.d.ts +2 -2
  478. package/types/src/form/index.d.ts +3 -0
  479. package/types/src/index.d.ts +9 -9
  480. package/dist/active-host-CcIa2tmW.cjs +0 -1
  481. package/dist/active-host-CvNYoprt.js +0 -57
  482. package/dist/autocomplete-DWSuwSRS.js.map +0 -1
  483. package/dist/autocomplete-iCJOia-q.cjs +0 -115
  484. package/dist/autocomplete-iCJOia-q.cjs.map +0 -1
  485. package/dist/checkbox-NNReP9s_.cjs.map +0 -1
  486. package/dist/date-range-CaOxwZDq.cjs +0 -131
  487. package/dist/date-range-CaOxwZDq.cjs.map +0 -1
  488. package/dist/date-range-CgNujP8r.js.map +0 -1
  489. package/dist/date-range-inline-D4IjOOO0.cjs +0 -43
  490. package/dist/decorate-23nYs4Le.js +0 -7
  491. package/dist/decorate-DpFmy0nm.cjs +0 -1
  492. package/dist/float-CKmd-0-t.cjs +0 -1
  493. package/dist/form-CFvwnfuJ.js +0 -68
  494. package/dist/form-CFvwnfuJ.js.map +0 -1
  495. package/dist/form-Ceijw1aA.cjs +0 -1
  496. package/dist/form-Ceijw1aA.cjs.map +0 -1
  497. package/dist/input-D95GjINh.js.map +0 -1
  498. package/dist/input-D9s4jDAb.cjs +0 -51
  499. package/dist/input-D9s4jDAb.cjs.map +0 -1
  500. package/dist/mixins-BV0w2yIE.js +0 -627
  501. package/dist/mixins-BV0w2yIE.js.map +0 -1
  502. package/dist/mixins-DvAYa-F7.cjs +0 -298
  503. package/dist/mixins-DvAYa-F7.cjs.map +0 -1
  504. package/dist/notification-BC9nG8Sr.cjs +0 -23
  505. package/dist/radio-group-ByMD6Lsj.cjs +0 -40
  506. package/dist/radio-group-ByMD6Lsj.cjs.map +0 -1
  507. package/dist/radio-group-CW8airhZ.js.map +0 -1
  508. package/dist/select-BdBThja4.cjs +0 -56
  509. package/dist/select-BdBThja4.cjs.map +0 -1
  510. package/dist/select-Dbn-CImU.js.map +0 -1
  511. package/dist/state-DNdCPITt.cjs +0 -1
  512. package/dist/surface-BpppoNXN.cjs +0 -7
  513. package/dist/textarea-B9dy-yec.js +0 -211
  514. package/dist/textarea-B9dy-yec.js.map +0 -1
  515. package/dist/textarea-DFY0Flgv.cjs +0 -39
  516. package/dist/textarea-DFY0Flgv.cjs.map +0 -1
  517. package/dist/theme-CpuF3D3q.cjs +0 -181
  518. package/dist/theme-button-B6Xf-EiH.cjs +0 -8
  519. package/src/checkbox/checkbox.ts +0 -162
  520. package/types/src/checkbox/checkbox.d.ts +0 -71
  521. package/types/src/range/range.d.ts +0 -25
  522. package/types/src/switch/switch.d.ts +0 -53
  523. /package/dist/{animation-CO_Csq84.cjs → animation-CCOIW4wJ.cjs} +0 -0
  524. /package/dist/{animation-BK-8BwY8.js → animation-DCznELuT.js} +0 -0
  525. /package/dist/{context-DJTJnSK4.js → context-6oXCZmZN.js} +0 -0
  526. /package/dist/{context-BpCETidA.cjs → context-CRZeiCqq.cjs} +0 -0
  527. /package/dist/{hashContent-Bobsobip.cjs → hashContent-Ck6laKlk.cjs} +0 -0
  528. /package/dist/{hashContent-BU6jl5ih.js → hashContent-dJrI-9sc.js} +0 -0
  529. /package/dist/{lazy-Dq9mRRjT.cjs → lazy-CayEFyC3.cjs} +0 -0
  530. /package/dist/{lazy-B0ia54tT.js → lazy-D-bO2r4m.js} +0 -0
  531. /package/dist/{overlay-stack-DCDS17uj.js → overlay-stack-BR4iYivO.js} +0 -0
  532. /package/dist/{overlay-stack-DPIe_aYv.cjs → overlay-stack-Dk0xETTy.cjs} +0 -0
  533. /package/dist/{reduced-motion-D-L12p7G.js → reduced-motion-D7LqTUMn.js} +0 -0
  534. /package/dist/{reduced-motion-Ds-HjMzn.cjs → reduced-motion-Dzfp_w5x.cjs} +0 -0
  535. /package/dist/{rxjs-utils-DCUHg_Ml.cjs → rxjs-utils-BKB2UM_j.cjs} +0 -0
  536. /package/dist/{rxjs-utils-CVeJQ9KG.js → rxjs-utils-Dv9T9IpA.js} +0 -0
  537. /package/dist/{search-BLCRsxIC.cjs → search-DPKoC-dT.cjs} +0 -0
  538. /package/dist/{search-BTz7-Rev.js → search-MvIBA93K.js} +0 -0
  539. /package/dist/{theme.interface-B9TjbSBF.js → theme.interface-C2XNgsLB.js} +0 -0
  540. /package/dist/{theme.interface-BujperTo.cjs → theme.interface-D4NeufQA.cjs} +0 -0
  541. /package/src/{autocomplete → form/fields/autocomplete}/autocomplete.scss +0 -0
  542. /package/src/{autocomplete → form/fields/autocomplete}/index.ts +0 -0
  543. /package/src/{checkbox → form/fields/checkbox}/index.ts +0 -0
  544. /package/src/{date-range → form/fields/date-range}/date-range-dialog.ts +0 -0
  545. /package/src/{date-range → form/fields/date-range}/date-range-helpers.ts +0 -0
  546. /package/src/{date-range → form/fields/date-range}/date-range-presets.ts +0 -0
  547. /package/src/{date-range → form/fields/date-range}/date-utils.ts +0 -0
  548. /package/src/{date-range → form/fields/date-range}/index.ts +0 -0
  549. /package/src/{input → form/fields/input}/index.ts +0 -0
  550. /package/src/{input → form/fields/input}/input.scss +0 -0
  551. /package/src/{radio-group → form/fields/radio-group}/index.ts +0 -0
  552. /package/src/{radio-group → form/fields/radio-group}/radio-group.scss +0 -0
  553. /package/src/{range → form/fields/range}/index.ts +0 -0
  554. /package/src/{select → form/fields/select}/index.ts +0 -0
  555. /package/src/{switch → form/fields/switch}/index.ts +0 -0
  556. /package/src/{textarea → form/fields/textarea}/index.ts +0 -0
  557. /package/src/{textarea → form/fields/textarea}/textarea.scss +0 -0
  558. /package/types/src/{autocomplete → form/fields/autocomplete}/index.d.ts +0 -0
  559. /package/types/src/{checkbox → form/fields/checkbox}/checkbox.test.d.ts +0 -0
  560. /package/types/src/{checkbox → form/fields/checkbox}/index.d.ts +0 -0
  561. /package/types/src/{date-range → form/fields/date-range}/date-range-dialog.d.ts +0 -0
  562. /package/types/src/{date-range → form/fields/date-range}/date-range-helpers.d.ts +0 -0
  563. /package/types/src/{date-range → form/fields/date-range}/date-range-presets.d.ts +0 -0
  564. /package/types/src/{date-range → form/fields/date-range}/date-utils.d.ts +0 -0
  565. /package/types/src/{date-range → form/fields/date-range}/index.d.ts +0 -0
  566. /package/types/src/{input → form/fields/input}/index.d.ts +0 -0
  567. /package/types/src/{radio-group → form/fields/radio-group}/index.d.ts +0 -0
  568. /package/types/src/{range → form/fields/range}/index.d.ts +0 -0
  569. /package/types/src/{select → form/fields/select}/index.d.ts +0 -0
  570. /package/types/src/{switch → form/fields/switch}/index.d.ts +0 -0
  571. /package/types/src/{switch → form/fields/switch}/switch.test.d.ts +0 -0
  572. /package/types/src/{textarea → form/fields/textarea}/index.d.ts +0 -0
@@ -1,49 +1,145 @@
1
1
  # schmancy-form
2
2
 
3
- > Form container that collects data from child controls, validates, and emits submit/reset events.
3
+ > Form container with isolated submit state, typed schema seam, and a unified validation UX contract every field implements.
4
4
 
5
5
  ## Usage
6
+
6
7
  ```html
7
- <schmancy-form @submit=${(e) => handleSubmit(e.detail)}>
8
+ <schmancy-form @submit=${(e) => handleSubmit(e.detail.data)}>
8
9
  <schmancy-input name="email" label="Email" required></schmancy-input>
9
10
  <schmancy-button type="submit">Submit</schmancy-button>
10
11
  </schmancy-form>
11
12
  ```
12
13
 
14
+ The submit detail is `{ data, formData, until }`:
15
+
16
+ ```ts
17
+ type SchmancyFormSubmitDetail<T = Record<string, FormDataEntryValue>> = {
18
+ data: T // typed when `schema` is set
19
+ formData: FormData // raw payload
20
+ until(p: Promise<unknown>): void // gate success/error on async outcome
21
+ }
22
+ ```
23
+
13
24
  ## Properties
25
+
14
26
  | Property | Type | Default | Description |
15
- |----------|------|---------|-------------|
16
- | novalidate | boolean | `false` | Skip validation on submit |
27
+ |---|---|---|---|
28
+ | `schema` | `ParseSchema` (zod / valibot / ArkType compatible) | | When set, parses raw FormData on submit; `e.detail.data` is typed `z.infer<TSchema>`. |
29
+ | `novalidate` | `boolean` | `true` | Skip native browser validation popups (we control display). |
17
30
 
18
31
  ## Events
32
+
19
33
  | Event | Detail | Description |
20
- |-------|--------|-------------|
21
- | submit | FormData | Form data from all child controls |
22
- | reset | - | When the form is reset |
34
+ |---|---|---|
35
+ | `submit` | `SchmancyFormSubmitDetail` | Fired after all registered fields pass validation. |
36
+ | `reset` | `CustomEvent` | Fired after the form resets. |
23
37
 
24
38
  ## Methods
39
+
25
40
  | Method | Returns | Description |
26
- |--------|---------|-------------|
27
- | submit() | boolean | Validates and dispatches submit event. Returns false if invalid. |
28
- | reset() | void | Resets all child controls to default values |
29
- | getFormData() | FormData | Collects current form data without submitting |
30
- | reportValidity() | boolean | Checks and shows validation on all controls |
41
+ |---|---|---|
42
+ | `submit()` | `boolean` | Programmatic submission via the inner form's `requestSubmit()`. |
43
+ | `reset()` | `void` | Resets every registered field. |
44
+ | `setFieldError(name, message)` | `boolean` | RHF `setError(name, ...)`-equivalent: maps a server-side error to a specific field. |
45
+ | `setFormError(message, code?)` | `void` | RHF `setError('root.serverError', ...)`-equivalent: structured form-level error. |
46
+ | `getFormData()` | `FormData` | Snapshot of the registered fields' contributed entries. |
47
+ | `reportValidity()` | `boolean` | Checks every registered field. |
48
+ | `checkValidity()` | `boolean` | Same as `reportValidity` without the side effect. |
49
+
50
+ ## Validation UX (binding contract)
51
+
52
+ Every field that extends `SchmancyFormField()` implements four phases:
53
+
54
+ | Phase | Trigger | Behaviour |
55
+ |---|---|---|
56
+ | 1 — Pristine | User hasn't changed the field | **No error shown**, ever. `dirty = false` is the gate. |
57
+ | 2 — Dirty | User typed something then blurred | Validate. **Show error only if invalid.** |
58
+ | 3 — Live correction | User returns to a field with an error | Re-validate on every keystroke. Error clears immediately when valid. |
59
+ | 4 — Submit | User clicks submit | Force-validate **all** fields regardless of `dirty`. Focus the first invalid field. |
60
+
61
+ The default mode is `validateOn="dirty"`. Override per-field for special cases:
62
+
63
+ ```html
64
+ <schmancy-input validateOn="always" ...></schmancy-input> <!-- live search -->
65
+ <schmancy-input validateOn="submitted" ...></schmancy-input> <!-- wizard step -->
66
+ ```
67
+
68
+ After a submit attempt, the field stays in live-correction mode (Phase 3) for the rest of the session — `resetForm()` is the only way back.
69
+
70
+ ## Server-side errors
71
+
72
+ ```ts
73
+ async _onSubmit(e: CustomEvent<SchmancyFormSubmitDetail>) {
74
+ const form = e.target as SchmancyForm
75
+ e.detail.until(
76
+ chargeCard(e.detail.data).catch(err => {
77
+ if (err.code === 'CARD_DECLINED') {
78
+ form.setFieldError('card', 'Card declined — check the number')
79
+ } else {
80
+ form.setFormError(err.message)
81
+ }
82
+ throw err // re-throw so submit-state flips to 'error'
83
+ }),
84
+ )
85
+ }
86
+ ```
87
+
88
+ ## CSS state hooks (free)
89
+
90
+ Every field broadcasts these via `:state(...)`:
91
+
92
+ ```css
93
+ schmancy-input:state(invalid) { --border-color: var(--color-error); }
94
+ schmancy-input:state(dirty) { --border-color: var(--color-primary); }
95
+ schmancy-input:state(touched) { /* user blurred at least once */ }
96
+ schmancy-input:state(submitted) { /* post-submit state */ }
97
+ schmancy-input:state(required) { /* required visual */ }
98
+
99
+ schmancy-button[type=submit]:state(submitting) { opacity: 0.6; } /* form busy */
100
+ ```
101
+
102
+ The `<schmancy-form>` host gets `aria-busy="true"` while submitting (WCAG 2.2 AA — disabled submit buttons drop from tab order; we keep them focusable and signal busy via aria).
103
+
104
+ ## Field-author contract
105
+
106
+ Components that extend `SchmancyFormField()` get FACE wiring, ARIA reflection (`internals.ariaInvalid` / `ariaRequired`), the validation UX state (`touched/dirty/submitted/validateOn`), the `_shouldShowError()` gate, the form-registry composed event (`FIELD_CONNECT_EVENT`), and reset/disabled propagation — all for free.
107
+
108
+ The component author must wire only two things:
109
+
110
+ ```ts
111
+ // 1. Call markTouched() on blur — tells the mixin the user has left the field
112
+ this.input.addEventListener('blur', () => this.markTouched())
113
+
114
+ // 2. Call emitChange() when value changes
115
+ this.value = newValue
116
+ this.emitChange({ value: newValue })
117
+ ```
118
+
119
+ Override only when validity semantics differ (checkbox uses `checked`, switch uses `checked`, date-range uses `dateFrom`/`dateTo`) or when FormData contribution is multi-entry (date-range emits `${name}From` and `${name}To`).
120
+
121
+ ## Submit triggers
122
+
123
+ `<schmancy-form>` listens on its host for `click` on `<button type=submit>` / `<schmancy-button type=submit>` and `keydown.Enter` on registered fields, then calls the inner shadow-DOM form's `requestSubmit()`. This bridges the gap that native form-association cannot cross from light-DOM slotted children to a shadow-DOM `<form>`.
31
124
 
32
125
  ## Examples
126
+
33
127
  ```html
34
- <!-- Form with validation -->
35
- <schmancy-form @submit=${(e) => save(e.detail)} @reset=${() => clearForm()}>
36
- <schmancy-input name="name" label="Name" required></schmancy-input>
37
- <schmancy-select name="role" label="Role" required>
38
- <schmancy-option value="admin" label="Admin"></schmancy-option>
39
- <schmancy-option value="user" label="User"></schmancy-option>
40
- </schmancy-select>
41
- <schmancy-checkbox name="active" label="Active"></schmancy-checkbox>
42
- <div class="flex gap-2">
43
- <schmancy-button type="submit">Save</schmancy-button>
44
- <schmancy-button type="reset">Reset</schmancy-button>
45
- </div>
128
+ <!-- Two independent checkout forms — each <schmancy-form> instance has its own
129
+ isolated submit state via <schmancy-context>; no cross-contamination. -->
130
+ <schmancy-form @submit=${(e) => pay('primary', e)}>
131
+ <schmancy-input name="card" required></schmancy-input>
132
+ <schmancy-button type="submit">Pay £50</schmancy-button>
133
+ </schmancy-form>
134
+
135
+ <schmancy-form @submit=${(e) => pay('backup', e)}>
136
+ <schmancy-input name="card" required></schmancy-input>
137
+ <schmancy-button type="submit">Pay £50</schmancy-button>
46
138
  </schmancy-form>
47
139
  ```
48
140
 
49
- Submit triggers on Enter key in inputs or clicking a submit-type button.
141
+ ## See also
142
+
143
+ - `form-ux-rules.md` — the Revolute UX contract → mixin API mapping.
144
+ - `mixins.md` — `SchmancyFormField()` factory composition.
145
+ - `state.md` — `formSubmitState` + `<schmancy-context>` isolation pattern.
@@ -22,7 +22,10 @@
22
22
  | validationMessage | string | `''` | Custom validation message |
23
23
  | hint | string | `undefined` | Hint text below the field |
24
24
  | size | `'xxs'\|'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Input height (24-56px) |
25
- | validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'touched'` | When to show validation |
25
+ | validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When to display validation errors. Default suppresses errors on pristine fields until submit. |
26
+ | touched | boolean (read-only) | `false` | True after first blur — set by `markTouched()`. |
27
+ | dirty | boolean (getter) | — | True when `value` differs from the captured default. |
28
+ | submitted | boolean (read-only) | `false` | Set by `<schmancy-form>` on submit; flips field to live-correction mode. |
26
29
  | align | `'left'\|'center'\|'right'` | `'left'` | Text alignment |
27
30
  | pattern | string | `undefined` | Regex validation pattern |
28
31
  | inputmode | string | `undefined` | Virtual keyboard hint |
@@ -34,9 +37,21 @@
34
37
  ## Events
35
38
  | Event | Detail | Description |
36
39
  |-------|--------|-------------|
37
- | input | `{ value: string }` | Every keystroke |
38
- | change | `{ value: string }` | On blur/native change |
39
- | enter | `{ value: string }` | When Enter key is pressed |
40
+ | input | `{ value: string }` | Every keystroke (bubbles, composed) |
41
+ | change | `{ value: string }` | On blur/native change (bubbles, composed) |
42
+ | enter | `{ value: string }` | Enter key pressed |
43
+ | focus / blur | — | Standard focus events |
44
+
45
+ ## Public API (from `SchmancyFormField`)
46
+ - `markTouched()` / `markSubmitted()` — flip the `_shouldShowError()` gate.
47
+ - `checkValidity()` / `reportValidity()` — return current validity (used by `<schmancy-form>` and native `<form>`).
48
+ - `setCustomValidity(message)` — server-side error path. `<schmancy-form>` calls this from `setFieldError(name, msg)`.
49
+ - `resetForm()` — restores the captured default; clears `error`, `touched`, `submitted`.
50
+ - `internals.ariaInvalid` / `ariaRequired` — set automatically; reaches AT through shadow DOM.
51
+
52
+ `<schmancy-form>` auto-discovers this field via `FIELD_CONNECT_EVENT` (composed event). No registration needed.
53
+
54
+ See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
40
55
 
41
56
  ## Examples
42
57
  ```html
@@ -20,9 +20,15 @@
20
20
  | `min` | number | `0` | Minimum value |
21
21
  | `max` | number | `1` | Maximum value |
22
22
  | `step` | number | `0.01` | Increment per tick |
23
- | `value` | number | `0` | Current value |
23
+ | `value` | number | `0` | Current value (narrowed override of the mixin's wide union). |
24
24
  | `label` | string | — | Optional label (current value displays on the right) |
25
25
  | `disabled` | boolean | `false` | Disabled state (38% opacity) |
26
+ | `name` | string | `''` | Form submission name. From `SchmancyFormField`. |
27
+ | `required` | boolean | `false` | Field must have a value to validate. |
28
+ | `validateOn` | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When errors display. |
29
+ | `validationMessage` | string | `''` | Error message. |
30
+ | `hint` | string | `undefined` | Helper text. |
31
+ | `touched / dirty / submitted` | boolean | — | Validation state from `SchmancyFormField`. |
26
32
 
27
33
  ## Events
28
34
  | Event | Payload | When |
@@ -34,6 +40,14 @@
34
40
  - Circular thumb with hover halo (8px primary glow at 12% opacity).
35
41
  - Disabled state: 38% opacity, not-allowed cursor.
36
42
 
43
+ ## Form-field contract
44
+
45
+ Extends `SchmancyFormField()`. FormData contributes `String(value)` under `name`. `markTouched()` fires on every input event (slider drag), so the field transitions to `touched` immediately on interaction — the `dirty` gate opens once value diverges from the captured default.
46
+
47
+ Auto-discovered by `<schmancy-form>` via `FIELD_CONNECT_EVENT`. Public API: `markTouched()`, `markSubmitted()`, `checkValidity()`, `setCustomValidity()`, `resetForm()`.
48
+
49
+ See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
50
+
37
51
  ## Example — precise float control
38
52
  ```html
39
53
  <schmancy-range
@@ -23,7 +23,11 @@
23
23
  | multi | boolean | `false` | Enable multi-select mode |
24
24
  | hint | string | `''` | Hint text below the select |
25
25
  | size | `'xxs'\|'xs'\|'sm'\|'md'\|'lg'` | `'md'` | Input height |
26
- | validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'touched'` | When to show validation |
26
+ | validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When validation errors display. From `SchmancyFormField`. |
27
+ | validationMessage | string | `''` | Error message — set by `setCustomValidity()` or `<schmancy-form>.setFieldError()`. |
28
+ | error | boolean (read-only) | — | True when invalid AND `_shouldShowError()` gate is open. |
29
+ | touched / dirty / submitted | boolean | — | Validation state from `SchmancyFormField`. |
30
+ | readonly | boolean | `false` | Read-only mode. |
27
31
 
28
32
  ## Events
29
33
  | Event | Detail | Description |
@@ -47,3 +51,11 @@
47
51
  ```
48
52
 
49
53
  Children must be `<schmancy-option>` elements with `value` and `label` attributes.
54
+
55
+ ## Form-field contract
56
+
57
+ Extends `SchmancyFormField()` — auto-discovered by `<schmancy-form>` via `FIELD_CONNECT_EVENT`. Exposes `markTouched()`, `markSubmitted()`, `checkValidity()`, `reportValidity()`, `setCustomValidity()`, `resetForm()`. Multi-select serializes to a comma-joined string for native FormData; `toFormEntries()` emits one `[name, value]` per selection for `<schmancy-form>` consumers.
58
+
59
+ ARIA combobox attributes (`role="combobox"`, `aria-expanded`, `aria-controls`) plus `aria-invalid` / `aria-required` reflect through `ElementInternals` — target via `:state(invalid)` / `:state(required)` in CSS, not host `[aria-*]` selectors.
60
+
61
+ See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
@@ -17,6 +17,11 @@
17
17
  | label | string | `''` | ARIA label on the inner button; also used by axe. |
18
18
  | required | boolean | `false` | Must be on for form validity. |
19
19
  | disabled | boolean | `false` | Disables interaction. |
20
+ | validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When validation errors display. From `SchmancyFormField`. |
21
+ | validationMessage | string | `''` | Error text — default `'This switch is required.'` when required and off. |
22
+ | error | boolean | `false` | Error state (gated by `validateOn`). |
23
+ | hint | string | `undefined` | Helper text. |
24
+ | touched / dirty / submitted | boolean | — | Validation state from `SchmancyFormField`. |
20
25
 
21
26
  ## Events
22
27
  | Event | Detail | Description |
@@ -32,10 +37,24 @@
32
37
  ## States
33
38
  | State | When |
34
39
  |-------|------|
35
- | `:state(checked)` | While the switch is on. Target via `schmancy-switch:state(checked) { … }`. |
40
+ | `:state(checked)` | switch is on |
41
+ | `:state(touched)` | user has blurred the host at least once |
42
+ | `:state(dirty)` | `checked` differs from initial |
43
+ | `:state(submitted)` | parent `<schmancy-form>` has submitted |
44
+ | `:state(invalid)` | error flag is set (gated by `validateOn`) |
45
+ | `:state(required)` | required and not disabled |
46
+ | `:state(disabled)` | disabled |
36
47
 
37
48
  ## Form association
38
- Uses `ElementInternals` — participates in `<form>` submission natively. Contributes `name=value` when checked; omitted when unchecked. `formResetCallback` restores the initial `checked` attribute. `formDisabledCallback` propagates `<fieldset disabled>`.
49
+ Extends `SchmancyFormField()` — participates in `<form>` submission natively. FormData contributes `name=value` when checked; omitted when unchecked.
50
+
51
+ `dirty` is overridden to mean "`checked` diverged from the snapshot taken at first render," not the mixin's value-vs-default. Under default `validateOn: 'dirty'`, an empty-required switch only shows an error after the user toggles it (or submit forces validation), but `internals.checkValidity()` already reports `false` so `<form>.checkValidity()` is correct.
52
+
53
+ `resetForm()` restores the snapshot taken in `firstUpdated` (the pre-render `checked` value). `formDisabledCallback` propagates `<fieldset disabled>`. ARIA `aria-invalid` / `aria-required` reflect through `ElementInternals`.
54
+
55
+ Public API: `markTouched()`, `markSubmitted()`, `checkValidity()`, `setCustomValidity()`, `resetForm()`. Auto-discovered by `<schmancy-form>` via `FIELD_CONNECT_EVENT`.
56
+
57
+ See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
39
58
 
40
59
  ## Examples
41
60
  ```html
@@ -28,6 +28,11 @@
28
28
  | resize | `'none'\|'vertical'\|'horizontal'\|'both'` | `'vertical'` | Resize handle |
29
29
  | align | `'left'\|'center'\|'right'` | `'left'` | Text alignment |
30
30
  | wrap | `'hard'\|'soft'` | `'soft'` | Text wrapping mode |
31
+ | validateOn | `'always'\|'touched'\|'dirty'\|'submitted'` | `'dirty'` | When validation errors display. From `SchmancyFormField`. |
32
+ | validationMessage | string | `''` | Custom error message. Set via `setCustomValidity()` or by `<schmancy-form>.setFieldError()`. |
33
+ | spellcheck | boolean | `false` | Native spellcheck attribute. |
34
+ | dirname | string | `undefined` | Native dirname for RTL form submission. |
35
+ | touched / dirty / submitted | boolean | — | Validation state from `SchmancyFormField`. |
31
36
 
32
37
  ## Events
33
38
  | Event | Detail | Description |
@@ -46,3 +51,11 @@
46
51
  <!-- Fill container -->
47
52
  <schmancy-textarea fillHeight label="Content"></schmancy-textarea>
48
53
  ```
54
+
55
+ ## Form-field contract
56
+
57
+ Extends `SchmancyFormField()` — `markTouched()`, `markSubmitted()`, `checkValidity()`, `reportValidity()`, `setCustomValidity()`, `resetForm()` all available; `internals.ariaInvalid` / `ariaRequired` set automatically; `<schmancy-form>` auto-discovers via `FIELD_CONNECT_EVENT`.
58
+
59
+ Validation message renders in the same supporting slot as `hint`, with `role="alert"` set when `error` is true so AT announces the change.
60
+
61
+ See `form.md` and `form-ux-rules.md` for the binding 4-phase validation contract.
@@ -0,0 +1,122 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
2
+ import './button'
3
+ import '../form/form'
4
+ import '../form/fields/input/input'
5
+ import { expectNoA11yViolations } from '../test-utils/a11y'
6
+ import type { SchmancyFormSubmitDetail } from '../form/form'
7
+
8
+ const nextUpdate = () => new Promise(r => requestAnimationFrame(() => r(null)))
9
+
10
+ describe('schmancy-button busy mirror', () => {
11
+ let host: HTMLDivElement
12
+
13
+ beforeEach(() => {
14
+ host = document.createElement('div')
15
+ document.body.appendChild(host)
16
+ })
17
+
18
+ afterEach(() => {
19
+ host.remove()
20
+ })
21
+
22
+ it('mirrors closest <schmancy-form> aria-busy onto a submit button', async () => {
23
+ host.innerHTML = `
24
+ <schmancy-form>
25
+ <schmancy-input name="x" value="ok"></schmancy-input>
26
+ <schmancy-button type="submit">Send</schmancy-button>
27
+ </schmancy-form>
28
+ `
29
+ const form = host.querySelector('schmancy-form') as HTMLElement
30
+ const btn = host.querySelector('schmancy-button[type=submit]') as HTMLElement
31
+ await nextUpdate()
32
+ await nextUpdate()
33
+
34
+ expect(btn.hasAttribute('aria-busy')).toBe(false)
35
+
36
+ form.setAttribute('aria-busy', 'true')
37
+ await nextUpdate()
38
+ await nextUpdate()
39
+ expect(btn.getAttribute('aria-busy')).toBe('true')
40
+ expect(btn.matches(':state(submitting)')).toBe(true)
41
+
42
+ form.removeAttribute('aria-busy')
43
+ await nextUpdate()
44
+ await nextUpdate()
45
+ expect(btn.hasAttribute('aria-busy')).toBe(false)
46
+ expect(btn.matches(':state(submitting)')).toBe(false)
47
+ })
48
+
49
+ it('does not mirror busy on non-submit buttons', async () => {
50
+ host.innerHTML = `
51
+ <schmancy-form>
52
+ <schmancy-button type="button">Cancel</schmancy-button>
53
+ </schmancy-form>
54
+ `
55
+ const form = host.querySelector('schmancy-form') as HTMLElement
56
+ const btn = host.querySelector('schmancy-button') as HTMLElement
57
+ await nextUpdate()
58
+ await nextUpdate()
59
+
60
+ form.setAttribute('aria-busy', 'true')
61
+ await nextUpdate()
62
+ await nextUpdate()
63
+ expect(btn.hasAttribute('aria-busy')).toBe(false)
64
+ expect(btn.matches(':state(submitting)')).toBe(false)
65
+ })
66
+
67
+ it('has no axe-core a11y violations in busy state', async () => {
68
+ host.innerHTML = `
69
+ <schmancy-form>
70
+ <schmancy-input name="x" value="ok"></schmancy-input>
71
+ <schmancy-button type="submit">Send</schmancy-button>
72
+ </schmancy-form>
73
+ `
74
+ const form = host.querySelector('schmancy-form') as HTMLElement
75
+ await nextUpdate()
76
+ await nextUpdate()
77
+ // Idle baseline.
78
+ await expectNoA11yViolations(host)
79
+ // Busy state — button gets aria-busy, must remain focusable + AT-clean.
80
+ form.setAttribute('aria-busy', 'true')
81
+ await nextUpdate()
82
+ await nextUpdate()
83
+ await expectNoA11yViolations(host)
84
+ })
85
+
86
+ it('drives busy through the awaitable submit lifecycle', async () => {
87
+ host.innerHTML = `
88
+ <schmancy-form>
89
+ <schmancy-input name="x" value="ok"></schmancy-input>
90
+ <schmancy-button type="submit">Send</schmancy-button>
91
+ </schmancy-form>
92
+ `
93
+ const form = host.querySelector('schmancy-form') as HTMLElement
94
+ const btn = host.querySelector('schmancy-button[type=submit]') as HTMLElement
95
+ await nextUpdate()
96
+ await nextUpdate()
97
+
98
+ // Resolve the until-promise after a tick so we can observe the busy window.
99
+ let resolveSubmit: (() => void) | null = null
100
+ form.addEventListener('submit', (e: Event) => {
101
+ const detail = (e as CustomEvent<SchmancyFormSubmitDetail>).detail
102
+ detail.until(new Promise<void>(res => { resolveSubmit = res }))
103
+ })
104
+
105
+ btn.click()
106
+ // Wait for the submit microtask + form state flip + MutationObserver tick.
107
+ await nextUpdate()
108
+ await nextUpdate()
109
+ await nextUpdate()
110
+
111
+ expect(btn.getAttribute('aria-busy')).toBe('true')
112
+ expect(btn.matches(':state(submitting)')).toBe(true)
113
+
114
+ resolveSubmit!()
115
+ await nextUpdate()
116
+ await nextUpdate()
117
+ await nextUpdate()
118
+
119
+ expect(btn.hasAttribute('aria-busy')).toBe(false)
120
+ expect(btn.matches(':state(submitting)')).toBe(false)
121
+ })
122
+ })
@@ -62,6 +62,13 @@ export class SchmancyButton extends SchmancyElement {
62
62
 
63
63
  static formAssociated = true
64
64
  private internals: ElementInternals | undefined
65
+ /**
66
+ * When this button is `type="submit"` and lives inside a <schmancy-form>,
67
+ * the observer mirrors the form's `aria-busy` attribute onto this button
68
+ * while a submit is in flight. Stays focusable; disabled buttons drop from
69
+ * the tab order and are unreachable to AT (WCAG 2.2 AA).
70
+ */
71
+ private _formBusyObserver?: MutationObserver
65
72
 
66
73
  constructor() {
67
74
  super()
@@ -99,6 +106,35 @@ export class SchmancyButton extends SchmancyElement {
99
106
  this.disabled = disabled
100
107
  }
101
108
 
109
+ override connectedCallback(): void {
110
+ super.connectedCallback()
111
+ // Mirror the closest <schmancy-form>'s aria-busy onto this submit button
112
+ // so the user gets a visible busy state during async submit handlers.
113
+ // Schmancy-form sets aria-busy="true" while status === 'submitting'.
114
+ if (this.type !== 'submit') return
115
+ const form = this.closest('schmancy-form') as HTMLElement | null
116
+ if (!form) return
117
+ const sync = () => {
118
+ const busy = form.getAttribute('aria-busy') === 'true'
119
+ if (busy) {
120
+ this.setAttribute('aria-busy', 'true')
121
+ this.internals?.states.add('submitting')
122
+ } else {
123
+ this.removeAttribute('aria-busy')
124
+ this.internals?.states.delete('submitting')
125
+ }
126
+ }
127
+ sync()
128
+ this._formBusyObserver = new MutationObserver(sync)
129
+ this._formBusyObserver.observe(form, { attributes: true, attributeFilter: ['aria-busy'] })
130
+ }
131
+
132
+ override disconnectedCallback(): void {
133
+ this._formBusyObserver?.disconnect()
134
+ this._formBusyObserver = undefined
135
+ super.disconnectedCallback()
136
+ }
137
+
102
138
  @query('[part="base"]', true)
103
139
  private nativeElement!: HTMLElement
104
140