@expressivecss/expressive 0.14.1 → 0.16.0

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 (603) hide show
  1. package/CHANGELOG.md +1589 -1
  2. package/README.md +9 -8
  3. package/dist/css/expressive.css +19304 -12021
  4. package/dist/css/expressive.css.map +1 -1
  5. package/dist/css/expressive.min.css +1 -1
  6. package/dist/css/expressive.min.css.map +1 -1
  7. package/dist/fonts/LICENSE-noto-sans-arabic +93 -0
  8. package/dist/fonts/LICENSE-noto-sans-hebrew +93 -0
  9. package/dist/fonts/LICENSE-noto-sans-thai +93 -0
  10. package/dist/fonts/material-symbols-outlined.woff2 +0 -0
  11. package/dist/fonts/material-symbols-rounded.woff2 +0 -0
  12. package/dist/fonts/material-symbols-sharp.woff2 +0 -0
  13. package/dist/fonts/noto-sans-arabic-arabic-400.woff2 +0 -0
  14. package/dist/fonts/noto-sans-arabic-arabic-500.woff2 +0 -0
  15. package/dist/fonts/noto-sans-arabic-arabic-700.woff2 +0 -0
  16. package/dist/fonts/noto-sans-cyrillic-400.woff2 +0 -0
  17. package/dist/fonts/noto-sans-cyrillic-500.woff2 +0 -0
  18. package/dist/fonts/noto-sans-cyrillic-700.woff2 +0 -0
  19. package/dist/fonts/noto-sans-cyrillic-ext-400.woff2 +0 -0
  20. package/dist/fonts/noto-sans-cyrillic-ext-500.woff2 +0 -0
  21. package/dist/fonts/noto-sans-cyrillic-ext-700.woff2 +0 -0
  22. package/dist/fonts/noto-sans-devanagari-400.woff2 +0 -0
  23. package/dist/fonts/noto-sans-devanagari-500.woff2 +0 -0
  24. package/dist/fonts/noto-sans-devanagari-700.woff2 +0 -0
  25. package/dist/fonts/noto-sans-greek-400.woff2 +0 -0
  26. package/dist/fonts/noto-sans-greek-500.woff2 +0 -0
  27. package/dist/fonts/noto-sans-greek-700.woff2 +0 -0
  28. package/dist/fonts/noto-sans-greek-ext-400.woff2 +0 -0
  29. package/dist/fonts/noto-sans-greek-ext-500.woff2 +0 -0
  30. package/dist/fonts/noto-sans-greek-ext-700.woff2 +0 -0
  31. package/dist/fonts/noto-sans-hebrew-hebrew-400.woff2 +0 -0
  32. package/dist/fonts/noto-sans-hebrew-hebrew-500.woff2 +0 -0
  33. package/dist/fonts/noto-sans-hebrew-hebrew-700.woff2 +0 -0
  34. package/dist/fonts/noto-sans-latin-700.woff2 +0 -0
  35. package/dist/fonts/noto-sans-latin-ext-400.woff2 +0 -0
  36. package/dist/fonts/noto-sans-latin-ext-500.woff2 +0 -0
  37. package/dist/fonts/noto-sans-latin-ext-700.woff2 +0 -0
  38. package/dist/fonts/noto-sans-thai-thai-400.woff2 +0 -0
  39. package/dist/fonts/noto-sans-thai-thai-500.woff2 +0 -0
  40. package/dist/fonts/noto-sans-thai-thai-700.woff2 +0 -0
  41. package/dist/fonts/noto-sans-vietnamese-400.woff2 +0 -0
  42. package/dist/fonts/noto-sans-vietnamese-500.woff2 +0 -0
  43. package/dist/fonts/noto-sans-vietnamese-700.woff2 +0 -0
  44. package/dist/fonts/roboto-cyrillic-400.woff2 +0 -0
  45. package/dist/fonts/roboto-cyrillic-500.woff2 +0 -0
  46. package/dist/fonts/roboto-cyrillic-700.woff2 +0 -0
  47. package/dist/fonts/roboto-cyrillic-ext-400.woff2 +0 -0
  48. package/dist/fonts/roboto-cyrillic-ext-500.woff2 +0 -0
  49. package/dist/fonts/roboto-cyrillic-ext-700.woff2 +0 -0
  50. package/dist/fonts/roboto-greek-400.woff2 +0 -0
  51. package/dist/fonts/roboto-greek-500.woff2 +0 -0
  52. package/dist/fonts/roboto-greek-700.woff2 +0 -0
  53. package/dist/fonts/roboto-greek-ext-400.woff2 +0 -0
  54. package/dist/fonts/roboto-greek-ext-500.woff2 +0 -0
  55. package/dist/fonts/roboto-greek-ext-700.woff2 +0 -0
  56. package/dist/fonts/roboto-latin-700.woff2 +0 -0
  57. package/dist/fonts/roboto-latin-ext-400.woff2 +0 -0
  58. package/dist/fonts/roboto-latin-ext-500.woff2 +0 -0
  59. package/dist/fonts/roboto-latin-ext-700.woff2 +0 -0
  60. package/dist/fonts/roboto-vietnamese-400.woff2 +0 -0
  61. package/dist/fonts/roboto-vietnamese-500.woff2 +0 -0
  62. package/dist/fonts/roboto-vietnamese-700.woff2 +0 -0
  63. package/dist/js/chunks/chunk-2CS6TITK.mjs +219 -0
  64. package/dist/js/chunks/chunk-2CS6TITK.mjs.map +7 -0
  65. package/dist/js/chunks/chunk-2RLBDFH4.mjs +108 -0
  66. package/dist/js/chunks/chunk-2RLBDFH4.mjs.map +7 -0
  67. package/dist/js/chunks/chunk-3L3QIYLC.mjs +85 -0
  68. package/dist/js/chunks/chunk-3L3QIYLC.mjs.map +7 -0
  69. package/dist/js/chunks/chunk-4EWGD4V2.mjs +75 -0
  70. package/dist/js/chunks/chunk-4EWGD4V2.mjs.map +7 -0
  71. package/dist/js/chunks/chunk-4IKVPCSU.mjs +7 -0
  72. package/dist/js/chunks/chunk-4IKVPCSU.mjs.map +7 -0
  73. package/dist/js/chunks/chunk-4PIXLDNJ.mjs +127 -0
  74. package/dist/js/chunks/chunk-4PIXLDNJ.mjs.map +7 -0
  75. package/dist/js/chunks/{chunk-A7ALMYUR.mjs → chunk-4QUCNFSD.mjs} +68 -125
  76. package/dist/js/chunks/chunk-4QUCNFSD.mjs.map +7 -0
  77. package/dist/js/chunks/{chunk-4TKTLGEM.mjs → chunk-4TRZ2AER.mjs} +35 -41
  78. package/dist/js/chunks/chunk-4TRZ2AER.mjs.map +7 -0
  79. package/dist/js/chunks/{chunk-BG6ZRB5H.mjs → chunk-5KIHWJI2.mjs} +40 -26
  80. package/dist/js/chunks/chunk-5KIHWJI2.mjs.map +7 -0
  81. package/dist/js/chunks/{chunk-YDCS5S3J.mjs → chunk-67ZPPKXS.mjs} +20 -33
  82. package/dist/js/chunks/chunk-67ZPPKXS.mjs.map +7 -0
  83. package/dist/js/chunks/{chunk-3DHK5CZU.mjs → chunk-6FSEUFVW.mjs} +40 -29
  84. package/dist/js/chunks/chunk-6FSEUFVW.mjs.map +7 -0
  85. package/dist/js/chunks/chunk-752ADW4M.mjs +225 -0
  86. package/dist/js/chunks/chunk-752ADW4M.mjs.map +7 -0
  87. package/dist/js/chunks/{chunk-GVGT6MIU.mjs → chunk-75E5EDJF.mjs} +3 -11
  88. package/dist/js/chunks/chunk-75E5EDJF.mjs.map +7 -0
  89. package/dist/js/chunks/{chunk-TBM3FT7G.mjs → chunk-7NLUI3RR.mjs} +148 -78
  90. package/dist/js/chunks/chunk-7NLUI3RR.mjs.map +7 -0
  91. package/dist/js/chunks/chunk-7W7TV6NY.mjs +108 -0
  92. package/dist/js/chunks/chunk-7W7TV6NY.mjs.map +7 -0
  93. package/dist/js/chunks/chunk-7YQBHTK3.mjs +225 -0
  94. package/dist/js/chunks/chunk-7YQBHTK3.mjs.map +7 -0
  95. package/dist/js/chunks/chunk-7YZ5CN3V.mjs +33 -0
  96. package/dist/js/chunks/chunk-7YZ5CN3V.mjs.map +7 -0
  97. package/dist/js/chunks/chunk-AI73GJKG.mjs +28 -0
  98. package/dist/js/chunks/chunk-AI73GJKG.mjs.map +7 -0
  99. package/dist/js/chunks/{chunk-NS2UMNZV.mjs → chunk-ANKFWNWT.mjs} +21 -45
  100. package/dist/js/chunks/chunk-ANKFWNWT.mjs.map +7 -0
  101. package/dist/js/chunks/{chunk-GIW4K4SE.mjs → chunk-B7DQFHA5.mjs} +37 -53
  102. package/dist/js/chunks/chunk-B7DQFHA5.mjs.map +7 -0
  103. package/dist/js/chunks/chunk-BIGU5RCJ.mjs +153 -0
  104. package/dist/js/chunks/chunk-BIGU5RCJ.mjs.map +7 -0
  105. package/dist/js/chunks/{chunk-GUB3TNO2.mjs → chunk-BPF3I2MN.mjs} +109 -27
  106. package/dist/js/chunks/chunk-BPF3I2MN.mjs.map +7 -0
  107. package/dist/js/chunks/chunk-CMGXGYUC.mjs +74 -0
  108. package/dist/js/chunks/chunk-CMGXGYUC.mjs.map +7 -0
  109. package/dist/js/chunks/{chunk-JIDMQGK6.mjs → chunk-CSYWKEK3.mjs} +322 -223
  110. package/dist/js/chunks/chunk-CSYWKEK3.mjs.map +7 -0
  111. package/dist/js/chunks/chunk-CZSQHXEV.mjs +227 -0
  112. package/dist/js/chunks/chunk-CZSQHXEV.mjs.map +7 -0
  113. package/dist/js/chunks/chunk-DZYVU75J.mjs +121 -0
  114. package/dist/js/chunks/chunk-DZYVU75J.mjs.map +7 -0
  115. package/dist/js/chunks/{chunk-QDAL4IYN.mjs → chunk-EC26RU2D.mjs} +11 -29
  116. package/dist/js/chunks/chunk-EC26RU2D.mjs.map +7 -0
  117. package/dist/js/chunks/{chunk-3GVFZ4XO.mjs → chunk-EVCVFEV3.mjs} +238 -152
  118. package/dist/js/chunks/chunk-EVCVFEV3.mjs.map +7 -0
  119. package/dist/js/chunks/chunk-FCNF4GRJ.mjs +445 -0
  120. package/dist/js/chunks/chunk-FCNF4GRJ.mjs.map +7 -0
  121. package/dist/js/chunks/chunk-GCWWEZKO.mjs +342 -0
  122. package/dist/js/chunks/chunk-GCWWEZKO.mjs.map +7 -0
  123. package/dist/js/chunks/chunk-GNRSYMVH.mjs +1 -0
  124. package/dist/js/chunks/chunk-GVZQH2H5.mjs +54 -0
  125. package/dist/js/chunks/chunk-GVZQH2H5.mjs.map +7 -0
  126. package/dist/js/chunks/chunk-GWZ76SR4.mjs +435 -0
  127. package/dist/js/chunks/chunk-GWZ76SR4.mjs.map +7 -0
  128. package/dist/js/chunks/{chunk-ZAS25YFD.mjs → chunk-ILDRRG7T.mjs} +21 -23
  129. package/dist/js/chunks/chunk-ILDRRG7T.mjs.map +7 -0
  130. package/dist/js/chunks/chunk-INLZWHLY.mjs +80 -0
  131. package/dist/js/chunks/chunk-INLZWHLY.mjs.map +7 -0
  132. package/dist/js/chunks/chunk-JUKBBN6P.mjs +175 -0
  133. package/dist/js/chunks/chunk-JUKBBN6P.mjs.map +7 -0
  134. package/dist/js/chunks/chunk-KYIEG4U3.mjs +730 -0
  135. package/dist/js/chunks/chunk-KYIEG4U3.mjs.map +7 -0
  136. package/dist/js/chunks/{chunk-KHV6DZXX.mjs → chunk-KZPSAXIU.mjs} +156 -46
  137. package/dist/js/chunks/chunk-KZPSAXIU.mjs.map +7 -0
  138. package/dist/js/chunks/chunk-LDXCC2L3.mjs +438 -0
  139. package/dist/js/chunks/chunk-LDXCC2L3.mjs.map +7 -0
  140. package/dist/js/chunks/chunk-NAC72P7R.mjs +137 -0
  141. package/dist/js/chunks/chunk-NAC72P7R.mjs.map +7 -0
  142. package/dist/js/chunks/chunk-NBJAUGPP.mjs +244 -0
  143. package/dist/js/chunks/chunk-NBJAUGPP.mjs.map +7 -0
  144. package/dist/js/chunks/chunk-NNHVANQA.mjs +113 -0
  145. package/dist/js/chunks/chunk-NNHVANQA.mjs.map +7 -0
  146. package/dist/js/chunks/chunk-NVQ5EHCU.mjs +376 -0
  147. package/dist/js/chunks/chunk-NVQ5EHCU.mjs.map +7 -0
  148. package/dist/js/chunks/{chunk-Z2NRKI7R.mjs → chunk-OP43LLIC.mjs} +44 -73
  149. package/dist/js/chunks/chunk-OP43LLIC.mjs.map +7 -0
  150. package/dist/js/chunks/chunk-OUCHKSAW.mjs +63 -0
  151. package/dist/js/chunks/chunk-OUCHKSAW.mjs.map +7 -0
  152. package/dist/js/chunks/{chunk-PM655FXL.mjs → chunk-OYNUDOHR.mjs} +20 -48
  153. package/dist/js/chunks/chunk-OYNUDOHR.mjs.map +7 -0
  154. package/dist/js/chunks/{chunk-UEZUJQ66.mjs → chunk-P6DRQ6KS.mjs} +36 -31
  155. package/dist/js/chunks/chunk-P6DRQ6KS.mjs.map +7 -0
  156. package/dist/js/chunks/chunk-PA7NU5AK.mjs +99 -0
  157. package/dist/js/chunks/chunk-PA7NU5AK.mjs.map +7 -0
  158. package/dist/js/chunks/chunk-QACZ6TUP.mjs +224 -0
  159. package/dist/js/chunks/chunk-QACZ6TUP.mjs.map +7 -0
  160. package/dist/js/chunks/{chunk-5HQSGDZ5.mjs → chunk-QXKWVHBD.mjs} +286 -203
  161. package/dist/js/chunks/chunk-QXKWVHBD.mjs.map +7 -0
  162. package/dist/js/chunks/{chunk-DAIU5SLG.mjs → chunk-ROH2HDB4.mjs} +7 -6
  163. package/dist/js/chunks/chunk-ROH2HDB4.mjs.map +7 -0
  164. package/dist/js/chunks/chunk-S23RJ3XY.mjs +86 -0
  165. package/dist/js/chunks/chunk-S23RJ3XY.mjs.map +7 -0
  166. package/dist/js/chunks/{chunk-FS7XY3HT.mjs → chunk-SPPHF7YZ.mjs} +36 -29
  167. package/dist/js/chunks/chunk-SPPHF7YZ.mjs.map +7 -0
  168. package/dist/js/chunks/chunk-T3BNSRP3.mjs +152 -0
  169. package/dist/js/chunks/chunk-T3BNSRP3.mjs.map +7 -0
  170. package/dist/js/chunks/chunk-TFABTUAZ.mjs +108 -0
  171. package/dist/js/chunks/chunk-TFABTUAZ.mjs.map +7 -0
  172. package/dist/js/chunks/chunk-U4B3VHFS.mjs +507 -0
  173. package/dist/js/chunks/chunk-U4B3VHFS.mjs.map +7 -0
  174. package/dist/js/chunks/chunk-UGJHCHXG.mjs +341 -0
  175. package/dist/js/chunks/chunk-UGJHCHXG.mjs.map +7 -0
  176. package/dist/js/chunks/chunk-VFV75DHF.mjs +70 -0
  177. package/dist/js/chunks/chunk-VFV75DHF.mjs.map +7 -0
  178. package/dist/js/chunks/{chunk-4HZMB7LI.mjs → chunk-VGY4M57S.mjs} +281 -135
  179. package/dist/js/chunks/chunk-VGY4M57S.mjs.map +7 -0
  180. package/dist/js/chunks/chunk-VH4BMAZS.mjs +167 -0
  181. package/dist/js/chunks/chunk-VH4BMAZS.mjs.map +7 -0
  182. package/dist/js/chunks/chunk-VJVQIXHC.mjs +123 -0
  183. package/dist/js/chunks/chunk-VJVQIXHC.mjs.map +7 -0
  184. package/dist/js/chunks/{chunk-S3XDFGSZ.mjs → chunk-VMY55K2X.mjs} +92 -141
  185. package/dist/js/chunks/chunk-VMY55K2X.mjs.map +7 -0
  186. package/dist/js/chunks/{chunk-UEXCIMJZ.mjs → chunk-VR3L2WN5.mjs} +11 -17
  187. package/dist/js/chunks/chunk-VR3L2WN5.mjs.map +7 -0
  188. package/dist/js/chunks/chunk-W6FAL3TI.mjs +38 -0
  189. package/dist/js/chunks/chunk-W6FAL3TI.mjs.map +7 -0
  190. package/dist/js/chunks/chunk-WU7XJ4RR.mjs +450 -0
  191. package/dist/js/chunks/chunk-WU7XJ4RR.mjs.map +7 -0
  192. package/dist/js/chunks/chunk-X7SDA2J5.mjs +116 -0
  193. package/dist/js/chunks/chunk-X7SDA2J5.mjs.map +7 -0
  194. package/dist/js/chunks/chunk-Y6H2X7ZC.mjs +209 -0
  195. package/dist/js/chunks/chunk-Y6H2X7ZC.mjs.map +7 -0
  196. package/dist/js/chunks/chunk-Y6TLRA3U.mjs +129 -0
  197. package/dist/js/chunks/chunk-Y6TLRA3U.mjs.map +7 -0
  198. package/dist/js/chunks/chunk-Z4GICXR2.mjs +190 -0
  199. package/dist/js/chunks/chunk-Z4GICXR2.mjs.map +7 -0
  200. package/dist/js/chunks/chunk-Z4OARDZ7.mjs +442 -0
  201. package/dist/js/chunks/chunk-Z4OARDZ7.mjs.map +7 -0
  202. package/dist/js/chunks/{chunk-MZ6Z24BX.mjs → chunk-ZJNLAGY5.mjs} +19 -34
  203. package/dist/js/chunks/chunk-ZJNLAGY5.mjs.map +7 -0
  204. package/dist/js/chunks/chunk-ZKWUWBUB.mjs +81 -0
  205. package/dist/js/chunks/chunk-ZKWUWBUB.mjs.map +7 -0
  206. package/dist/js/chunks/chunk-ZM3XBHWV.mjs +746 -0
  207. package/dist/js/chunks/chunk-ZM3XBHWV.mjs.map +7 -0
  208. package/dist/js/chunks/chunk-ZO6ZLHFF.mjs +48 -0
  209. package/dist/js/chunks/chunk-ZO6ZLHFF.mjs.map +7 -0
  210. package/dist/js/chunks/chunk-ZVLOUDIJ.mjs +251 -0
  211. package/dist/js/chunks/chunk-ZVLOUDIJ.mjs.map +7 -0
  212. package/dist/js/expressive.cjs +10333 -4070
  213. package/dist/js/expressive.cjs.map +4 -4
  214. package/dist/js/expressive.js +10333 -4070
  215. package/dist/js/expressive.js.map +4 -4
  216. package/dist/js/expressive.min.js +23 -25
  217. package/dist/js/expressive.min.js.map +4 -4
  218. package/dist/js/expressive.mjs +184 -69
  219. package/dist/js/expressive.mjs.map +2 -2
  220. package/dist/js/internal/behaviors/bottomSheets.mjs +4 -3
  221. package/dist/js/internal/behaviors/copy.mjs +9 -0
  222. package/dist/js/internal/behaviors/copy.mjs.map +7 -0
  223. package/dist/js/internal/behaviors/dataTables.mjs +10 -0
  224. package/dist/js/internal/behaviors/dataTables.mjs.map +7 -0
  225. package/dist/js/internal/behaviors/dialogs.mjs +2 -2
  226. package/dist/js/internal/behaviors/forms.mjs +2 -2
  227. package/dist/js/internal/behaviors/imageCompare.mjs +8 -0
  228. package/dist/js/internal/behaviors/imageCompare.mjs.map +7 -0
  229. package/dist/js/internal/behaviors/lists.mjs +8 -0
  230. package/dist/js/internal/behaviors/lists.mjs.map +7 -0
  231. package/dist/js/internal/behaviors/paneResize.mjs +8 -0
  232. package/dist/js/internal/behaviors/paneResize.mjs.map +7 -0
  233. package/dist/js/internal/behaviors/sheetDrag.mjs +7 -2
  234. package/dist/js/internal/behaviors/sideSheets.mjs +4 -3
  235. package/dist/js/internal/behaviors/sortable.mjs +8 -0
  236. package/dist/js/internal/behaviors/sortable.mjs.map +7 -0
  237. package/dist/js/internal/behaviors/theme.mjs +8 -0
  238. package/dist/js/internal/behaviors/theme.mjs.map +7 -0
  239. package/dist/js/internal/behaviors/tour.mjs +8 -0
  240. package/dist/js/internal/behaviors/tour.mjs.map +7 -0
  241. package/dist/js/internal/behaviors/transferList.mjs +8 -0
  242. package/dist/js/internal/behaviors/transferList.mjs.map +7 -0
  243. package/dist/js/internal/components/appBar.mjs +3 -2
  244. package/dist/js/internal/components/autocomplete.mjs +4 -4
  245. package/dist/js/internal/components/backToTop.mjs +9 -0
  246. package/dist/js/internal/components/backToTop.mjs.map +7 -0
  247. package/dist/js/internal/components/barChart.mjs +5 -4
  248. package/dist/js/internal/components/buttonGroup.mjs +3 -2
  249. package/dist/js/internal/components/buttons.mjs +3 -3
  250. package/dist/js/internal/components/cards.mjs +3 -3
  251. package/dist/js/internal/components/carousel.mjs +3 -3
  252. package/dist/js/internal/components/cascader.mjs +10 -0
  253. package/dist/js/internal/components/cascader.mjs.map +7 -0
  254. package/dist/js/internal/components/characterCounter.mjs +3 -2
  255. package/dist/js/internal/components/chips.mjs +6 -5
  256. package/dist/js/internal/components/colorPicker.mjs +9 -0
  257. package/dist/js/internal/components/colorPicker.mjs.map +7 -0
  258. package/dist/js/internal/components/columnChart.mjs +4 -3
  259. package/dist/js/internal/components/commandPalette.mjs +3 -3
  260. package/dist/js/internal/components/confetti.mjs +3 -2
  261. package/dist/js/internal/components/currencyInput.mjs +9 -0
  262. package/dist/js/internal/components/currencyInput.mjs.map +7 -0
  263. package/dist/js/internal/components/datepicker.mjs +11 -8
  264. package/dist/js/internal/components/expandingCard.mjs +3 -3
  265. package/dist/js/internal/components/funnelChart.mjs +10 -0
  266. package/dist/js/internal/components/funnelChart.mjs.map +7 -0
  267. package/dist/js/internal/components/heatmapChart.mjs +4 -3
  268. package/dist/js/internal/components/hoverCard.mjs +9 -0
  269. package/dist/js/internal/components/hoverCard.mjs.map +7 -0
  270. package/dist/js/internal/components/index.mjs +133 -64
  271. package/dist/js/internal/components/inputMask.mjs +9 -0
  272. package/dist/js/internal/components/inputMask.mjs.map +7 -0
  273. package/dist/js/internal/components/keypad.mjs +9 -0
  274. package/dist/js/internal/components/keypad.mjs.map +7 -0
  275. package/dist/js/internal/components/lightbox.mjs +3 -3
  276. package/dist/js/internal/components/lineChart.mjs +29 -4
  277. package/dist/js/internal/components/loadingOverlay.mjs +9 -0
  278. package/dist/js/internal/components/loadingOverlay.mjs.map +7 -0
  279. package/dist/js/internal/components/mapView.mjs +3 -3
  280. package/dist/js/internal/components/menu.mjs +3 -3
  281. package/dist/js/internal/components/menubar.mjs +10 -0
  282. package/dist/js/internal/components/menubar.mjs.map +7 -0
  283. package/dist/js/internal/components/messageScroller.mjs +3 -3
  284. package/dist/js/internal/components/mixedChart.mjs +5 -4
  285. package/dist/js/internal/components/navigationRail.mjs +3 -2
  286. package/dist/js/internal/components/particles.mjs +3 -2
  287. package/dist/js/internal/components/pieChart.mjs +4 -3
  288. package/dist/js/internal/components/pullToRefresh.mjs +9 -0
  289. package/dist/js/internal/components/pullToRefresh.mjs.map +7 -0
  290. package/dist/js/internal/components/questionnaire.mjs +3 -3
  291. package/dist/js/internal/components/radarChart.mjs +4 -3
  292. package/dist/js/internal/components/radialChart.mjs +4 -3
  293. package/dist/js/internal/components/registry.mjs +59 -40
  294. package/dist/js/internal/components/richTextEditor.mjs +3 -3
  295. package/dist/js/internal/components/sankeyChart.mjs +10 -0
  296. package/dist/js/internal/components/sankeyChart.mjs.map +7 -0
  297. package/dist/js/internal/components/scatterChart.mjs +10 -0
  298. package/dist/js/internal/components/scatterChart.mjs.map +7 -0
  299. package/dist/js/internal/components/scrollspy.mjs +3 -2
  300. package/dist/js/internal/components/select.mjs +4 -4
  301. package/dist/js/internal/components/showMore.mjs +9 -0
  302. package/dist/js/internal/components/showMore.mjs.map +7 -0
  303. package/dist/js/internal/components/slider.mjs +3 -3
  304. package/dist/js/internal/components/snackbar.mjs +2 -2
  305. package/dist/js/internal/components/swipeActions.mjs +9 -0
  306. package/dist/js/internal/components/swipeActions.mjs.map +7 -0
  307. package/dist/js/internal/components/tabs.mjs +3 -4
  308. package/dist/js/internal/components/timepicker.mjs +5 -4
  309. package/dist/js/internal/components/tooltip.mjs +3 -3
  310. package/dist/js/internal/components/treeSelect.mjs +13 -0
  311. package/dist/js/internal/components/treeSelect.mjs.map +7 -0
  312. package/dist/js/internal/components/treemapChart.mjs +10 -0
  313. package/dist/js/internal/components/treemapChart.mjs.map +7 -0
  314. package/dist/js/internal/core/component.mjs +2 -1
  315. package/dist/js/internal/core/formControl.mjs +12 -0
  316. package/dist/js/internal/core/formControl.mjs.map +7 -0
  317. package/dist/js/internal/core/spring.mjs +11 -0
  318. package/dist/js/internal/core/spring.mjs.map +7 -0
  319. package/dist/js/internal/core/utils.mjs +11 -3
  320. package/dist/js/internal/plugins/dockedDisplayPlugin.mjs +2 -2
  321. package/dist/js/internal/plugins/modalDisplayPlugin.mjs +13 -0
  322. package/dist/js/internal/plugins/modalDisplayPlugin.mjs.map +7 -0
  323. package/dist/js/modular.mjs +175 -69
  324. package/dist/types/behaviors/bottomSheets.d.ts +19 -3
  325. package/dist/types/behaviors/copy.d.ts +18 -0
  326. package/dist/types/behaviors/dataTables.d.ts +129 -0
  327. package/dist/types/behaviors/dialogs.d.ts +27 -1
  328. package/dist/types/behaviors/forms.d.ts +68 -2
  329. package/dist/types/behaviors/imageCompare.d.ts +12 -0
  330. package/dist/types/behaviors/lists.d.ts +12 -0
  331. package/dist/types/behaviors/paneResize.d.ts +29 -0
  332. package/dist/types/behaviors/sheetDrag.d.ts +18 -0
  333. package/dist/types/behaviors/sideSheets.d.ts +1 -1
  334. package/dist/types/behaviors/sortable.d.ts +28 -0
  335. package/dist/types/behaviors/theme.d.ts +22 -0
  336. package/dist/types/behaviors/tour.d.ts +36 -0
  337. package/dist/types/behaviors/transferList.d.ts +51 -0
  338. package/dist/types/components/appBar.d.ts +5 -6
  339. package/dist/types/components/autocomplete.d.ts +92 -17
  340. package/dist/types/components/backToTop.d.ts +36 -0
  341. package/dist/types/components/barChart.d.ts +3 -6
  342. package/dist/types/components/buttonGroup.d.ts +2 -4
  343. package/dist/types/components/buttons.d.ts +5 -5
  344. package/dist/types/components/cards.d.ts +3 -16
  345. package/dist/types/components/carousel.d.ts +9 -15
  346. package/dist/types/components/cascader.d.ts +130 -0
  347. package/dist/types/components/characterCounter.d.ts +2 -15
  348. package/dist/types/components/chips.d.ts +65 -19
  349. package/dist/types/components/colorPicker.d.ts +42 -0
  350. package/dist/types/components/columnChart.d.ts +23 -10
  351. package/dist/types/components/commandPalette.d.ts +11 -16
  352. package/dist/types/components/confetti.d.ts +2 -4
  353. package/dist/types/components/currencyInput.d.ts +59 -0
  354. package/dist/types/components/datepicker.d.ts +59 -36
  355. package/dist/types/components/expandingCard.d.ts +6 -6
  356. package/dist/types/components/funnelChart.d.ts +38 -0
  357. package/dist/types/components/heatmapChart.d.ts +39 -8
  358. package/dist/types/components/hoverCard.d.ts +58 -0
  359. package/dist/types/components/index.d.ts +17 -1
  360. package/dist/types/components/inputMask.d.ts +30 -0
  361. package/dist/types/components/keypad.d.ts +66 -0
  362. package/dist/types/components/lightbox.d.ts +17 -25
  363. package/dist/types/components/lineChart.d.ts +176 -10
  364. package/dist/types/components/loadingOverlay.d.ts +42 -0
  365. package/dist/types/components/mapView.d.ts +26 -17
  366. package/dist/types/components/menu.d.ts +61 -22
  367. package/dist/types/components/menubar.d.ts +37 -0
  368. package/dist/types/components/messageScroller.d.ts +2 -14
  369. package/dist/types/components/mixedChart.d.ts +15 -6
  370. package/dist/types/components/navigationRail.d.ts +16 -5
  371. package/dist/types/components/particles.d.ts +8 -4
  372. package/dist/types/components/pieChart.d.ts +32 -7
  373. package/dist/types/components/pullToRefresh.d.ts +80 -0
  374. package/dist/types/components/questionnaire.d.ts +58 -16
  375. package/dist/types/components/radarChart.d.ts +10 -6
  376. package/dist/types/components/radialChart.d.ts +58 -8
  377. package/dist/types/components/registry.d.ts +77 -3
  378. package/dist/types/components/richTextEditor.d.ts +6 -14
  379. package/dist/types/components/sankeyChart.d.ts +72 -0
  380. package/dist/types/components/scatterChart.d.ts +102 -0
  381. package/dist/types/components/scrollspy.d.ts +3 -5
  382. package/dist/types/components/select.d.ts +43 -30
  383. package/dist/types/components/showMore.d.ts +51 -0
  384. package/dist/types/components/slider.d.ts +5 -15
  385. package/dist/types/components/snackbar.d.ts +62 -0
  386. package/dist/types/components/swipeActions.d.ts +81 -0
  387. package/dist/types/components/tabs.d.ts +93 -27
  388. package/dist/types/components/timepicker.d.ts +114 -20
  389. package/dist/types/components/tooltip.d.ts +56 -20
  390. package/dist/types/components/treeSelect.d.ts +106 -0
  391. package/dist/types/components/treemapChart.d.ts +56 -0
  392. package/dist/types/core/component.d.ts +43 -25
  393. package/dist/types/core/formControl.d.ts +21 -0
  394. package/dist/types/core/spring.d.ts +20 -0
  395. package/dist/types/core/utils.d.ts +85 -72
  396. package/dist/types/modular.d.ts +33 -1
  397. package/dist/types/plugins/dockedDisplayPlugin.d.ts +10 -7
  398. package/dist/types/plugins/modalDisplayPlugin.d.ts +32 -0
  399. package/package.json +10 -8
  400. package/src/sass/README.md +27 -18
  401. package/src/sass/abstracts/_breakpoints.scss +0 -1
  402. package/src/sass/abstracts/_elevation.scss +13 -7
  403. package/src/sass/abstracts/_index.scss +1 -0
  404. package/src/sass/abstracts/_mixins.scss +438 -92
  405. package/src/sass/abstracts/_spring.scss +63 -0
  406. package/src/sass/abstracts/_variables.scss +43 -15
  407. package/src/sass/base/_fonts.scss +61 -48
  408. package/src/sass/base/_global.scss +105 -34
  409. package/src/sass/base/_index.scss +3 -1
  410. package/src/sass/base/_normalize.scss +59 -114
  411. package/src/sass/base/_print.scss +21 -0
  412. package/src/sass/base/_prose.scss +68 -0
  413. package/src/sass/base/_typography.scss +9 -5
  414. package/src/sass/components/_accordion.scss +9 -16
  415. package/src/sass/components/_alert.scss +102 -0
  416. package/src/sass/components/_aura.scss +8 -3
  417. package/src/sass/components/_avatar.scss +3 -3
  418. package/src/sass/components/_back-to-top.scss +38 -0
  419. package/src/sass/components/_badges.scss +7 -13
  420. package/src/sass/components/_bar-chart.scss +41 -19
  421. package/src/sass/components/_bottom-sheet.scss +44 -16
  422. package/src/sass/components/_breadcrumb.scss +8 -1
  423. package/src/sass/components/_button-groups.scss +44 -89
  424. package/src/sass/components/_buttons.scss +156 -63
  425. package/src/sass/components/_calendar.scss +246 -0
  426. package/src/sass/components/_cards.scss +41 -68
  427. package/src/sass/components/_carousel.scss +43 -158
  428. package/src/sass/components/_cascader.scss +142 -0
  429. package/src/sass/components/_chips.scss +36 -52
  430. package/src/sass/components/_column-chart.scss +19 -12
  431. package/src/sass/components/_command-palette.scss +4 -7
  432. package/src/sass/components/_confetti.scss +0 -2
  433. package/src/sass/components/_countdown.scss +1 -1
  434. package/src/sass/components/_data-table.scss +162 -27
  435. package/src/sass/components/_datepicker.scss +57 -62
  436. package/src/sass/components/_description-list.scss +85 -0
  437. package/src/sass/components/_dialog.scss +42 -44
  438. package/src/sass/components/_docked-display.scss +1 -3
  439. package/src/sass/components/_drag-handle.scss +16 -20
  440. package/src/sass/components/_expanding-card.scss +20 -9
  441. package/src/sass/components/_fab-menu.scss +44 -32
  442. package/src/sass/components/_funnel-chart.scss +124 -0
  443. package/src/sass/components/_heatmap-chart.scss +113 -24
  444. package/src/sass/components/_icon-buttons.scss +7 -8
  445. package/src/sass/components/_icons-material-design.scss +2 -2
  446. package/src/sass/components/_image-compare.scss +108 -0
  447. package/src/sass/components/_index.scss +21 -0
  448. package/src/sass/components/_keypad.scss +182 -0
  449. package/src/sass/components/_kpi.scss +6 -11
  450. package/src/sass/components/_lightbox.scss +26 -20
  451. package/src/sass/components/_line-chart.scss +16 -2
  452. package/src/sass/components/_list.scss +59 -14
  453. package/src/sass/components/_loading-indicator.scss +1 -0
  454. package/src/sass/components/_loading-overlay.scss +105 -0
  455. package/src/sass/components/_map.scss +35 -13
  456. package/src/sass/components/_marquee.scss +3 -2
  457. package/src/sass/components/_mega-menu.scss +137 -0
  458. package/src/sass/components/_menu.scss +159 -182
  459. package/src/sass/components/_menubar.scss +59 -0
  460. package/src/sass/components/_message-scroller.scss +2 -2
  461. package/src/sass/components/_message.scss +3 -3
  462. package/src/sass/components/_mixed-chart.scss +37 -9
  463. package/src/sass/components/_modal-display.scss +21 -0
  464. package/src/sass/components/_navbar.scss +43 -65
  465. package/src/sass/components/_navigation-bar.scss +15 -77
  466. package/src/sass/components/_navigation-rail.scss +171 -121
  467. package/src/sass/components/_org-chart.scss +192 -0
  468. package/src/sass/components/_page-footer.scss +16 -13
  469. package/src/sass/components/_pagination.scss +6 -13
  470. package/src/sass/components/_panes.scss +33 -31
  471. package/src/sass/components/_particles.scss +0 -2
  472. package/src/sass/components/_pie-chart.scss +91 -11
  473. package/src/sass/components/_popover.scss +18 -5
  474. package/src/sass/components/_progress.scss +158 -35
  475. package/src/sass/components/_pull-to-refresh.scss +90 -0
  476. package/src/sass/components/_questionnaire.scss +74 -3
  477. package/src/sass/components/_radar-chart.scss +38 -10
  478. package/src/sass/components/_radial-chart.scss +113 -5
  479. package/src/sass/components/_rich-text-editor.scss +2 -2
  480. package/src/sass/components/_sankey-chart.scss +114 -0
  481. package/src/sass/components/_scatter-chart.scss +153 -0
  482. package/src/sass/components/_scrim.scss +0 -2
  483. package/src/sass/components/_scrollspy.scss +0 -2
  484. package/src/sass/components/_search.scss +26 -22
  485. package/src/sass/components/_show-more.scss +8 -0
  486. package/src/sass/components/_side-sheet.scss +23 -40
  487. package/src/sass/components/_skeleton.scss +2 -4
  488. package/src/sass/components/_snackbar.scss +27 -21
  489. package/src/sass/components/_split-button.scss +5 -5
  490. package/src/sass/components/_stat.scss +3 -8
  491. package/src/sass/components/_stepper.scss +1 -5
  492. package/src/sass/components/_swipe-actions.scss +71 -0
  493. package/src/sass/components/_tabs.scss +51 -32
  494. package/src/sass/components/_timeline.scss +12 -12
  495. package/src/sass/components/_timepicker.scss +111 -112
  496. package/src/sass/components/_toolbar.scss +35 -47
  497. package/src/sass/components/_tooltip.scss +21 -12
  498. package/src/sass/components/_tour.scss +89 -0
  499. package/src/sass/components/_transfer-list.scss +73 -0
  500. package/src/sass/components/_transitions.scss +4 -4
  501. package/src/sass/components/_tree.scss +3 -16
  502. package/src/sass/components/_treemap-chart.scss +122 -0
  503. package/src/sass/components/forms/_checkboxes.scss +140 -86
  504. package/src/sass/components/forms/_color-picker.scss +135 -0
  505. package/src/sass/components/forms/_color-swatches.scss +85 -0
  506. package/src/sass/components/forms/_drop-zone.scss +15 -9
  507. package/src/sass/components/forms/_fieldset.scss +10 -10
  508. package/src/sass/components/forms/_file-input.scss +6 -9
  509. package/src/sass/components/forms/_index.scss +3 -1
  510. package/src/sass/components/forms/_input-fields.scss +254 -90
  511. package/src/sass/components/forms/_radio-buttons.scss +40 -127
  512. package/src/sass/components/forms/_rating.scss +2 -32
  513. package/src/sass/components/forms/_select.scss +199 -23
  514. package/src/sass/components/forms/_slider.scss +140 -330
  515. package/src/sass/components/forms/_switches.scss +53 -164
  516. package/src/sass/custom.scss +10 -1
  517. package/src/sass/expressive.scss +3 -63
  518. package/src/sass/tokens/_contrast.scss +94 -0
  519. package/src/sass/tokens/_elevation.scss +16 -0
  520. package/src/sass/tokens/_index.scss +5 -0
  521. package/src/sass/tokens/_motion.scss +109 -0
  522. package/src/sass/tokens/_reference.scss +72 -141
  523. package/src/sass/tokens/_shape.scss +38 -0
  524. package/src/sass/tokens/_stacking.scss +27 -0
  525. package/src/sass/tokens/_state.scss +2 -4
  526. package/src/sass/tokens/_theme.scss +11 -2
  527. package/src/sass/tokens/_vibrant.scss +2 -5
  528. package/src/sass/utilities/_colors.scss +6 -1
  529. package/src/sass/utilities/_defer-render.scss +17 -0
  530. package/src/sass/utilities/_helpers.scss +183 -26
  531. package/src/sass/utilities/_index.scss +2 -1
  532. package/src/sass/utilities/_scroll-area.scss +0 -2
  533. package/src/sass/utilities/_spacing.scss +52 -34
  534. package/src/sass/utilities/_typescale.scss +8 -1
  535. package/src/sass/utilities/_visibility.scss +47 -76
  536. package/src/sass/utilities/_z-depth.scss +7 -4
  537. package/dist/js/chunks/chunk-3DHK5CZU.mjs.map +0 -7
  538. package/dist/js/chunks/chunk-3GVFZ4XO.mjs.map +0 -7
  539. package/dist/js/chunks/chunk-4HZMB7LI.mjs.map +0 -7
  540. package/dist/js/chunks/chunk-4KMNFIFZ.mjs +0 -270
  541. package/dist/js/chunks/chunk-4KMNFIFZ.mjs.map +0 -7
  542. package/dist/js/chunks/chunk-4TKTLGEM.mjs.map +0 -7
  543. package/dist/js/chunks/chunk-5BKHWHYY.mjs +0 -292
  544. package/dist/js/chunks/chunk-5BKHWHYY.mjs.map +0 -7
  545. package/dist/js/chunks/chunk-5HQSGDZ5.mjs.map +0 -7
  546. package/dist/js/chunks/chunk-6N2XAEFK.mjs +0 -125
  547. package/dist/js/chunks/chunk-6N2XAEFK.mjs.map +0 -7
  548. package/dist/js/chunks/chunk-A7ALMYUR.mjs.map +0 -7
  549. package/dist/js/chunks/chunk-BG6ZRB5H.mjs.map +0 -7
  550. package/dist/js/chunks/chunk-CUQPB25U.mjs +0 -55
  551. package/dist/js/chunks/chunk-CUQPB25U.mjs.map +0 -7
  552. package/dist/js/chunks/chunk-DAIU5SLG.mjs.map +0 -7
  553. package/dist/js/chunks/chunk-FS7XY3HT.mjs.map +0 -7
  554. package/dist/js/chunks/chunk-GIW4K4SE.mjs.map +0 -7
  555. package/dist/js/chunks/chunk-GUB3TNO2.mjs.map +0 -7
  556. package/dist/js/chunks/chunk-GVGT6MIU.mjs.map +0 -7
  557. package/dist/js/chunks/chunk-GZKEFWPM.mjs +0 -181
  558. package/dist/js/chunks/chunk-GZKEFWPM.mjs.map +0 -7
  559. package/dist/js/chunks/chunk-HKT2S7VM.mjs +0 -48
  560. package/dist/js/chunks/chunk-HKT2S7VM.mjs.map +0 -7
  561. package/dist/js/chunks/chunk-ILP3PDTL.mjs +0 -187
  562. package/dist/js/chunks/chunk-ILP3PDTL.mjs.map +0 -7
  563. package/dist/js/chunks/chunk-JIDMQGK6.mjs.map +0 -7
  564. package/dist/js/chunks/chunk-KBNN3QDH.mjs +0 -7
  565. package/dist/js/chunks/chunk-KBNN3QDH.mjs.map +0 -7
  566. package/dist/js/chunks/chunk-KHV6DZXX.mjs.map +0 -7
  567. package/dist/js/chunks/chunk-KY6U46SM.mjs +0 -345
  568. package/dist/js/chunks/chunk-KY6U46SM.mjs.map +0 -7
  569. package/dist/js/chunks/chunk-LRZMJZ3T.mjs +0 -291
  570. package/dist/js/chunks/chunk-LRZMJZ3T.mjs.map +0 -7
  571. package/dist/js/chunks/chunk-LTWPGFBR.mjs +0 -59
  572. package/dist/js/chunks/chunk-LTWPGFBR.mjs.map +0 -7
  573. package/dist/js/chunks/chunk-MNPROCZF.mjs +0 -328
  574. package/dist/js/chunks/chunk-MNPROCZF.mjs.map +0 -7
  575. package/dist/js/chunks/chunk-MZ6Z24BX.mjs.map +0 -7
  576. package/dist/js/chunks/chunk-NS2UMNZV.mjs.map +0 -7
  577. package/dist/js/chunks/chunk-O5XPWXIQ.mjs +0 -406
  578. package/dist/js/chunks/chunk-O5XPWXIQ.mjs.map +0 -7
  579. package/dist/js/chunks/chunk-PM655FXL.mjs.map +0 -7
  580. package/dist/js/chunks/chunk-QDAL4IYN.mjs.map +0 -7
  581. package/dist/js/chunks/chunk-QERLECVU.mjs +0 -572
  582. package/dist/js/chunks/chunk-QERLECVU.mjs.map +0 -7
  583. package/dist/js/chunks/chunk-QJABDLSD.mjs +0 -112
  584. package/dist/js/chunks/chunk-QJABDLSD.mjs.map +0 -7
  585. package/dist/js/chunks/chunk-RHRQKTTX.mjs +0 -139
  586. package/dist/js/chunks/chunk-RHRQKTTX.mjs.map +0 -7
  587. package/dist/js/chunks/chunk-S3XDFGSZ.mjs.map +0 -7
  588. package/dist/js/chunks/chunk-SPETGK25.mjs +0 -59
  589. package/dist/js/chunks/chunk-SPETGK25.mjs.map +0 -7
  590. package/dist/js/chunks/chunk-TBM3FT7G.mjs.map +0 -7
  591. package/dist/js/chunks/chunk-UEXCIMJZ.mjs.map +0 -7
  592. package/dist/js/chunks/chunk-UEZUJQ66.mjs.map +0 -7
  593. package/dist/js/chunks/chunk-VGZSAFTX.mjs +0 -173
  594. package/dist/js/chunks/chunk-VGZSAFTX.mjs.map +0 -7
  595. package/dist/js/chunks/chunk-X7OCHZVF.mjs +0 -76
  596. package/dist/js/chunks/chunk-X7OCHZVF.mjs.map +0 -7
  597. package/dist/js/chunks/chunk-YDCS5S3J.mjs.map +0 -7
  598. package/dist/js/chunks/chunk-YMSXJON6.mjs +0 -79
  599. package/dist/js/chunks/chunk-YMSXJON6.mjs.map +0 -7
  600. package/dist/js/chunks/chunk-Z2NRKI7R.mjs.map +0 -7
  601. package/dist/js/chunks/chunk-ZAS25YFD.mjs.map +0 -7
  602. package/dist/js/chunks/chunk-ZKZKNSLC.mjs +0 -1
  603. /package/dist/js/chunks/{chunk-ZKZKNSLC.mjs.map → chunk-GNRSYMVH.mjs.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,1592 @@ the format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.16.0] - 2026-10-27
9
+
10
+ This release removes the aliases kept for markup written before 0.8.0. See
11
+ Removed and Migration below before upgrading.
12
+
13
+ ### Deprecated
14
+
15
+ - Chip sizing properties `--padding`, `--font-size` and `--font-size-icon`.
16
+ Use `--md-comp-chip-padding`, `--md-comp-chip-label-size` and
17
+ `--md-comp-chip-icon-size` instead. Each new property takes priority over
18
+ its old counterpart. Old overrides on a chip remain supported as fallbacks,
19
+ defaults are unchanged, and there is no removal date.
20
+
21
+ ### Added
22
+
23
+ - Native multiple-leaf TreeSelect through `<select data-tree multiple>`, with
24
+ independent leaf toggles, an open popup and optional search retaining hidden
25
+ choices. Native form submission includes all selected leaves and no branches.
26
+ Branch defaults never propagate into leaf choices; reset and refresh retain
27
+ native ownership. Selection and focus remain separate on the named tree.
28
+
29
+ - Opt-in single-leaf TreeSelect search through `searchable: true`. Matching leaf
30
+ paths open without changing the native selection. Clearing or closing restores
31
+ pre-query expansion, including through refresh and disabled-control recovery.
32
+ Search reuses accessible popup controls, localization and lifecycle handling
33
+ while retaining tree keyboard behavior and native leaf submission.
34
+ - Independent drop-zone file-count limits through `data-max-files`. Exact-count
35
+ choices pass; too many files invalidate the complete retained selection with
36
+ accessible count feedback and `expressive:reject` reason `count`. All selected
37
+ files appear in independent rejection snapshots. Shared Forms handling keeps
38
+ type/size precedence, application validity, deduplication and reset recovery.
39
+ - Optional per-file drop-zone byte limits through `data-max-size`, independent
40
+ of type checking. Exact-limit files pass; one oversized file invalidates the
41
+ whole retained selection with accessible feedback and `expressive:reject`
42
+ reason `size`. Combined rules preserve type-first feedback and application
43
+ custom validity. Constraint-aware deduplication, reset and shadow handling
44
+ reuse the existing Forms path.
45
+ - Opt-in drop-zone type validation with `data-validate-types`, native form
46
+ prevention and accessible error feedback. Extensions, exact MIME types and
47
+ standard media wildcards match whole selections without filtering files.
48
+ Browse and drop share validation; `expressive:reject` reports invalid choices.
49
+ Recovery preserves application validity and supports open shadow roots.
50
+ - File reset cleanup now follows native form ownership, including external
51
+ associated inputs, and runs after reset dispatch/default handling. Canceled
52
+ resets preserve current file state; newer selections retain their feedback.
53
+ - Server-owned data table paging through silent validated `DataTables.setPage`
54
+ state and cancelable `expressive:page` requests. Server responses retain
55
+ every supplied record without local slicing, filtering or sorting. Local
56
+ page and size controls now request before applying their default; cancel
57
+ to preserve the accepted view. Null state restores local paging.
58
+ - Authored single-select page-size controls for local data tables. Changing
59
+ size preserves an available page or clamps to the new last page, retaining
60
+ selections and matching counts.
61
+ - Local data table paging through a fixed `data-page-size` and authored
62
+ Previous/Next buttons. Paging follows filtering and sorting, keeps details
63
+ with records, scopes select-all to the displayed page and preserves
64
+ selections on other pages. Silent sync clamps the current page after row
65
+ changes. Ordinary pagination links retain their navigation behavior.
66
+ - Server-owned data table filtering through cancelable `expressive:filter`
67
+ requests with a trimmed, case-preserving query. Cancel synchronously to
68
+ preserve the current view, then replace records and call
69
+ `Expressive.DataTables.sync(wrapper)`. Sync stays silent and preserves the
70
+ application's server count; an uncanceled input resumes local filtering.
71
+ - Opt-in data table text filtering. A labelled search input with
72
+ `data-table-filter` searches columns whose headers have `data-filter`.
73
+ Record details stay together, author-hidden rows remain hidden, and an
74
+ authored status output can announce the result count. Select-all now
75
+ affects only enabled records visible in the current view; hidden records
76
+ retain their selections. To include hidden records in a bulk operation,
77
+ check them from script and call `Expressive.DataTables.sync(wrapper)`;
78
+ `expressive:change` continues reporting all selected records.
79
+ - Opt-in select filtering with `FormSelect`'s `searchable` option. A
80
+ separate popup search field filters grouped options while the native select
81
+ retains its form value. Includes localized search and no-results text,
82
+ keyboard navigation, query clearing on close and reset, and query-preserving
83
+ refresh. On a multiple select, picks keep the popup open with the query and
84
+ focus in place, and options the query hides stay selected and submitted.
85
+ Default, tree and browser-default selects keep their behavior.
86
+ - Autocomplete option groups. An entry's `group` lists it under a labelled
87
+ heading, and entries with the same group gather where the group first
88
+ appears. Up and Down pass over headings, the announced result count leaves
89
+ them out, and a click on one chooses nothing. Entries without a group keep
90
+ their behavior.
91
+ - Disabled Autocomplete entries. An entry with `disabled: true` stays in the
92
+ results, dimmed, and a click, Enter and `selectOption()` leave it
93
+ unselected, or selected when the `selected` option or
94
+ `setMenuItems(items, selected)` chose it. Up and Down skip it, and the
95
+ announced result count leaves it out. Entries without the flag keep their
96
+ behavior.
97
+ - Independent gap utilities. `.gap-x-0` through `.gap-x-6` set column gaps and
98
+ `.gap-y-0` through `.gap-y-6` set row gaps on the existing rem spacing scale.
99
+ Both support all four window-size prefixes and override the gap shorthand
100
+ at the same breakpoint. Existing gap utilities retain their behavior.
101
+ - Responsive child sizing. `.flex-1`, `.flex-none` and `.shrink-0` now take
102
+ window-size prefixes. New `.flex-initial` and `.shrink-1` classes restore
103
+ content sizing and shrinking, with the same four prefixes.
104
+ - Responsive self-alignment. `.self-start`, `.self-center`, `.self-end` and
105
+ `.self-stretch` take the `medium:`, `expanded:`, `large:` and
106
+ `extra-large:` prefixes, and the new `.self-auto` returns a child to its
107
+ parent's `align-items`. `self-center expanded:self-auto` centers a child
108
+ until Expanded and then follows the parent. The unprefixed classes are
109
+ unchanged.
110
+ - Responsive visual order. `.order-first`, `.order-last` and the new
111
+ `.order-none` (`order: 0`) take the `medium:`, `expanded:`, `large:` and
112
+ `extra-large:` prefixes. `order-last expanded:order-none` moves a child to
113
+ the end until Expanded and then back to its source position. The classes
114
+ change visual order only; Tab and reading order still follow the source.
115
+ - Show more. A `.show-more` holds text with a `line-clamp-1`, `-2` or
116
+ `-3` class and a `<button>`; the button shows the full text, reads
117
+ "Show less" while it is open (`i18n.showLess` or `data-show-less`) and
118
+ sets `aria-expanded` and `aria-controls`. The button hides while the
119
+ clamped text fits and comes back when a resize or a web font cuts it.
120
+ New semantics rules require a `<button type="button">` and clamped text.
121
+ - Treemap chart. A `<figure class="treemap-chart">` draws each row of its
122
+ table's first value column as a rectangle whose area is its share of the
123
+ total, filling the plot in a squarified layout from the largest value
124
+ down, mirrored in right-to-left pages. Each rectangle shows its name and
125
+ cell when they fit, and rows with no positive value draw nothing. The plot
126
+ is one Tab stop whose arrow keys step through the rectangles in table
127
+ order, the tooltip adds each row's share, and it takes `update()` and
128
+ `data-watch` like the other charts. A new semantics rule asks for a
129
+ `<figure>` with a `<table>` and a `<figcaption>`.
130
+ - Hover card. A link with `hover-card-trigger` names a `.popover` with
131
+ `popover="hint"` in `aria-details`, and once the pointer or keyboard
132
+ focus has rested on the link for 500 ms, that card shows against it.
133
+ The card stays while the pointer or focus is on the link or the card,
134
+ and hides 300 ms after both are left, or at once on Escape with focus
135
+ back on the link. A tap or click follows the link and shows no card.
136
+ Two new semantics rules keep the trigger an `<a href>` whose
137
+ `aria-details` names a `[popover]`.
138
+ - Transfer list. A `.transfer-list` holds a `.transfer-available` and a
139
+ `.transfer-chosen` list of checkbox rows with `data-transfer` buttons
140
+ between them. `add` and `remove` move the checked rows, `add-all` and
141
+ `remove-all` every row, and a row moved back returns to its original
142
+ place. The form submits the chosen rows' values under the container's
143
+ `data-name`, in the chosen list's order, and a form reset puts the rows
144
+ back. Each move fires `expressive:transfer` with `{ rows, from, to }`
145
+ and is announced through `TransferList.i18n.moved`. Four new semantics
146
+ rules ask for `data-name`, unnamed checkboxes, named lists and
147
+ `type="button"` on the move buttons.
148
+ - Funnel chart. A `<figure class="funnel-chart">` draws each table row as
149
+ a stage, from the top down in table order, centered and as wide as its
150
+ value against the largest one. The tooltip adds each stage's percentage
151
+ of the first row, and further columns show in the tooltip. The plot is
152
+ one Tab stop whose up and down arrows move between rows, and it takes
153
+ `update()`, where stages move from their old widths, and `data-watch`
154
+ like the other charts. A new semantics rule asks for a `<figure>` with a
155
+ `<table>` and a `<figcaption>`.
156
+ - Sankey chart. A `<figure class="sankey-chart">` draws each table row as
157
+ a flow: the first column names the source node, the second the target
158
+ node, and the third holds the value. Nodes stand in columns by their
159
+ longest path from a source and stack in the order they first appear.
160
+ Each link is as thick as its value, and each node as tall as the larger
161
+ of its in and out totals. Rows without a positive value or both names,
162
+ and rows that would close a cycle, draw nothing. The plot is one Tab
163
+ stop whose arrow keys step through the links in table order, and it
164
+ takes `update()` and `data-watch` like the other charts. A new
165
+ semantics rule asks for a `<figure>` with a `<table>` and a
166
+ `<figcaption>`.
167
+ - Loading overlay. While the page sets `aria-busy="true"` on a
168
+ `.loading-overlay`, a surface scrim covers it, its loading indicator
169
+ shows in the centre, and the script makes the region `inert`, so
170
+ nothing inside takes a click, a tap or keyboard focus. A visually
171
+ hidden status region after it announces the start and the finish, in
172
+ words set with `i18n`, and focus goes back to the control that had it
173
+ when the region clears. A new semantics rule asks for a direct
174
+ `.loading-indicator` child.
175
+ - `Dialogs.confirm()` asks a yes-or-no question in a basic alert dialog
176
+ and returns a promise that resolves `true` on the confirm button and
177
+ `false` on Cancel, Escape or a scrim tap. Focus starts on Cancel and
178
+ returns to the opener, and the dialog is removed once it closes.
179
+ `Dialogs.i18n` holds the default labels, "OK" and "Cancel".
180
+ - `.back-to-top` is an in-page link that appears once the window has
181
+ scrolled past `threshold`, one viewport height by default. Activating it
182
+ scrolls to the top, instantly under reduced motion, and focuses the
183
+ element its `href` names. The `BackToTop` component keeps it `inert`
184
+ while hidden and watches the threshold with an `IntersectionObserver`.
185
+ Without the script the link stays visible and jumps to its target. A
186
+ focused link stays until focus leaves, and modified clicks are left to
187
+ the browser.
188
+ - `.defer-render` makes the browser skip layout and paint for a long
189
+ list's off-screen rows through `content-visibility: auto`. Skipped rows
190
+ reserve `--defer-render-row-size`, the list item height by default, and
191
+ focus rings inside a deferred row are drawn inset so the row does not
192
+ clip them. Rows with swipe actions are left alone, and table rows are
193
+ not supported.
194
+ - Line clamp utilities. `.line-clamp-1`, `.line-clamp-2` and
195
+ `.line-clamp-3` cut text to that many lines and end the last one in an
196
+ ellipsis, and `.line-clamp-none` shows every line again. All four take
197
+ the `medium:`, `expanded:`, `large:` and `extra-large:` prefixes.
198
+ - Pointer helpers. `.pointer-events-none` lets clicks, taps and hovers
199
+ pass through an element to what lies beneath it, and
200
+ `.pointer-events-auto` gives them back to a child, such as a button in
201
+ a caption overlay. `.cursor-pointer` shows the pointer cursor and
202
+ changes nothing else. Neither pointer-events class affects focus or
203
+ keys; use `disabled` or `inert` to block all input.
204
+ - `.opacity-0`, `.opacity-25`, `.opacity-38`, `.opacity-50`, `.opacity-75`
205
+ and `.opacity-100` set an element's opacity. 38 is the M3 opacity for
206
+ disabled content.
207
+ - `.list-unstyled` removes a `<ul>` or `<ol>`'s markers and inline-start
208
+ padding and keeps its margins. A new semantics rule,
209
+ `list-unstyled-has-list-role`, flags one with no `role`, because WebKit
210
+ drops the list role from a list without markers. Add `role="list"`, or
211
+ the role the list should have.
212
+ - Position and inset helpers: `.position-absolute`, `.position-fixed` and
213
+ `.position-static`, `.inset-0`, and the edge pins `.top-0`, `.bottom-0`,
214
+ `.start-0` and `.end-0`. The start and end pins use logical properties, so
215
+ they swap sides in right-to-left pages. The classes take a `position-`
216
+ prefix because the navigation bar, toolbar and table of contents already
217
+ use `.fixed` as a modifier. They have no window-size prefixes, and
218
+ `.position-fixed` sets no `z-index`.
219
+ - `.grid-auto-fill` lays out as many columns as fit, each at least
220
+ `--grid-column-min` wide (15rem by default). Set the property on the grid or
221
+ an ancestor. A container narrower than the minimum gets one column, and the
222
+ last row keeps the column width. Pair it with `.gap-*`.
223
+ - Data table column resize. A `<button class="drag-handle">` ending a
224
+ header cell lets people resize its column by dragging, with the arrow
225
+ keys (16px, 64px with Shift), Home and End, or a click, Enter or Space
226
+ that steps through narrow, middle and wide. Each change fires
227
+ `expressive:resize` from the wrapper with `{ header, column, width }`,
228
+ and `DataTables.setWidth()` restores saved widths without firing it. The
229
+ new `--md-comp-data-table-column-min-width` token sets the narrowest
230
+ width.
231
+ - Data table column visibility. A menu checkbox item with `data-column`
232
+ set to a first-row header cell's `id` hides that column's header and
233
+ cells while it is unchecked, and an item unchecked at load starts its
234
+ column hidden. Cells that span several columns stay, and resized columns
235
+ keep their widths. `DataTables.sync()` applies the toggles for markup
236
+ rendered later. The framework stores nothing; save the choice from the
237
+ menu's `expressive:change`.
238
+ - `.sticky-column` on a `.data-table` keeps the first column in view while
239
+ the other columns scroll sideways, in both writing directions. When the
240
+ first column holds row checkboxes, the name cell after it stays pinned
241
+ too, and the checkbox column takes the width of the new
242
+ `--md-comp-data-table-checkbox-column-width` token. Pinned cells keep
243
+ their row's hover and selected colors, and a divider marks their edge.
244
+ - Calendar week, day and year views. `table.calendar.week` and
245
+ `table.calendar.day` are hourly grids: a row per hour named by a
246
+ `<th scope="row">`, and a column per day whose header can carry
247
+ `aria-current="date"`. An event sits in the cell for its day and
248
+ starting hour and covers one hour, or `--md-comp-calendar-event-duration`
249
+ hours, starting `--md-comp-calendar-event-start` hours into the row.
250
+ The placement is only visual, so write each event's time in a
251
+ `.visually-hidden` span. Events that overlap in time overlap on screen,
252
+ and an event past the last hour row spills out of the table. `.calendar-year` lays
253
+ out twelve month tables in as many columns as fit. The new
254
+ `--md-comp-calendar-hour-height` token sets the row height (48px).
255
+ - `AutoInit(context, options, { watch: true })` keeps watching the
256
+ context after the first scan. Components start in markup added later,
257
+ with the same options, markup options and `no-autoinit` opt-out, and
258
+ are destroyed when their markup is removed. Elements that already have
259
+ an instance keep it, moved elements keep theirs, and shadow roots are
260
+ watched only when passed as the context. The call returns a function
261
+ that stops watching. Without `watch`, `AutoInit()` behaves as before.
262
+ - Timepicker's `minTime` and `maxTime` options bound the times a person
263
+ can choose, as 24-hour `HH:MM` or `HH:MM:SS`. Dial ticks outside the
264
+ range are dimmed and refused, the fields stop stepping at the bounds and
265
+ refuse typed times outside them, and a value outside the range opens at
266
+ the nearest bound. On a 12-hour clock, a period with no allowed time has
267
+ its AM or PM button disabled. Ranges can't cross midnight. Without the
268
+ options every time stays open.
269
+ - Timepicker's `showSeconds` option adds a seconds field after the
270
+ minutes. It is a spin button named by the new `i18n.seconds`, it steps
271
+ and takes typed values like the minute field, and the picker writes
272
+ `HH:MM:SS`, with AM or PM on a 12-hour clock. The dial keeps its hours
273
+ and minutes views. A `type="time"` input needs `step="1"` to hold the
274
+ seconds without a step mismatch. The default of `false` keeps `HH:MM`.
275
+ - `AutoInit()` reads options from markup. An element's
276
+ `data-<name>-options` attribute holds a JSON object of that component's
277
+ options, with the name in kebab case: `data-menu-options`,
278
+ `data-form-select-options`. Options passed to `AutoInit()` win for the
279
+ keys they set. Values must match the kind of their default, so callbacks,
280
+ elements and `null`-default options stay script-only, as do
281
+ `allowUnsafeHTML` and the Chips and Autocomplete `data` lists. Invalid
282
+ values log a warning and keep their defaults. Direct `init()` calls do not
283
+ read the attribute.
284
+ - Tooltip's `openOnClick` option opens the tooltip on a click instead of
285
+ hover and focus. A second click, Escape, a click elsewhere or focus moving
286
+ to another element closes it, and Enter or Space on a button trigger
287
+ toggles it. On touch a tap is the click, so the long press is off. The
288
+ default of `false` keeps hover and focus.
289
+ - A chart's `update()` moves its marks from the old values to the new ones.
290
+ Line chart lines, areas and points, column chart columns, bar chart bars
291
+ and mixed chart marks move over `--md-sys-motion-duration-medium4` with
292
+ `--md-sys-motion-easing-standard`. A series or value new to the chart
293
+ rises from its base, and one that goes away goes at once. With reduced
294
+ motion the new shape appears at once. Migration: after `update()`,
295
+ columns and bars no longer grow again from zero, and lines no longer jump
296
+ to their new shape. No page change is needed.
297
+ - Autocomplete's `allowCreate` option ends the list in an `Add "text"` row
298
+ when the typed text matches no suggestion exactly, ignoring case and
299
+ surrounding spaces. Choosing it with Enter or a click calls `onCreate` with
300
+ the trimmed text and fires `expressive:create` with `{ text }`. The
301
+ selection does not change; the page adds the entry. `i18n.create` sets the
302
+ row's label. Chips add the text as a chip, in an `autocompleteOnly` field
303
+ too.
304
+ - When a search returns no suggestions, Autocomplete's open list shows
305
+ `i18n.noResults` as its first row, so sighted users see what the live
306
+ region announces. The row is `li.autocomplete-no-results` with
307
+ `role="none"` and `aria-hidden="true"`. Arrow keys skip it, and a click on
308
+ it chooses nothing and keeps focus in the field. It leaves the list when a
309
+ search returns a match. Arrow keys and Enter now move through
310
+ `li[role="option"]` rows only. In Chips, Enter that adds the typed text
311
+ as a chip now closes the list.
312
+ - A chart with `data-watch` on its figure, or the `watch` option, redraws
313
+ itself when its table changes, so page script no longer calls `update()`.
314
+ It watches added and removed rows and cells, cell text, and `data-value`,
315
+ `class` and the heatmap's `data-label` inside the table, and it follows a
316
+ replaced table. The edits a script makes in one run redraw it once. Every
317
+ chart type takes it, and `destroy()` stops it. Charts without it behave as
318
+ before.
319
+ - Autocomplete's `searchDelay` option waits that many milliseconds after
320
+ typing pauses before calling `onSearch`, so a remote search runs once per
321
+ pause instead of once per key. A text change aborts the running search's
322
+ signal right away. A search on focus runs at once, and blur, `destroy()`
323
+ or choosing a single result cancels a pending one. The default of `0`
324
+ keeps the search on every input. Chips take it through
325
+ `autocompleteOptions`.
326
+ - A menu item with `role="menuitemradio"` checks itself and unchecks the
327
+ other radio items in its group. A group is a `<ul role="group">` with an
328
+ `aria-label` inside an `<li role="none">`; radio items outside a group form
329
+ one group per menu. Rows in a group are styled and reached by arrow keys
330
+ and type-ahead like any other row. A click or Enter checks the item and
331
+ closes the menu while `closeOnClick` is on. Space now checks it and keeps
332
+ the menu open, where it used to close the menu. A change fires
333
+ `expressive:change` from the trigger with `{ item, checked: true }`, after
334
+ `onItemClick` and `expressive:select`; choosing the checked item fires no
335
+ change. Page code that synced `aria-checked` on radio items can go. It
336
+ writes the same values, so leaving it in place does no harm.
337
+ - A menu item with `role="menuitemcheckbox"` toggles its own
338
+ `aria-checked`. A click or Space flips it and keeps the menu open, so
339
+ several items can be toggled in a row; Enter flips it and closes the menu
340
+ while `closeOnClick` is on. Each toggle fires `expressive:change` from the
341
+ trigger with `{ item, checked }`, after `onItemClick` and
342
+ `expressive:select`. Migration: a page that flipped `aria-checked` itself
343
+ in `onItemClick` or a click listener must remove that code, or the two
344
+ flips cancel out.
345
+ - A `.validate` field sets `aria-invalid="true"` along with `invalid`, and
346
+ clears both once the value passes, so a screen reader hears the error
347
+ state the color shows. Its `[data-error]` supporting text joins the
348
+ input's `aria-describedby`, keeping the ids already there, so the error
349
+ message is read with the field. An empty `data-length` no longer marks a
350
+ field invalid.
351
+ - Tooltips show on a long press on touch, as Android does: after half a
352
+ second held, without `enterDelay`, staying for a second and a half after the finger lifts. A
353
+ tap used to show the tooltip through its compatibility mouse events and
354
+ leave it up until the next tap elsewhere; a tap now shows nothing, and a
355
+ press that turns into a scroll shows nothing. The click a long press's
356
+ release sends is consumed, so it does not press the button or follow the
357
+ link.
358
+ - Menus take `placement: 'top'` to open above the trigger when they fit
359
+ there, as for a trigger in a bottom bar, and Home and End jump to the
360
+ first and last rows. An anchored menu that does not fit below its trigger
361
+ now opens above it when there is more room there. Its height was capped
362
+ to the room below, so it shrank and scrolled instead of flipping.
363
+ - Chips submit a form value. Give the field's `<input>` a `name` and the
364
+ chips submit under it, one `id` per chip, as a multiple select does.
365
+ `init` wraps the input in `<expressive-chips-control>`, the framework's
366
+ first custom element. It is form-associated, has `display: contents` and
367
+ takes the name, so half-typed text is not submitted. The browser handles
368
+ the field's reset, validity and disabled state: a reset puts back the
369
+ starting chips within the reset, and a disabled fieldset drops the values
370
+ at once. Setting `disabled`, `readonly` or `form` on the input applies at
371
+ the next microtask. A `required` input makes the field valid once it has a
372
+ chip, and says the new `i18n.required` until then, with
373
+ `aria-required="true"` on the input. That validity is on the control,
374
+ apart from any error the page sets on the input. A read-only input's field
375
+ is not required. `destroy()` unwraps the input and gives its name and
376
+ `required` back. Without form-associated custom elements, as in jsdom, the
377
+ input keeps its name and `required` and submits its text. Pasting text
378
+ that lists values, split by commas, tabs or new lines, adds a chip for
379
+ each, up to `limit`.
380
+ - Data tables sort and select. With `data-sort` on a `.data-table`, a
381
+ button in a header cell reorders the rows by its column and moves
382
+ `aria-sort`. A `numeric` column compares numbers, other columns compare
383
+ text in the page's language, `data-value` stands in for a cell's text, and
384
+ a detail row moves with its row. A cancelable `expressive:sort` lets a
385
+ server-paged table sort the rows itself. A checkbox in the first header
386
+ cell now selects every enabled row and shows mixed for some, and each
387
+ change fires `expressive:change` with the selected rows.
388
+ `Expressive.DataTables.sync()` updates the select-all box after rows are
389
+ checked from script. Pages that sort with their own script and no
390
+ `data-sort` are unaffected.
391
+ - Charts with a series legend take `.toggle`. Each legend item becomes a
392
+ button with `aria-pressed` that shows or hides its series, and the scale
393
+ refits to the series left. The other series keep their colors, the last
394
+ one shown with data cannot be hidden, and a hidden series stays hidden
395
+ through `update()`. Line, column, bar, mixed and radar charts have it.
396
+ Without the class the legend stays decorative.
397
+ - The Auto Init page documents Alpine.js. A short `x-expressive` directive
398
+ starts a component each time Alpine renders its element, including inside
399
+ `x-if` and `x-for`, and destroys it when Alpine removes the element. The
400
+ page also shows how to keep a Select in sync with `x-model` by calling
401
+ `refresh()`. A browser test runs the directive against Alpine in Chromium,
402
+ Firefox and WebKit.
403
+ - Charts have `update()`, which redraws a chart from its changed table in
404
+ place. Before, the way to redraw was to call `init()` again, which dropped
405
+ keyboard focus and the highlighted row. Now focus stays on the chart, the
406
+ highlighted row stays where the table still has it, and a scrolled heatmap
407
+ stays scrolled. A chart set up with an empty table draws once it has rows.
408
+ - Tabs can be a tablist. A strip the page writes as `role="tablist"`, with
409
+ `role="tab"` links naming their panel in `aria-controls`, gets the ARIA
410
+ tabs pattern: Tabs keeps `aria-selected` and a roving `tabindex`, so the
411
+ strip is one Tab stop, and Left, Right, Home and End select as they move.
412
+ Link tabs with `aria-current` stay the default. `semantics.json` allows the
413
+ roles only when the markup is complete: named, on a `<div>`, every tab a
414
+ `role="tab"` with `aria-controls`. In either mode an overflowing bar
415
+ scrolls the selected tab into view, without scrolling the page, and with
416
+ no `.active` tab or matching hash the first enabled tab is selected rather
417
+ than a disabled first one.
418
+ - Scatter chart. A `<figure class="scatter-chart">` plots each table row
419
+ as one point per series: the second column holds the x value, and each
420
+ further column is a series of y values. `data-x-min` and `data-x-max`, or
421
+ the `xMin` and `xMax` options, fix the x scale, and `axis` labels both
422
+ scales. The plot is one Tab stop whose arrow keys step through the points
423
+ in table order, and it takes `update()`, `data-watch` and a `toggle`
424
+ legend like the other charts. A new semantics rule asks for a `<figure>`
425
+ with a `<table>` and a `<figcaption>`.
426
+ - Bubble sizes on the scatter chart. With `bubble`, the last column sizes
427
+ each row's points, so their areas follow its values, and the largest is
428
+ `--md-comp-scatter-chart-bubble-size` (48px) across. A row without a
429
+ positive size draws no points. The tooltip names the size, a `toggle`
430
+ legend refits the sizes, and bubbles grow or shrink from their old sizes
431
+ after `update()`. Room around the plot keeps a bubble at the end of a
432
+ scale clear of the axis labels and legend.
433
+ - Pull-to-refresh. A touch pull down from the top of a `.pull-to-refresh`
434
+ container, or its `<button data-refresh>`, fires `expressive:refresh` and
435
+ shows the container's loading indicator with `aria-busy="true"` until
436
+ every promise passed to `event.detail.waitUntil()` settles or the page
437
+ calls `complete()`. The `threshold` option sets the pull distance (64px).
438
+ A visually hidden status region announces the start and the finish, in
439
+ words set with `i18n`. The container and the page holding it get
440
+ `overscroll-behavior-y: contain`, so the browser's own pull-to-refresh
441
+ stops. New semantics rules
442
+ ask for the button and a direct `.loading-indicator` child.
443
+ - Swipe actions. In a `.list.swipeable`, a touch swipe toward a row's
444
+ inline start slides it and reveals its `.swipe-actions` buttons. A swipe
445
+ only reveals; nothing runs until a person presses an action. The row's
446
+ `<button data-swipe-toggle>` opens and closes it without a swipe, focus
447
+ on an action opens its row, and Escape, a tap outside or an action closes
448
+ it. One row is open at a time. Each change fires `expressive:swipetoggle`
449
+ with `{ row, open }` and runs `onToggle`; `open(row)` and `close()` work
450
+ from script. A new semantics rule asks for the toggle in every row with
451
+ actions.
452
+ - Input mask. A text field with `data-mask` formats what people type,
453
+ paste or compose to the pattern: `0` takes a digit, `a` a letter, `*`
454
+ either, and other characters are literals the mask writes, such as
455
+ `(000) 000-0000`. The caret stays after the edit, Backspace and Delete
456
+ remove the digit across a literal, an IME composition is formatted once
457
+ it ends, and saved and reset values are formatted too. The form submits
458
+ the value as shown. A new semantics rule keeps `data-mask` on input types
459
+ that have a caret.
460
+ - Currency input. A text field with `data-currency="EUR"` shows its
461
+ amount in the page's locale and that currency once it loses focus, such
462
+ as `1.234,50 €` under `lang="de"`, and the plain number `1234,5` while
463
+ it has focus. The last `.` or `,` is the decimal mark when no more than
464
+ the currency's fraction digits follow it, so `1234.5` and `1.234,5` read
465
+ the same. The form data holds the plain number, `1234.5`. Text with no
466
+ digit stays as typed and marks the field invalid, with a message `i18n`
467
+ can replace. The instance's `value` returns the number. A new semantics
468
+ rule keeps `data-currency` on text inputs.
469
+ - Cascader. A `.field.cascader` with a named text input and nested
470
+ `ul.cascader-options` lists shows the options as columns in a popover,
471
+ where each choice opens the next column. Arrow keys, Home, End, Enter,
472
+ Space, Escape and Tab move through the columns, swapped under `rtl`.
473
+ Choosing a leaf shows the path in the input and fires `input` and
474
+ `change`, and the form gets one entry per level, such as `place=us`,
475
+ `place=ca`, `place=sf`, through a form-associated control. `data-selected`
476
+ on a leaf sets the starting path, which a reset brings back, and
477
+ `required` blocks submit until a path is chosen. New semantics rules keep
478
+ the source lists plain and every option valued.
479
+ - Tree select. A `<select data-tree>` whose options name their parent's
480
+ value in `data-parent` opens an ARIA tree, where the arrows, Home, End,
481
+ `*` and typeahead move between visible rows and only a leaf can be
482
+ chosen. The native select keeps the form value, reset and validity, and
483
+ branch options are disabled while it runs, so the form never submits
484
+ one. `refresh()` keeps open branches and focus. AutoInit starts
485
+ `TreeSelect` on `select[data-tree]` and FormSelect on other selects, and
486
+ a new semantics rule keeps `data-tree` on single selects nested only
487
+ through `data-parent`.
488
+
489
+ - A `data-draggable` map marker moves without a drag (WCAG 2.5.7). A tap
490
+ picks it up and sets `aria-pressed`, and the next tap on the map drops it
491
+ there. `Escape` or a second tap puts it back, and the arrow keys nudge a
492
+ focused one. A marker that is not a `<button>` gets `role="button"` and
493
+ `tabindex="0"` while the map runs.
494
+ - Map controls take `pan-up`, `pan-down`, `pan-left` and `pan-right` actions,
495
+ which move the view a third of the map's size, so it pans without a drag.
496
+
497
+ - Menu, Lightbox, NavigationRail, Cards and ExpandingCard fire
498
+ `expressive:open` and `expressive:close` DOM events from the element
499
+ they were initialized on. Menu, Lightbox and NavigationRail then fire
500
+ `expressive:opened` and `expressive:closed`. The events bubble and cross
501
+ shadow roots, and each follows its `on…` callback, which still works.
502
+
503
+ - Choices and changes fire events too, with what was chosen in `detail`:
504
+ `expressive:change` from Tabs (`{ panel }`) and Carousel
505
+ (`{ item, dragged }`), `expressive:select` from Menu items (`{ item }`),
506
+ Datepicker (`{ date }`) and Timepicker (`{ hours, minutes }`),
507
+ `expressive:confirm` and `expressive:cancel` from both pickers,
508
+ `expressive:autocomplete` (`{ values }`), and `expressive:chip-add`,
509
+ `chip-select` and `chip-delete` (`{ chip }`). A callback that changes the
510
+ choice again leaves only the event for the final one. Tabs now calls
511
+ `onShow` after hiding the old panel, and Chips callbacks get the instance
512
+ as `this`, as every other component's do.
513
+
514
+ - The rest report too: Tooltip fires `expressive:open` and
515
+ `expressive:close` when it shows and hides; Snackbar fires `open`,
516
+ `action`, `close` and `closed`; ButtonGroup fires `change` with
517
+ `{ button, pressed }`; ScrollSpy fires `change` from the section with
518
+ `{ link }`; Tour fires `open`, `change` with `{ step, index }` and `close`
519
+ with `{ completed }`; and copy buttons fire `expressive:copy` with
520
+ `{ text, copied }`. `Tour.end(el, completed)` takes the flag from script.
521
+
522
+ - Sheets spring back with the finger's speed: a bottom or side sheet
523
+ released short of dismissing solves its spring at run time from where
524
+ it is and how fast it moves, and a press while it springs catches it in
525
+ place. Each motion spring gains `-damping` and `-stiffness` tokens.
526
+
527
+ - Arabic, Hebrew and Thai text: Noto Sans Arabic, Noto Sans Hebrew and
528
+ Noto Sans Thai ship at 400, 500 and 700, each limited to its script's
529
+ `unicode-range` so a page fetches one only when it shows that script,
530
+ and `--md-ref-typeface-fallback` lists them before `sans-serif`.
531
+
532
+ - Autocomplete `onSearch` gets an `AbortSignal` as its third argument. It
533
+ aborts when a newer search starts or the autocomplete is destroyed, so a
534
+ page that passes it to `fetch()` drops stale responses.
535
+
536
+ - Linear progress `.stop` puts a dot in the indicator colour at the
537
+ track's end, and `.wavy` draws the indicator as a wave over a thin track,
538
+ on `<progress>`, `.determinate` and bare bars, and a circular indicator
539
+ takes `.wavy` too: a wave round the ring over a thin track. New tokens:
540
+ `--md-comp-progress-stop-size` and `--md-comp-progress-wavelength`.
541
+
542
+ - Common button shapes: `square` takes the size's squared corner, every
543
+ common button morphs to its size's pressed corner while pressed, and
544
+ `aria-pressed` makes a button a toggle that swaps round and square when
545
+ selected and takes the M3 selected colours for its style.
546
+
547
+ - Questionnaire extras, each opt-in on the form: `data-shortcuts` lets a
548
+ letter or digit pick an answer, `data-summary` adds a review step that
549
+ lists every answer with an Edit button before submitting, and
550
+ `data-save="key"` keeps the answers and the shown question in
551
+ localStorage until the form is submitted.
552
+
553
+ - Keypad and keyboard keys: `data-key="CapsLock"` holds capitals until
554
+ pressed again, and `data-key="Layer"` shows the elements whose
555
+ `data-layer` matches its `value`, such as a row of symbols. A hardware
556
+ key held down in the field presses the matching on-screen key. The
557
+ keypad now checks `minlength` on its own edits, with the
558
+ `i18n.tooShort` message.
559
+
560
+ - Radial chart fills: `data-segments` splits each ring into segments filled
561
+ whole, and `.gradient` shades each fill along its ring, from a light
562
+ tint at the start to its full color where the fill ends.
563
+
564
+ - Range columns and bars: a series header with the class `range` reads
565
+ cells such as `120–480`, `3 to 14` or `data-value="120 480"` and floats a
566
+ column or bar between the two ends, rounded at both.
567
+
568
+ - Mixed chart stacking: `.stacked` stacks the column series into one
569
+ column per row, with the `end` scale's columns in their own column
570
+ beside it. Lines and areas keep their own values.
571
+ - Line and mixed chart `.points` marks every value on a line with a dot,
572
+ and `.straight` draws straight lines between values instead of a curve.
573
+
574
+ - Heatmap scales: `data-mid` makes the scale diverge from that value, with
575
+ values below it shading towards the new
576
+ `--md-comp-heatmap-chart-low-color` (`tertiary`), and `data-steps` groups
577
+ the shades into bands, with a swatch per band under the grid.
578
+ - Wide heatmaps scroll: cells keep `--md-comp-heatmap-chart-cell-min-width`
579
+ (12px), and a grid too wide for its figure scrolls its cells sideways
580
+ instead of narrowing them, while the row labels stay in view. The arrow
581
+ keys scroll the cell they move to into view.
582
+
583
+ - Pie chart grouping: `data-other="5"` turns every row under 5% of the
584
+ whole into one last slice with their sum and share, named by
585
+ `data-other-label` ("Other" by default). The table keeps every row.
586
+ - Radial chart names: `.labels` draws the rings three quarters of the way
587
+ round and writes each row's name in the empty top left quarter, beside
588
+ its ring's start. Names shrink to fit crowded rings. On a gauge, the names
589
+ hang under the base line, a row per ring with the innermost on top, each
590
+ after a line down from its ring's start. A sparkline ignores it.
591
+ - Pie chart names: `.labels` writes each slice's row name outside the pie,
592
+ beside its slice. Names that would touch move apart along their side, a
593
+ line leads from each name back to its slice, and the pie shrinks to leave `--md-comp-pie-chart-label-width` (96px), or a
594
+ quarter of a narrow figure, on each side.
595
+ - Expandable bottom sheets: `dialog.bottom-sheet.expandable` opens at
596
+ `--md-comp-bottom-sheet-partial-height` (50% of the viewport) and
597
+ `.expanded` grows it to the full height. A drag up expands it, a drag
598
+ down collapses it before it dismisses, and a handle `<button>` switches
599
+ between the heights with `aria-expanded` kept current.
600
+ - Arrow keys for tabs and lists: Left, Right, Home and End move focus
601
+ between tabs, wrapping and skipping disabled ones, and Up, Down, Home and
602
+ End move it between the rows of a `.list` whose rows are each one link or
603
+ button. Tabs and rows stay links and Tab stops; focus moves without
604
+ choosing. The list keys come from the new `Lists` behavior.
605
+ - Modal date and time pickers: `displayPlugin: 'modal'` opens the picker in
606
+ a modal `<dialog class="display-modal">` drawn as a basic dialog, named by
607
+ the input's label. Ok writes the input; Cancel, Escape and a press on the
608
+ scrim close it without a change and call `onCancel`. Focus moves into the
609
+ dialog and back to the input. Selective Sass builds add `"dialog"` and
610
+ `"modal-display"`.
611
+ - Value axes for charts: `.axis` on a line, column, bar or mixed chart
612
+ labels its value scale at round values, with a grid line at each, and
613
+ widens an end the chart chose to the next round value. The labels repeat
614
+ the cells' currency or percent sign and shorten large numbers. A mixed
615
+ chart labels its `end` scale on the far side and stretches it so both
616
+ label sets share the grid lines. On a radar chart, `.axis` rings the grid
617
+ at round values and labels the rings.
618
+ - Non-Latin text faces: Roboto and Noto Sans now ship Latin Extended,
619
+ Cyrillic, Cyrillic Extended, Greek, Greek Extended and Vietnamese subsets,
620
+ and Noto Sans adds Devanagari, at 400, 500 and 700. Each face has a
621
+ `unicode-range`, so a browser downloads only the scripts a page renders.
622
+ - Cut corners: `--md-sys-shape-corner-family` (`round` or `bevel`), a
623
+ `corners="cut"` switch that cuts the corners of cards, dialogs, sheets,
624
+ menus, fieldsets, buttons, chips, alerts, snackbars, tooltips, popovers and
625
+ outlined fields, and a `.corner-cut` utility. Built on CSS `corner-shape`;
626
+ browsers without it keep rounded corners.
627
+ - Spring motion tokens from Material 3 Expressive:
628
+ `--md-sys-motion-spring-{fast,default,slow}-{spatial,effects}` with a
629
+ `-duration` token each, solved at compile time into `linear()` easings.
630
+ `motion="expressive"` on the root or a subtree selects the expressive
631
+ spatial springs. The Sass `spring($damping, $stiffness)` and
632
+ `spring-duration()` functions build custom ones.
633
+ - Emphasized type roles from Material 3 Expressive: `.{role}-emphasized`
634
+ classes for all fifteen roles and
635
+ `--md-sys-typescale-emphasized-{role}-font-weight` tokens, at `500` for
636
+ display, headline, title-large and body and `700` for title-medium,
637
+ title-small and label. Roboto and Noto Sans now ship a `700` face, fetched
638
+ only when a page renders that weight.
639
+ - A "Design tokens" documentation page at `/tokens.html` lists every token
640
+ family, its prefix and the page that documents it, with an override
641
+ example.
642
+ - Material 3 motion tokens: `--md-sys-motion-easing-*` for the standard,
643
+ emphasized and linear curves and `--md-sys-motion-duration-short1` to
644
+ `extra-long4`. Components now read them wherever they used an on-scale
645
+ curve or time, so `:root { --md-sys-motion-duration-short4: 150ms; }`
646
+ speeds up every 200ms transition. Computed values are unchanged.
647
+ - Material 3 corner tokens: `--md-sys-shape-corner-none` to `full`, with the
648
+ Expressive `large-increased`, `extra-large-increased` and
649
+ `extra-extra-large` steps. Component shape tokens on the scale read them,
650
+ so `:root { --md-sys-shape-corner-medium: 8px; }` squares off every medium
651
+ corner. Computed values are unchanged.
652
+ - Elevation tokens: `--md-sys-elevation-level0` to `level5` and
653
+ `level1-half`, generated from the `$elevations` map. The `z-depth()`
654
+ mixin, the `.z-depth-*` classes and every component read them, so a theme
655
+ can change a shadow level at runtime. Computed values are unchanged.
656
+ - `--expressive-z-*` properties name the stacking order of fixed and floating
657
+ surfaces, from `toolbar` (996) to `confetti` (10001). Components read them
658
+ instead of literal `z-index` values, and the Shadow page lists them.
659
+ - Layout helpers take a window-size prefix: `.medium:`, `.expanded:`,
660
+ `.large:` and `.extra-large:` versions of the display, flex direction and
661
+ wrap, `justify-*`, `align-*`, text alignment, `.gap-*`, margin and padding
662
+ classes, and `.hide`, apply from that size class up, so
663
+ `flex flex-column expanded:flex-row` stacks until Expanded.
664
+ - More helpers: `.block`, `.inline-block`, `.grid`, `.inline-grid`,
665
+ `.contents`, `.relative`, `.sticky-top`, `.flex-row`, `.flex-nowrap`,
666
+ `.justify-around`, `.justify-evenly`, `.align-baseline`, `.self-*`,
667
+ `.order-first`, `.order-last`, `.shrink-0`, `.w-full`, `.h-full`,
668
+ `.max-w-full`, `.aspect-1x1`, `.aspect-4x3`, `.aspect-16x9`,
669
+ `.object-cover`, `.object-contain`, `.bordered`, `.border-top`,
670
+ `.border-bottom`, `.border-start`, `.border-end`, `.corner-none` to
671
+ `.corner-full`, `.text-balance` and `.text-pretty`.
672
+ - Print styles. Paper uses the light scheme and hides navigation rails,
673
+ navigation bars, the FAB menu, snackbars and tooltips. External links in running text print their address, headings
674
+ stay with what follows, and table headers repeat on each page.
675
+ `.hide-on-print` and `.print-only` cover the rest.
676
+ - `.prose` styles a container of bare HTML, such as rendered Markdown: a
677
+ 70-character measure, heading and list spacing, underlined links in lists
678
+ and headings, and a surface for inline code and `<pre>`. It only touches
679
+ elements without a class and sits in the base layer, so components inside
680
+ it keep their own look.
681
+ - `.query-container` makes an element a query container. Horizontal cards
682
+ and description lists inside one stack when it is narrower than 600px, so
683
+ they adapt to a sidebar or pane on a wide window.
684
+ - Contrast levels: `contrast="medium"` and `contrast="high"` on the root or
685
+ a subtree select M3's medium and high contrast schemes. Accents, their
686
+ containers, `on-surface-variant` and outlines move to tones that reach
687
+ about 4.5:1 and 7:1 against the surface. `prefers-contrast: more` applies
688
+ the high scheme unless a `contrast` attribute is set, and
689
+ `contrast="standard"` opts out.
690
+ - Color swatches component: a `fieldset.color-swatches` of radios in
691
+ labels with visually hidden names, each drawn as a round chip of the color
692
+ set in `--md-comp-color-swatch-color`, with a ring around the checked one.
693
+ An `<input type="color">` at the end adds a custom value. CSS only.
694
+ - Number stepper: two trailing `.icon-button.suffix` buttons with
695
+ `data-step="down"` and `data-step="up"` in a `.field` step its
696
+ `<input type="number">` within `min`, `max` and `step`, and fire `input`
697
+ and `change`. The browser's spin buttons are hidden. The Forms behavior
698
+ handles it, so there is nothing to initialize.
699
+ - Color picker component: `ColorPicker` enhances a `.color-picker` around an
700
+ `<input type="color">` with a saturation and brightness area, the
701
+ framework's slider as a hue control, and a hex field. The native input stays
702
+ the form value and fires `input` and `change`. The area is a keyboard
703
+ slider with a spoken value. AutoInit starts it.
704
+ - A "Frosted glass" documentation page at `/glass.html` covers the
705
+ `--expressive-glass`, `-blur` and `-opacity` properties, the Sass defaults,
706
+ the surfaces that frost, and the reduced-transparency fallback, with live
707
+ demos. A button in the docs app bar turns glass on across the site.
708
+ - A navigation rail destination can open a `.navigation-rail-panel` side
709
+ panel of more links. Make the destination a `<button popovertarget>` and
710
+ put the panel popover right after it. The panel docks beside the rail at
711
+ full height, a click toggles it, and with a mouse hovering the destination
712
+ opens it. `<details>` groups inside the panel are its dropdowns.
713
+ - `.org-chart` draws a reporting line top down, with each person as a card
714
+ under their manager. Write nested lists; a manager's card is the
715
+ `<summary>` of a `<details>` that folds the team away. Cards take an
716
+ `.org-chart-role` band, an `.avatar` and an `.org-chart-name`. A wide
717
+ chart scrolls sideways. CSS only.
718
+ - The `expressivecss-migration` agent skill moves a project from Materialize
719
+ or an older 0.x release to current names in eight steps: package and
720
+ assets, JavaScript API, removed components, classes and markup, the aliases
721
+ 0.16.0 removes, silent visual changes, and verification. Each step ends with a
722
+ search for the names it replaces, and the skill installs on its own with
723
+ `npx skills add BaezFJ/ExpressiveCSS`.
724
+ - An "AI agents" documentation page at `/ai.html` lists the plain-text docs,
725
+ the install command for the agent skills, the MCP server configuration and
726
+ the `expressivecss-lint` command. Its skills table is read from each
727
+ `skills/<name>/SKILL.md`, so a new skill appears without editing the page.
728
+ - Menubar component: a `.menubar` of `.menu-trigger` buttons gets the menubar
729
+ and menuitem roles, one Tab stop, Left, Right, Home and End along the bar,
730
+ and Left and Right between open menus. Each item opens an ordinary Menu.
731
+ AutoInit starts it.
732
+ - Mega menu component: a `nav.mega-menu` of links and buttons whose
733
+ `.mega-menu-panel` popovers open wide panels of grouped links below the bar.
734
+ CSS only, on native popovers.
735
+ - Tour component: a `.tour` manual popover walks through `<section>` steps
736
+ beside each `data-tour-target`, with Back, Next, Done, progress text,
737
+ skipped missing targets, Escape and focus return. `Expressive.Tour` adds
738
+ `start()`, `go()` and `end()`.
739
+ - Image compare component: a `.image-compare` reveals its second image up to
740
+ a native range input's value. The `ImageCompare` behavior moves the
741
+ divider, and Slider no longer initializes that range.
742
+ - Calendar component: a page-rendered `table.calendar` draws a month grid
743
+ with weekday headers, today, outside days and event chips. CSS only.
744
+ - Sortable lists: a `.sortable` list reorders by dragging an item's
745
+ `.drag-handle` or with its `[data-move]` buttons, announces each move and
746
+ fires `change` with `{ item, from, to }`. Semantics require the buttons.
747
+ - `<input type="color">` is drawn as a round swatch of its color.
748
+ - Description list component: `dl.description-list` lays out label and value
749
+ pairs in two columns with a divider per pair, stacking each label above its
750
+ value at Compact widths. CSS only.
751
+ - Error summary: an `.error-summary` alert in a `novalidate` form stops an
752
+ invalid submit, lists one link per invalid field with its label and the
753
+ browser's message, and takes focus. Each link focuses its field. Part of
754
+ the Forms behavior.
755
+ - Resizable panes: a `<button class="drag-handle">` between the two panes of
756
+ a list-detail or supporting layout resizes them by drag, arrow keys, Home
757
+ and End, or a click that steps through narrow, middle and wide. The
758
+ `PaneResize` behavior writes `--md-comp-pane-list-width` or
759
+ `--md-comp-pane-supporting-width`.
760
+ - Data table bulk actions and row expansion: a `.data-table-actions` bar
761
+ joins the table's top edge and takes the selected color while rows are
762
+ selected, and a `tr.data-table-detail` shows while the row before it holds
763
+ a button with `aria-expanded="true"`. CSS only; the page flips the state.
764
+ - Alert component: `.alert` is a persistent message in the page flow with an
765
+ optional leading icon, a heading and text, an `.alert-actions` row and a
766
+ close button. `critical` switches to the error container colors. CSS only.
767
+ It replaces the banner as the answer for persistent, nonblocking messages,
768
+ and the banner migration page now points to it.
769
+ - `<meter>` gets an 8px bar on a `secondary-container` track. The fill is
770
+ `primary` in the optimum region, `tertiary` one region away and `error` two
771
+ away, from the native `low`, `high` and `optimum` attributes. No class is
772
+ needed, so existing meters change appearance and fill their container's
773
+ width; set `width` on a meter to keep it inline.
774
+ - Copy buttons: `data-copy-for="id"` copies a field's value or an element's
775
+ text, and `data-copy="text"` copies the text itself. A snackbar confirms the
776
+ result. `Expressive.Copy.i18n` and `data-copy-message` / `data-copy-error`
777
+ replace its texts.
778
+ - Theme switch: `data-theme-set="light|dark|auto"` on any control writes the
779
+ `theme` attribute, saves the choice to `localStorage` and marks the current
780
+ control with `aria-pressed` or `aria-checked`. `Expressive.Theme` adds
781
+ `set()`, `get()` and `sync()`. Restoring a saved choice before first paint
782
+ stays with the page's inline script.
783
+
784
+ ### Fixed
785
+
786
+ - Nonsearch TreeSelect opening now honors Menu `autoFocus: false` and preserves
787
+ focus already moved to a tree row before its opening animation completes.
788
+
789
+ - Searchable tree rows inherit the shared menu tokens, preserving visible
790
+ keyboard focus, selected colors and row spacing in light and dark themes.
791
+ - Search popups resize after filtering so translated no-results feedback and
792
+ newly exposed tree paths fit, including inside transformed containers.
793
+ - Search popups stay hidden for controls initialized while disabled. Enabling
794
+ the control and calling `refresh()` restores normal interaction.
795
+ - Searchable selects preserve focus on a result reached before the opening
796
+ animation finishes, so Enter still chooses that result in dialogs and shadow roots.
797
+ - Escape dismisses an anchored menu while its opening animation still leaves
798
+ focus on the trigger, including a searchable select reopened from the keyboard.
799
+ A closed menu leaves Escape available to its surrounding dialog or page.
800
+ - Navbar form inputs and card media captions use their complete body-large
801
+ and title-medium type roles, including letter-spacing. Existing captions
802
+ now use title-medium tracking, which can change their text width or wrapping.
803
+ - The Timepicker canvas fade reads `--md-sys-motion-duration-short3`, changing
804
+ its default from 175ms to 150ms. Expanded card content reads the new
805
+ `--md-comp-expanding-card-content-delay` property, backed by
806
+ `--md-sys-motion-duration-short4`, changing its default delay from 180ms to
807
+ 200ms. Both follow token overrides and keep their reduced-motion resets.
808
+ Timepicker's JavaScript timers and `duration` option are unchanged.
809
+ - The map popup's shadow reads `--md-sys-elevation-level2`, so a theme
810
+ that changes that token changes the popup too. The shadow was written
811
+ out in full, so the popup kept the default level 2 shadow while menus
812
+ and cards followed the theme. It still overrides MapLibre's own shadow.
813
+ - Chips grow with the browser's font size. Labels read the label-large
814
+ font-size token, and the icon, minimum height, avatar, close-button box
815
+ and editable input use rem sizes. At a 32px root, the default label is
816
+ 28px and minimum height is 64px. Default rendering at a 16px root,
817
+ px spacing and existing custom-property overrides remain unchanged.
818
+ - Icons grow with the browser's font size in dialogs, snackbars, alerts,
819
+ lists, trees, timelines, the command palette, message avatars, the map
820
+ popup, fieldset legends, the drop zone and the dialog, side sheet and
821
+ pane header actions. Their sizes were in px, so the text beside
822
+ them grew and the icons didn't. Icon boxes in the same rules grow with
823
+ them, and the timeline text and the map popup text clear the larger
824
+ badge and close button. A short timeline event stays tall enough that
825
+ its badge doesn't overlap the next one. The Timepicker's tick text grows too; its dial
826
+ and ticks stay in px because the script places ticks in px. At the
827
+ default 16px size nothing moves.
828
+ - A single-line list row sits in the middle of the row. The row grid's
829
+ empty second line stretched, so the text sat 4px above its leading icon
830
+ in most rows. A checkbox or radio label row also took the control's
831
+ 12px row gap and sat 7px high. In a row taller than its text, the
832
+ headline and its supporting text now sit together in the middle instead
833
+ of being pushed apart. A checked checkbox in a label row shows its
834
+ checkmark on the box, not 16px before it.
835
+ - A table cell with the `hidden` attribute is hidden. The global `td, th`
836
+ rule set `display: table-cell`, which overrode the browser's
837
+ `[hidden]` rule.
838
+ - Security: Autocomplete with `allowUnsafeHTML` renders only a script-supplied
839
+ `text` as HTML. A `selected` id that has no data entry, which
840
+ `data-autocomplete-options` can set, used to become HTML too, so sanitized
841
+ user markup that kept the component's class and options attribute could
842
+ run script once the menu showed no results.
843
+ - Security: a questionnaire with `data-save` no longer stores password or
844
+ hidden inputs. It used to keep a password in `localStorage` as plain text
845
+ until submit, and to restore both into the next visitor's form, which
846
+ replaced the server's hidden values. Saved progress from an earlier
847
+ version no longer matches and starts fresh.
848
+ - A docked date or time picker, and a tooltip placed without CSS anchor
849
+ positioning, stay beside their trigger on a page scrolled sideways and
850
+ inside the body's margin. They used to be kept inside the body's box,
851
+ which scrolls with the page, so a picker that fit the viewport could jump
852
+ to its right edge. They are now kept inside the viewport only, and a
853
+ docked picker with an `align` other than `left`, `center` or `right` is
854
+ kept in view like a left-aligned one.
855
+ - `@use "expressive" with ($text-color: …)` colors the page text. The
856
+ variable was written on `html`, where the `body` rule's own on-surface
857
+ color covered it, so it only took effect inside a shadow root. `body`
858
+ and `:host` now take their color from `$text-color`. The default is
859
+ unchanged.
860
+ - MCP static inspection checks the `require-idref` and
861
+ `require-owned-descendant` rules from `semantics.json`. The server kept
862
+ its own copy of the rule helpers, which had drifted and skipped both, so
863
+ markup that passed before can now get findings. It now imports the same
864
+ rule module the repo's semantics checks use.
865
+ - Timepicker reads AM or PM wherever it appears in a value, so
866
+ `02:30:45 PM` opens at 2:30 PM. The period was looked for only after the
867
+ first colon, so such a value, or one like `2 PM`, opened as AM.
868
+ - With a query typed, the first Escape in the command palette clears it and
869
+ the next closes the palette, in every engine. Chromium and Firefox already
870
+ did this for a search input; WebKit closed at once, and so did every
871
+ engine for a text input. An Escape that cancels an IME composition is left
872
+ to the IME.
873
+ - In forced colors, a filled keypad key such as Call has a 3px edge. The
874
+ fill that set it apart is dropped there, so it looked like every digit.
875
+ - In forced colors, a determinate circular progress draws its track as a
876
+ thin line through the ring, so the value and the track differ in shape.
877
+ Both were full-width rings, told apart only by GrayText against
878
+ CanvasText, which Night sky sets close together.
879
+ - A narrow heatmap shows whole column labels. Like the line, column and
880
+ mixed charts, it keeps every second label (or every third, and so on)
881
+ when each is wider than its column, instead of cutting all of them to
882
+ "W…". Labels the author already spaced out with empty `data-label`
883
+ cells, such as a year of weeks named once a month, are left as written.
884
+ The labels are now measured where they sit, so the columns' gaps and
885
+ right-to-left grids are counted.
886
+ - Pie slices 5 and 6 stand out from the surface. They took
887
+ `primary-container` and `tertiary-container`, which are 1.3:1 on the
888
+ surface in light mode and 2:1 in dark, under the 3:1 a slice needs. Each is
889
+ now its container role mixed 45% with `on-surface`: the same hue, at 5:1
890
+ in light and 6.8:1 in dark. `.values` text on them is `surface`. A page
891
+ that sets `--md-comp-pie-chart-color-5` or `-6` keeps its own colors.
892
+ - In forced colors, an invalid checkbox has a dashed edge. Forced colors
893
+ drop the error color, so it looked like any other box. A checked invalid
894
+ box used to paint the author's error red and on-error mark, because the
895
+ error rules outranked the forced-colors ones; it now takes Highlight and
896
+ HighlightText like any checked box, and a disabled one stays GrayText.
897
+ - Chart cards in the docs keep their contents off the border, and the
898
+ period switch sits beside the stat instead of on a row of its own. The
899
+ column chart page now says a card needs `p-4` around its stat and chart,
900
+ as the line chart page already did.
901
+ - A narrow line, column or mixed chart shows whole row labels. When each
902
+ label is wider than its column, the chart keeps every second label (or
903
+ every third, and so on) and hides the rest, rather than cutting all of
904
+ them to "J…". Twelve months on a 320px phone show as six. The chart
905
+ re-checks as it resizes, and the full text stays in the tooltip and the
906
+ table.
907
+ - A top app bar whose destinations do not fit beside the title wraps them
908
+ onto a second row. Before, the title shrank to one letter and an
909
+ ellipsis. On one row the bar is unchanged.
910
+ - In WebKit, the keyboard can scroll a docs code sample that is wider than
911
+ its block. Chromium and Firefox already put such a block in the Tab
912
+ order; WebKit skipped it.
913
+ - The Carousel page shows the Show all action it recommends, opening a
914
+ full-screen dialog of the same items. It is the single-pointer way
915
+ through a carousel (WCAG 2.5.7), and no demo had it.
916
+ - The Enter that confirms an IME candidate no longer acts on a field. In
917
+ the date picker it moved focus into the calendar and read the unfinished
918
+ text; the time picker, the autocomplete's active option and the color
919
+ picker's hex field also took it. The date picker, time picker and
920
+ autocomplete now skip every key of a composition, so the arrows and
921
+ Escape used to pick a candidate leave them alone too.
922
+ `Utils.isComposing(e)` checks `isComposing` and Safari's keyCode 229, and
923
+ Chips, Command palette, Menu and Questionnaire now share it, so Menu and
924
+ Questionnaire also skip Safari's confirming Enter.
925
+ - A keyboard-focused slider handle takes the shared 3px focus ring. Its only
926
+ cue was a 10% tint around the handle, about 1.1:1 against the surface.
927
+ - In a browser without CSS anchor positioning, a popover is centered in the
928
+ viewport. It used to land in the top-left corner, far from its button.
929
+ - A scrolling marquee no longer restyles every item on each frame. The
930
+ reset's `box-sizing: inherit` tied each item's style to its moving group,
931
+ so on a page that also drew every frame, each frame restyled every item
932
+ as well as the groups. Items now set `box-sizing: border-box` themselves.
933
+ - A dot map marker takes taps in a 48dp circle around its 16dp dot. It was
934
+ a 16px target on a map that is itself a target, under WCAG 2.5.8's 24px
935
+ minimum.
936
+ - A snackbar with `displayLength: Infinity` gets its close button by
937
+ default, as one with an action does. Without an action it could otherwise
938
+ only be swiped away. An explicit `dismissible: false` is kept.
939
+ - A `nowrap` breadcrumb scrolls sideways as documented. Its crumbs used to
940
+ shrink below their text, so each separator sat on the last letter of the
941
+ crumb before it.
942
+ - A list row's trailing `span.badge` or `span.meta` stays in the last
943
+ column. The label rule matched it and outranked the trailing rule, so a
944
+ bare-text label like "Inbox" was pushed after the badge.
945
+ - Controls grow with their text. Type is set in `rem`, but buttons, icon
946
+ buttons, FABs, badges, avatars, keypad keys, text fields, selects, the
947
+ app bar, the search bar and the slider's inset icon used `px` boxes. With
948
+ a larger browser font size or 200% text-only zoom, their labels and icons
949
+ spilled out or were cut, and a field's floating label sat on its value.
950
+ Those sizes are now `rem` (a new `rem()` Sass function), so pages render
951
+ the same at the default 16px. A field's clearance for its prefix, suffix,
952
+ password toggle and number stepper grows with them.
953
+ - Charts, cards, stats, KPIs and the org chart grow with their text too:
954
+ - the chart height, y-axis width, bar and heatmap row heights, pie label
955
+ room, radar label room and tooltip width;
956
+ - the small, medium and large card heights;
957
+ - the stat tile minimum;
958
+ - the KPI icon box;
959
+ - the org chart card width.
960
+ At 200% text, axis labels no longer shrink to "8…" or "$…", a pie or
961
+ radial total stays inside its ring, and stat tiles wrap instead of
962
+ breaking "$48.2k".
963
+ - A trigger with both a Tooltip and a Menu keeps both anchors. Each wrote
964
+ the whole `anchor-name` property, so the second replaced the first, and
965
+ destroying either removed the other's. Tour targets share the same list.
966
+
967
+ - Timepicker on an `<input type="time">` writes 24-hour `HH:mm`. A
968
+ 12-hour picker wrote `02:15 PM`, which a time input rejects by emptying
969
+ itself.
970
+
971
+ - Tab closes an open Lightbox. The image zooms in place rather than in a
972
+ modal, so Tab used to move focus to the page behind the overlay.
973
+
974
+ - The data table page's sort script compares numeric columns as numbers
975
+ and reads `data-value` first, so `$1,200.00` sorts after `$87.00`.
976
+
977
+ - Forced colors (Windows contrast themes) paint every fill as Canvas, and a
978
+ few controls drew nothing else:
979
+ - Filled, tonal and elevated buttons, filled and tonal icon buttons,
980
+ keypad keys, the keyboard, the questionnaire's footer buttons, the bar
981
+ chart track and the search bar now get an outline.
982
+ - A pressed toggle takes the Highlight fill.
983
+ - The select caret and check, the submenu chevron and the bottom sheet
984
+ handle, all glyphs masked from a fill, paint in CanvasText.
985
+ - Slider stops come back, and the inactive track is CanvasText, so
986
+ GrayText now means only disabled.
987
+ - Disabled checkboxes, radios and their labels turn GrayText.
988
+ - FABs (`.extra`, `.extend`, `.large.circle`) and `.button` get the
989
+ outline too, the column chart track is outlined like the bar chart's,
990
+ the color picker area gets an edge, and every aura variant, rainbow and
991
+ glow included, is the solid Highlight ring its docs describe.
992
+ - Blockquotes, table cells and the stacked `.responsive-table` header use
993
+ logical properties, so the quote bar, cell alignment and header border
994
+ mirror in a right-to-left page.
995
+ - The lightbox opens above a non-modal bottom or side sheet. Its overlay and
996
+ zoomed image were at `z-index: 1000`, under the sheets' 1100; they now use
997
+ `--expressive-z-lightbox` (1200).
998
+ - Swipeable tabs no longer jump back to the previous panel when you pick a
999
+ new one while the last scroll is still running. The track released its
1000
+ target as soon as its position rounded to the new panel, so the rest of
1001
+ the old scroll selected the panel it was heading to and fired `onShow`
1002
+ for it. The target now holds until the track arrives.
1003
+ - Static chip close buttons work again after `AutoInit()`. The fallback
1004
+ handler stepped aside for any `.chips` with an instance, and an instance
1005
+ without `allowUserInput` never handled the click. Chips also copy their
1006
+ initial `data`, ignore Enter during IME composition, and mirror arrow keys
1007
+ in right-to-left text.
1008
+ - Menu clears its old highlight when it closes or moves, so reopening no
1009
+ longer leaves two rows active. A `.menu-trigger` whose target id does not
1010
+ resolve now warns and stays inert instead of inserting the text "null".
1011
+ Menubar arrow keys skip disabled items.
1012
+ - A multi-select's checkbox stays checked when the box itself is clicked, and
1013
+ a disabled option in a single select no longer closes the menu.
1014
+ - Autocomplete keeps the active row when a multi-select option is toggled and
1015
+ doesn't search again. It returns focus to the field after a single-select
1016
+ click, and takes Escape only when it closes the list, so an enclosing dialog
1017
+ stays open. Results set before the field is focused don't open the list.
1018
+ `destroy()` removes the combobox attributes it added.
1019
+ - Datepicker sorts multiple dates the same way in every browser, puts the tab
1020
+ stop on today when nothing is selected, keeps focus on the year or month
1021
+ select across a redraw, and no longer changes the caller's `minDate` and
1022
+ `maxDate`. A typed date in multiple-selection mode joins the selection.
1023
+ `destroy()` removes the date input's painted value.
1024
+ - Tabs find panels whose ids contain non-ASCII characters or sit in a shadow
1025
+ root, and a shown panel keeps its CSS `display` instead of becoming
1026
+ `block`.
1027
+ - Carousel leaves Alt, Ctrl, Meta and Shift shortcuts alone, as well as arrow
1028
+ keys aimed at sliders, menus, tab lists and media controls inside a slide.
1029
+ - A snackbar swipe made within one millisecond no longer counts as a flick.
1030
+ - A textarea hidden at load (in a closed dialog or an inactive tab) gets its
1031
+ height when it is first focused or typed in instead of staying 0px tall. A
1032
+ `.file-field` without a path input no longer throws.
1033
+ - Tour skips steps whose target has been removed. A side sheet starts a drag
1034
+ only from its own header. Escape during a sortable drag no longer closes
1035
+ the dialog around the list.
1036
+ - Lightbox returns focus to the image when it closes and doesn't open an
1037
+ image it can't measure. Particles uses the latest visibility entry,
1038
+ repaints still dots after a theme change, and follows reduced motion as it
1039
+ changes. MapView skips `data-lng-lat` values with an empty part and
1040
+ handles cluster zooms and fullscreen requests that finish after
1041
+ `destroy()`.
1042
+ - A keypad initialized before it is in the document works once inserted. The
1043
+ slider's value label follows its host when the host resizes.
1044
+ - RichTextEditor logs invalid toolbar `data-attributes` JSON instead of
1045
+ throwing. A required editor blocks submit while empty and takes focus,
1046
+ where the hidden textarea used to block it with no message.
1047
+ - The character counter shows a prefilled value's count and invalid state
1048
+ without waiting for focus. ExpandingCard calls `onClose` when its dialog is
1049
+ closed natively. Card reveals and the app bar's search view work inside a
1050
+ shadow root. ExpandingCard, AppBar, the FAB menu and CharacterCounter undo
1051
+ their ARIA and tabindex changes on `destroy()`, and an `<a>` FAB trigger
1052
+ without `href` is focusable.
1053
+ - A navigation rail `<button>` destination is now as tall as a link
1054
+ destination instead of the default button's 40px.
1055
+ - A side panel destination that comes first in a navigation rail is laid out
1056
+ as a destination, and `NavigationRail` no longer treats it as the menu
1057
+ toggle.
1058
+ - The navigation rail side panel keeps its 12px padding. The global
1059
+ `[popover]` reset in the menu styles had cleared it.
1060
+ - A modal or compact NavigationRail no longer collapses when blank space
1061
+ inside it is tapped. Its scrim is the rail's own `::before`, so those taps
1062
+ looked like scrim taps; only a tap beside the rail collapses it now.
1063
+ - Touch drags on a bottom sheet's `.drag-handle` and a side sheet's
1064
+ `<header>` now dismiss the sheet. Without `touch-action` the browser took
1065
+ the drag as a pan and cancelled the pointer, so the sheet snapped back. The
1066
+ bottom sheet's built-in handle band and the side sheet's inner edge have no
1067
+ element of their own to carry `touch-action`, so on touch screens the
1068
+ explicit handle and the header are the drag areas.
1069
+ - A docked Datepicker for a date range now opens from its end input, and a
1070
+ click on that input no longer closes it. The plugin counted the end input
1071
+ as outside.
1072
+ - Menus listen for outside clicks on the document instead of `<body>`, so a
1073
+ click below the content of a page shorter than the window closes them.
1074
+ - A MapView marker or popup whose `data-lng-lat` is not "longitude,latitude",
1075
+ such as Google's latitude-first order, is skipped with a warning. MapLibre
1076
+ threw on it after the map was created, which leaked the map and stopped
1077
+ the rest of that `init()` call.
1078
+ - Restarting a running Tour releases the step it was showing, so only one
1079
+ target carries the highlight.
1080
+ - Autocomplete results that arrive after the user left the field update the
1081
+ list without opening it under the input.
1082
+ - A date typed into a Datepicker that the calendar would not offer, outside
1083
+ `minDate`/`maxDate`, a disabled weekend or refused by `disableDayFn`, now
1084
+ puts the input back to the selected date. A date before `minDate` used to
1085
+ become `minDate` in the picker while the input, and the submitted form
1086
+ value, kept the typed text.
1087
+ - A Datepicker input's initial value is now the selection, as it already was
1088
+ once the input was clicked. `instance.date` was undefined until then, and a
1089
+ multiple selection started empty.
1090
+ - A form reset now resets a Datepicker: the inputs added for extra dates in
1091
+ multiple selection are removed, and the selection is read back from the
1092
+ reset values. A refused date typed into one of those inputs restores that
1093
+ input's own date. A Slider's fill and value label also follow a form reset.
1094
+ - Skipping a Questionnaire question clears its error. A skipped question
1095
+ whose answer had been wrong still showed the error when the user went back.
1096
+ - A tooltip opened by hover still closes on Escape but no longer takes the key
1097
+ from the focused control, so the same Escape also closes the dialog or menu
1098
+ the user is in. On its own trigger, Escape stays the tooltip's.
1099
+ - A hover menu no longer moves focus into itself when the pointer passes its
1100
+ trigger, which pulled focus out of the field being typed in. Space, Enter or
1101
+ an arrow key on the trigger moves focus into the open menu, and Escape
1102
+ closes it from wherever focus is.
1103
+ - Clicking inside an open Autocomplete input, for example to move the caret,
1104
+ no longer closes its list. A trigger's own click is no longer treated as an
1105
+ outside click by Menu.
1106
+ - Enter in a Timepicker hour or minute field writes the typed time, after an
1107
+ emptied field takes its default as it would on leaving. With the
1108
+ default `autoSubmit` there is no Ok button, so a keyboard user could type a
1109
+ time but never set it.
1110
+ - Chips selection follows focus. Arrow keys used to move from the highlighted
1111
+ chip while Backspace deleted the focused one, and the highlight stayed after
1112
+ focus left the field.
1113
+ - Behaviors that listen on the document now work inside an open shadow root.
1114
+ Copy, Theme, Dialogs light dismiss, bottom and side sheet dragging, the
1115
+ bottom sheet handle button, ImageCompare, PaneResize, Sortable, Tour
1116
+ controls, the password toggle, error summary links and drop zones read the
1117
+ event's `composedPath()` instead of its target, which the document sees as
1118
+ the shadow host. Sortable keeps focus on a moved item's button there, Theme
1119
+ marks the controls in the clicked control's shadow root, and a sheet closed
1120
+ there in the middle of a drag reopens without the drag offset.
1121
+ Menubar moves between open menus, ScrollSpy marks links, and a card reveal
1122
+ trigger named by `aria-labelledby` is accepted in a shadow root too. A
1123
+ tooltip under a positioned shadow host now sits next to its trigger instead
1124
+ of offset by the host's position. `change`, `submit`, `reset` and `toggle`
1125
+ events do not leave a shadow root, so file lists, field validation, the
1126
+ error summary and Tour's own toggle handling still need light DOM.
1127
+ - Focused read-only text fields now show the focus underline. The field's
1128
+ focus styles skipped `[readonly]`, and FormSelect makes its combobox input
1129
+ read-only, so a focused select had no visible focus indicator.
1130
+ - `@use "expressive" with ($md-source: …)` now sets the theme seed, as the
1131
+ changelog for 0.13.0 and the migration skill describe. The variable moved
1132
+ to `abstracts/_variables.scss`; before, Sass rejected the configuration
1133
+ because the tokens layer is loaded with `meta.load-css()`.
1134
+ - The time picker's clock face is sized from `dialRadius`. It was a fixed
1135
+ 260px while the hand and numbers centred on the default 135px radius, so
1136
+ the hand sat 5px off centre, further with a custom `dialRadius`.
1137
+ - Menus, context menus and select dropdowns open next to their trigger in
1138
+ right-to-left pages. The menu kept the browser's `[popover]` `inset: 0`,
1139
+ so with its explicit width the right edge won over `left`, and the menu
1140
+ opened against the right side of its container.
1141
+ - Unlayered CSS can set a shadow on any component again. Thirteen component
1142
+ rules that remove a shadow (text buttons, disabled buttons, docked
1143
+ toolbars, filled and outlined cards, full-screen dialogs, separated panes,
1144
+ the search view's bar) used `box-shadow: none !important`, and a layered
1145
+ `!important` beats every unlayered rule. Only the `.z-depth-0` utility
1146
+ keeps the flag. A focused disabled `a.button` with an `href` no longer
1147
+ shows the enabled fill, a disabled FAB takes the disabled fill instead of
1148
+ the primary container, and an `elevated` pane in a separated or floating
1149
+ layout now shows its elevation. Disabled FAB menu items and toolbar FABs,
1150
+ including `aria-disabled="true"` ones, paint as disabled and no longer lift
1151
+ or tint on focus; `aria-disabled` ones still take hover, so a tooltip can
1152
+ say why. `.hoverable` no longer lifts a disabled element.
1153
+ - A shadow root that adopts the sheet as its only stylesheet now inherits the
1154
+ page defaults: `border-box` sizing, the body-medium type role and the
1155
+ on-surface text color. These were set only on `html` and `body`, which a
1156
+ shadow tree cannot reach, so its elements were `content-box` with the
1157
+ browser's default text color.
1158
+ - With reduced motion requested, the floating label, switch handle, icon
1159
+ button shape, slider value label, chips, time picker dial and the open card
1160
+ reveal panel no longer animate.
1161
+ - A carousel that reaches the end of its track keeps the item you moved to.
1162
+ Items past the end share that scroll position, and a one-pixel rounding
1163
+ difference in WebKit could select a later one in a right-to-left carousel.
1164
+ - Selection and checked states stay visible with forced colors (Windows High
1165
+ Contrast). Tabs, navigation bar and rail destinations, pagination, toolbar
1166
+ actions, menu and list items, mega menu links and filter chips mark the
1167
+ selected item with a Highlight outline. Checkboxes, radios and switches draw
1168
+ their checked state in system colors and get an outline on keyboard focus.
1169
+ The datepicker marks today, the selected day and the range. Small badges,
1170
+ the loading indicator and carousel dots keep their shape. A keyboard-focused
1171
+ tab also gets the focus ring instead of only a faint tint.
1172
+ - Right-to-left pages lay out text fields, checkboxes and more on the correct
1173
+ side. The floating label, prefix and suffix icons, trailing icon button,
1174
+ character counter and the select caret's inset follow the reading
1175
+ direction, as do the checkbox mark, the date range band, the modal
1176
+ navigation rail, the snackbar container and its padding, the dialog header
1177
+ form, menu item text and the nested menu's entry slide, and the map popup's
1178
+ close button. A field's label, icons and icon clearance follow the field's
1179
+ `dir`, so an input with `dir="auto"` or its own `dir` keeps its text clear
1180
+ of the icon. Fields and the character counter read `dir`; a page that sets
1181
+ only the CSS `direction` property renders them left to right. Known issue:
1182
+ the date picker's `isRTL` option reverses the cells in script, so the range
1183
+ band points the wrong way with it on, and on an RTL page it turns the
1184
+ calendar back to left to right. On an RTL page, leave `isRTL` off.
1185
+ - The modular entry now exports the option types of `CommandPalette`,
1186
+ `Confetti`, `Particles`, `Keypad`, `MessageScroller`, `RichTextEditor` and
1187
+ `MapView`, as it already did for the other components.
1188
+ - The docs now cover the styled native `<meter>` on the progress page, the
1189
+ `onOpen` and `onClose` callbacks of cards and expanding cards, the
1190
+ timepicker's `dialRadius`, `outerRadius`, `innerRadius` and `tickRadius`
1191
+ options, `PaneResize.width()` and `PaneResize.setWidth()`,
1192
+ `Copy.textFor()`, and the `.overline` helper.
1193
+ - A JavaScript tooltip whose trigger sits in a shadow root now starts hidden
1194
+ and absolutely positioned. The tooltip goes into that shadow root, where
1195
+ neither `body > .tooltip` nor `:not(body) > .tooltip` matched it, so it
1196
+ showed in the page flow before it was ever opened. `:host > .tooltip` now
1197
+ gets the same rule as `body > .tooltip`.
1198
+ - A tap on a menu item after scrolling the menu by touch closes the menu
1199
+ again. The scroll flag was cleared only by a click, and a touch scroll
1200
+ ends without one, so the next tap was ignored as part of the scroll.
1201
+ - Datepicker's previous and next month buttons have accessible names. The
1202
+ `previousMonth` and `nextMonth` i18n strings were never read; they now label
1203
+ the buttons and default to `'Previous month'` and `'Next month'`.
1204
+ - A drag that starts on a bottom sheet's `.drag-handle` now moves the sheet
1205
+ wherever the handle sits. The drag check looked only for the pre-1.0
1206
+ `.handle` class.
1207
+
1208
+ ### Removed
1209
+
1210
+ - The version resolver's JSON output (`scripts/resolve-version.mjs` in the
1211
+ skill and the MCP package) drops `declaredVersion`,
1212
+ `skillContractVersion` and `matchingCommit`. The first two copied
1213
+ `declaredRange` and `contractVersion`, which remain; `matchingCommit`
1214
+ was always `null`. Read `declaredRange` and `contractVersion` instead.
1215
+ - Datepicker's undocumented `formats` property, the table of format
1216
+ functions. The `format` option and its tokens are unchanged.
1217
+ - **Breaking (0.16.0).** Most names kept for markup written before 0.8.0 are
1218
+ gone. Each one has a replacement that has been documented since 0.8.0;
1219
+ see Migration below. A few stay: `.breadcrumb` and `.breadcrumb-wrapper`,
1220
+ a bare `ul.pagination`, and checkbox `input + span`, which multiple Select
1221
+ still emits.
1222
+ - **Breaking (0.16.0).** The remaining compatibility paths are gone too: the
1223
+ `.range` and `.range-field` slider hosts, a switch whose `.switch` class
1224
+ sits on a wrapper around the label, the `.extra` size on a common button,
1225
+ radio `input + span` and switch `input + span` / `.lever` drawing, the
1226
+ `li.tab` wrapper, a chip's `.active`, Carousel's `.flat` layout, `fullWidth`
1227
+ option and `.carousel-fixed-item`, and the `background`, `on-background`,
1228
+ `surface-variant` and `surface-tint` color roles with their `-light`/`-dark`
1229
+ pairs and utility classes.
1230
+ - Selectors and code that never matched or never ran. The date and time
1231
+ picker rules no longer carry hyphenated twins of their generated parts,
1232
+ such as `.date-picker-container`; the script only ever emitted the
1233
+ unhyphenated names. The root `.date-picker` and `.time-picker` classes
1234
+ still start the components. Also gone: the `.tabbed` focus class, which
1235
+ every rule already paired with `:focus-visible`; the `.halfway-fab`,
1236
+ `.searchbar.has-sidebar` and `.prefix ~ .chips` offsets; the
1237
+ picker footer rules for buttons the script never created; and the
1238
+ normalize rules for `h1`, `b`, `strong`, `small` and `kbd`, which the
1239
+ typography rules already override.
1240
+ - Datepicker's `startRange` and `endRange` options. Nothing set them, and the
1241
+ `is-startrange`, `is-endrange` and `is-inrange` classes they produced had
1242
+ no styles. Use `isDateRange` for range selection.
1243
+
1244
+ ### Changed
1245
+
1246
+ - The `expressivecss` skill is version 0.12.0 and `expressivecss-review` is
1247
+ version 0.1.1. A review now leaves the reviewed files unchanged and only
1248
+ offers its fixes. `expressivecss-migration` ships at 0.1.0.
1249
+
1250
+ - Chips' form-associated control moved to a shared core module, which the
1251
+ cascader uses too. The control gained `checkValidity()` and
1252
+ `reportValidity()`.
1253
+
1254
+ - An open menu is a popover in the browser's top layer. This covers Menu,
1255
+ Select, Autocomplete, the menubar, Chips suggestions and the date
1256
+ picker's menus. A container that clips or scrolls no longer cuts a menu
1257
+ off, a modal dialog or sheet no longer covers it, and it draws above
1258
+ every `z-index`, so `--expressive-z-menu` now only orders the docked date
1259
+ and time pickers. Menu no longer sets `position: relative` on the
1260
+ nearest clipping ancestor. The menu's `popover` attribute is `manual`,
1261
+ and Menu still handles outside clicks and Escape itself. A context menu
1262
+ is kept inside the window rather than its scrolling container, and stays
1263
+ where it opened when that container scrolls. A `coverTrigger: true`
1264
+ menu, or a menu whose trigger sits under a transformed ancestor, is
1265
+ placed by measurement and follows its trigger when the page or a
1266
+ container scrolls. Firefox would anchor a top-layer menu to the
1267
+ trigger's box before transforms, which puts it beside a floating toolbar
1268
+ centred with `translateX(-50%)` instead of under its button. Migration:
1269
+ tests that run Menu in jsdom need `showPopover` and `hidePopover` stubs,
1270
+ and CSS or script that read an open menu's inline `display: block`
1271
+ should use `menu[id]:popover-open` or the instance's `isOpen`.
1272
+ - An open Lightbox shows its overlay, image and caption as manual popovers
1273
+ in the browser's top layer. The image still zooms from its thumbnail
1274
+ and back, and Tab, Escape, a click and scrolling still close it; focus is
1275
+ not trapped. Lightbox no longer sets `overflow: visible` on every
1276
+ ancestor of the image while it is open, which let a scrolling container
1277
+ lose its clipping. `--expressive-z-lightbox` no longer applies to it. The
1278
+ image carries `popover="manual"` only while open. Migration: tests that
1279
+ run Lightbox in jsdom need `showPopover` and `hidePopover` stubs.
1280
+ - The `.mx-*`, `.my-*`, `.px-*` and `.py-*` helpers set `margin-inline`,
1281
+ `margin-block`, `padding-inline` and `padding-block`. Horizontal text
1282
+ renders as before. In a vertical writing mode, `.mx-*` and `.px-*` now
1283
+ space the top and bottom, following the text, and `.my-*` and `.py-*`
1284
+ the left and right.
1285
+ - Menu, navigation bar and slider state layers read the
1286
+ `--md-sys-state-*-state-layer-opacity` tokens instead of fixed 8% and
1287
+ 10% mixes. The defaults render the same. A page that overrides a state
1288
+ token now changes these layers too.
1289
+ - Every component inherits one `Component.init`, and the base constructor
1290
+ merges `defaults` with the options passed in. `init` types are
1291
+ unchanged. The `CommandPalette` and `Questionnaire` constructors accept
1292
+ any `HTMLElement`, which their `init` already took, and a subclass that
1293
+ overrides `defaults` now gets its own defaults merged.
1294
+ - Every component inherits one `getInstance` from `Component`, which also
1295
+ sets and clears the `el.Expressive_<Name>` property. The types are
1296
+ unchanged, except that `Slider` and `CharacterCounter` accept any
1297
+ `HTMLElement`. A subclass that overrides `getInstance` with its own return
1298
+ type no longer compiles (TS2417); delete the override, because the inherited
1299
+ one already returns the subclass.
1300
+ - The bundle uses `ResizeObserver` and `IntersectionObserver` without
1301
+ checking that they exist. Every supported browser has both, but tests that
1302
+ run components in jsdom need stubs for them, as they already need one for
1303
+ `matchMedia`.
1304
+ - A click in a Select sets `selected` on the option clicked and leaves the
1305
+ others alone. It used to write every option.
1306
+ - Data tables and line charts inside a shadow root sort and format numbers
1307
+ in the host's `lang`, as the date and time pickers already do.
1308
+ - The MCP package ships `scripts/bounded-file.mjs` and
1309
+ `scripts/semantics-rules.mjs`. Inspection read errors use new wording,
1310
+ such as "inspected file exceeds N bytes".
1311
+ - A runtime tooltip that opens while a tooltip is closing, or within 300 ms
1312
+ after that one's `exitDelay` ends, shows without waiting its
1313
+ `enterDelay`, so moving along a toolbar shows each tooltip at once. Only
1314
+ pages that set `enterDelay` above `0` see a difference. The first tooltip
1315
+ still waits its delay, and a tooltip that stays open does not shorten the
1316
+ others'. The window is fixed and has no option.
1317
+ - A Chips field whose text `<input>` has a `name` now submits its chips
1318
+ under that name, one `id` each, instead of the text being typed. A page
1319
+ that read the draft text from the form should read `chips.getData()`, or
1320
+ take the `name` off the input to keep the old behavior. The input now sits
1321
+ inside `<expressive-chips-control>`, so `.chips > input` selectors and
1322
+ `input.parentElement` code need updating. The input's `validity`,
1323
+ `validationMessage`, `:invalid` and `invalid` event no longer report the
1324
+ required state; read them from the control or the form. `form.elements`
1325
+ lists the control under the field's name. In a Questionnaire step, or on
1326
+ a `.validate` input, an empty required chips field does not count as
1327
+ invalid.
1328
+ - Datepicker and Timepicker follow the page's language. With a `lang` on
1329
+ the input or around it, the calendar takes that language's month and
1330
+ weekday names from `Intl` and its first day of the week where the browser
1331
+ knows it, and the clock defaults to 12- or 24-hour as that language does.
1332
+ Options the page passes still win, and the button words stay English
1333
+ unless passed. A page with no `lang` is unchanged. To keep the English
1334
+ calendar on a page with another `lang`, pass the English names in `i18n`.
1335
+ A typed date in the picker's own `format` is now read with its names, so
1336
+ the localized value it writes reads back, and `05/10/2026` in
1337
+ `dd/mm/yyyy` is 5 October rather than what `Date.parse` guessed.
1338
+ - A full-screen `dialog.search-view` opens on a click, Enter or ArrowDown
1339
+ in the app bar's search field, not on focus. Tabbing through the bar used
1340
+ to open the modal each time, so every keyboard pass needed an Escape
1341
+ (WCAG 3.2.1). A docked view still opens on focus. The bar shows the
1342
+ shared focus ring while its field is focused, since its input clears its own.
1343
+
1344
+ - Snackbars queue. A new snackbar waits until the one on screen is dismissed,
1345
+ then shows, as Material asks, instead of replacing it at once. Migration:
1346
+ pass `replace: true` where a snackbar should still take over immediately,
1347
+ as copy buttons now do. A queued snackbar fires `expressive:open` and
1348
+ captures focus when it appears, `dismissAll()` clears the queue too, and a
1349
+ snackbar built from `snackbarId` has no `el` until it shows. A persistent
1350
+ snackbar whose container a re-render removed no longer blocks the next.
1351
+
1352
+ - Time picker hours step round the day: in 12-hour time, Up from 11 AM
1353
+ gives 12 PM and Down from 12 PM gives 11 AM, so AM and PM follow the
1354
+ hour.
1355
+ - Radar chart gaps: a missing value breaks the outline instead of joining
1356
+ the spokes either side, as a line chart's does. With `.area`, each
1357
+ unbroken run fills as a wedge from the middle, drawn by a new
1358
+ `.radar-chart-area` path, and a value between two gaps is a dot.
1359
+ - A sheet drag that moves against the dismissing direction now counts as
1360
+ a drag, so the click that ends it no longer activates a handle button.
1361
+ - The time picker's hour and minute fields are spin buttons
1362
+ (`role="spinbutton"` with their range). Up and Down step them by one and
1363
+ Page Up and Page Down by five, wrapping round the dial, and the clock hand
1364
+ follows. Code that found them by the `textbox` role needs `spinbutton`.
1365
+ - The `Tooltip` plugin anchors its bubble with CSS anchor positioning where
1366
+ the browser supports it: the tooltip stays beside its activator through
1367
+ page and container scrolling and flips at the viewport edge. Anchored
1368
+ tooltips fade in without sliding, and `transitionMovement` joins the gap.
1369
+ Other browsers keep the measured position.
1370
+ - Menus opened from a trigger, including Select, Autocomplete, the menubar
1371
+ and the date picker's menus, anchor with CSS anchor positioning where
1372
+ supported: they follow the trigger through scrolling, flip at the viewport
1373
+ edge and scroll when taller than the room on that side. Context menus and
1374
+ `coverTrigger: true` keep the measured placement.
1375
+ - The tabs indicator moves on the default spatial spring
1376
+ (`--md-comp-tabs-indicator-easing` and `-duration`), and now stops under
1377
+ reduced motion. The `Tabs` `duration` option defaults to `null`; a number
1378
+ keeps the old ease-out timing for that instance. Switch handles slide on
1379
+ the fast spatial spring (`--md-comp-switch-motion` and `-motion-duration`),
1380
+ and the chip set's border and shadow change on the fast effects spring.
1381
+ - Button groups and the keypad press on the fast spatial spring tokens
1382
+ instead of the hand-sampled `$motion-fast-spatial` curve, through
1383
+ `--md-comp-button-group-motion` and `--md-comp-keypad-motion` with new
1384
+ `-motion-duration` pairs, so `motion="expressive"` reaches them. The press
1385
+ settles in 182ms instead of a 200ms window. `$motion-fast-spatial` stays
1386
+ for Sass that still names it.
1387
+ - Reduced motion now reaches every component through the tokens: under
1388
+ `prefers-reduced-motion: reduce`, all `--md-sys-motion-duration-*` and
1389
+ spring `-duration` tokens are `0s`. Lists, the data table, the navigation
1390
+ bar, the mega menu, checkboxes, radios, pagination, tabs, the
1391
+ questionnaire and the lightbox had no rule of their own and animated
1392
+ before. No `!important`, so a page can opt an element back in.
1393
+ - Bottom and side sheets slide in and snap back on the default spatial
1394
+ spring (`--md-comp-bottom-sheet-motion`, `--md-comp-side-sheet-motion` and
1395
+ their `-motion-duration` tokens) instead of a 280ms ease, so
1396
+ `motion="expressive"` applies to them. Each sheet now extends 24px past its
1397
+ docked edge, with matching padding, so a spring's overshoot never uncovers
1398
+ the page.
1399
+ - The navigation rail expands and collapses on the default spatial spring
1400
+ (`--md-comp-nav-rail-motion` and `-motion-duration`). Its width, min-width
1401
+ and padding no longer follow `--md-comp-nav-rail-duration`, which now
1402
+ times only the indicator color.
1403
+ - FAB menu actions move on the fast spatial spring and fade on the fast
1404
+ effects spring. `--md-comp-fab-menu-easing` and `-duration` now default to
1405
+ the spatial spring, and the new `--md-comp-fab-menu-effects-easing` and
1406
+ `-effects-duration` time the fade.
1407
+ - Basic dialogs now animate in: they fade on the fast effects spring and grow
1408
+ from 96% on the default spatial spring (`--md-comp-basic-dialog-easing`,
1409
+ `-duration`, `-effects-easing` and `-effects-duration`). They still close
1410
+ at once. Sheets, `dialog.max` and the expanding card's dialog are
1411
+ unchanged, and reduced motion opens without moving.
1412
+ - The expanding card morphs on the slow spatial spring:
1413
+ `--md-comp-expanding-card-motion-duration` and `-motion-easing` now default
1414
+ to it instead of 500ms on the standard curve. New `-content-duration`,
1415
+ `-content-easing`, `-fade-duration` and `-fade-easing` tokens time the close
1416
+ button and detail content. Close cleanup still follows the actual clip
1417
+ transition.
1418
+ - Headings balance their lines and paragraphs avoid a one-word last line
1419
+ (`text-wrap-style: balance` and `pretty`). The longhand leaves wrapping
1420
+ itself alone, so `.truncate` and `.text-nowrap` still work.
1421
+ - A link without a class inside a `p`, `dd`, `blockquote`, `figcaption` or
1422
+ `td` is underlined, so links in running text no longer rely on color alone
1423
+ (WCAG 1.4.1). Links with a class, and links in lists, menus and navigation,
1424
+ are unchanged.
1425
+ - The documentation's category rail opens each group's pages in a side
1426
+ panel on hover or click, with each section as a dropdown. The section
1427
+ holding the current page starts open. The panel replaces the page list that
1428
+ sat beside the rail from Large up.
1429
+ - Snackbar's generated close button holds its icon in a
1430
+ `<span class="material-symbols">` instead of an `<i>`. Styles that targeted
1431
+ `.snackbar i` need `.snackbar .material-symbols`.
1432
+ - Swipeable tabs no longer use Carousel. The panels move into a full-width
1433
+ `.tabs-content` scroll-snap track, so touch and trackpad swipes are native
1434
+ scrolling. Only the shown panel is reachable by keyboard; the others are
1435
+ `inert`. The track re-aligns when its width changes, so a tab bar started
1436
+ in a closed dialog or sheet shows the current panel once opened. Dragging
1437
+ the panels with a mouse no longer switches tabs; click the tab instead.
1438
+ - Components that read `surface-variant` now read
1439
+ `surface-container-highest`, as Material 3 maps it: the unselected switch
1440
+ track, the time picker's clock face and hour and minute inputs, the date
1441
+ picker's header rule and focused month and year field, and disabled cards.
1442
+ In dark mode those surfaces are a little darker and more neutral. Rules
1443
+ that read `background` or `on-background` now read `surface` and
1444
+ `on-surface`, which resolve to the same colors.
1445
+
1446
+ ### Migration
1447
+
1448
+ - Sass: `@include z-depth("0")`, `btn-flat` and `btn-disabled` no longer emit
1449
+ `box-shadow: none !important`. A stylesheet that relied on the flag to
1450
+ cancel its own higher-specificity or inline shadow needs the flag itself.
1451
+ The `.z-depth-0` class keeps it. Because the utility layer outranks those
1452
+ resets, `.hoverable` on a text button now lifts it on hover, and a pressed
1453
+ `.filled` or `.outlined` card with `.hoverable` keeps the hover shadow.
1454
+
1455
+ - Icons: write `<span class="material-symbols" aria-hidden="true">`. A bare
1456
+ `<i>` is no longer treated as an icon inside buttons, lists, menus, chips,
1457
+ bars or fields, and `.material-icons` is gone; use `.material-symbols`
1458
+ (or the `-outlined`, `-rounded` and `-sharp` variants).
1459
+ - Field icons: name the side with `.prefix` or `.suffix`. The positional
1460
+ `i:first-of-type` / `i:last-of-type` fallback is gone.
1461
+ - Visibility helpers: replace `.hide-on-small-only` and
1462
+ `.hide-on-small-and-down` with `.hide-on-compact-only`, `.hide-on-med-only`
1463
+ with `.hide-on-medium-only`, `.hide-on-xxl-only` with
1464
+ `.hide-on-extra-large-only`, `.show-on-small` with `.show-on-compact`, and
1465
+ `.show-on-xxl` with `.show-on-extra-large`.
1466
+ - Replace `.no-padding` with `.p-0` and `.center-block` with `.mx-auto` plus a
1467
+ `display: block` of your own. `.no-select` has no replacement class; set
1468
+ `user-select: none` in your own CSS.
1469
+ - Progress: replace `.preloader` with `.progress.circular`.
1470
+ - Date and time pickers: AutoInit starts `.date-picker` and `.time-picker`
1471
+ only. Rename `class="datepicker"` and `class="timepicker"` on the inputs.
1472
+ - Search: replace `.searchbar` with `.search-bar`.
1473
+ - Sheets: replace `dialog.bottom` with `dialog.bottom-sheet`, and the sheet's
1474
+ `.handle` with `.drag-handle`. Replace side sheet `dialog.right` and
1475
+ `dialog.right-sheet` with `dialog.side-sheet`, and `dialog.left` and
1476
+ `dialog.left-sheet` with `dialog.side-sheet.start`.
1477
+ - Toolbar: replace host `.max` with `.docked` and host `.filled` with
1478
+ `.vibrant`. A `.filled` action and a `.max` spacer inside the bar are
1479
+ unchanged.
1480
+ - Tooltip: replace `.tooltip.max` with `.tooltip.rich`.
1481
+ - Menus: replace a bare `<hr>` between items with
1482
+ `<li class="divider" role="separator">`.
1483
+ - File input: the trigger is a `<label class="button">` wrapping the
1484
+ `<input type="file">`. A `<button>` or `.btn` trigger is no longer styled.
1485
+ - Script: replace `Expressive.Range` with `Expressive.Slider`.
1486
+ - Buttons: replace `class="button extra"` on a common button with
1487
+ `class="button medium"`. Its label grows from `label-large` (14px) to
1488
+ `title-medium` (16px). `circle extra` is still the FAB. A navigation
1489
+ rail FAB is a plain `.button`.
1490
+ - Radios and switches: drop the `<span>` or `.lever` after the input; the
1491
+ input draws the control and the label text sits beside it. Put `.switch`
1492
+ on the `<label>` itself: `<div class="switch"><label>` now draws a
1493
+ checkbox.
1494
+ - Sliders: replace a `.range` or `.range-field` host with `.slider`, or wrap
1495
+ the input in a `<label>`.
1496
+ - Tabs: put the `<a>` links directly in `nav.tabs`, without `ul` and
1497
+ `li.tab`.
1498
+ - Chips: replace `.active` with `.selected`.
1499
+ - Carousel: replace `.flat` or `fullWidth: true` with an M3 layout such as
1500
+ `.hero` or `.uncontained`. A `.carousel-fixed-item` child is now an
1501
+ ordinary item; position a fixed overlay in your own CSS.
1502
+ - Color: replace `--md-sys-color-background` with `surface`, `on-background`
1503
+ with `on-surface`, `surface-variant` with `surface-container-highest` and
1504
+ `surface-tint` with `primary`, in variables and in the `.x` / `.x-text`
1505
+ utility classes. Overrides of the `-light`/`-dark` pairs move the same
1506
+ way.
1507
+
1508
+ ## [0.15.0] - 2026-10-14
1509
+
1510
+ ### Added
1511
+
1512
+ - The agent skill has a layout guide, `expressivecss-layout`. It covers
1513
+ Material's layout principles, the five breakpoints with their grid
1514
+ prefixes and Sass mixins, the canonical layout starting points,
1515
+ right-to-left support, and where each Material layout term lives in
1516
+ ExpressiveCSS. Its breakpoints reference lists the panes and components
1517
+ for each breakpoint and walks through Material's five questions for the
1518
+ next size: what to reveal, divide, resize, reposition or swap. Its
1519
+ canonical layouts reference covers feed, list-detail and supporting pane
1520
+ layouts, including list-detail behavior when the window crosses 840px and
1521
+ a grid fallback for supporting content that must stack on narrow windows.
1522
+ Its grids and spacing reference maps Material's 4, 8 and 12 column grids
1523
+ onto the 12-track `.row`, rulers onto containers and pane margins, and
1524
+ covers grouping, rhythm and opt-in density with 48px targets. The design
1525
+ guide's scaffold reference now lists the recommended pane count for each
1526
+ breakpoint, the 50% split-pane rule with a navigation rail, the
1527
+ three-pane limit, drag-handle toggling and persistent resizing, and the
1528
+ co-planar, floating and docked ways to show more than one pane.
1529
+ - The scroll area docs show `.scroll-area` on `<html>` for a themed page
1530
+ scrollbar. A browser test covers page scrolling and theme colors.
1531
+ - `.keypad` and `.keyboard` are on-screen keys that type into the text
1532
+ field named by `aria-controls`. A keypad is three columns of round keys for
1533
+ PINs, codes and dial pads; a keyboard is rows of keys sized from a column
1534
+ count, with an optional `.numbers` row of shorter digit keys that
1535
+ `hidden` drops. Keys with a `value` type at the caret and fire `input`; `data-key`
1536
+ keys handle Backspace, Enter and a one-shot Shift. Keys square their
1537
+ corners on press, and a `wide` key spans two cells. A key inside the
1538
+ field's `.field`, such as a trailing Backspace, works too. Browsers skip
1539
+ `minlength` for scripted edits, so the docs give a minimum length as
1540
+ `pattern`. `Keypad` is in `AutoInit()` and takes an `onKey` option.
1541
+
1542
+ ### Changed
1543
+
1544
+ - The `expressivecss` skill is version 0.11.0. It adds the
1545
+ `expressivecss-layout` guide and component guides for keypad and keyboard.
1546
+
1547
+ ### Fixed
1548
+
1549
+ - Reference tables on the docs site scroll sideways inside their own box on
1550
+ narrow windows. At 375px, 22 docs pages used to scroll the whole page
1551
+ sideways, mostly because of tables with long token names and defaults.
1552
+ Three pages still do, because their demos (the 12-column grid, the large
1553
+ icon and the extra-large split button) are wider than a phone.
1554
+
1555
+ - A snackbar dismissed by a swipe now slides off the side it was swiped
1556
+ toward, starting from where the pointer let go. It used to jump to the
1557
+ right at once, even after a swipe to the left, because the dismiss
1558
+ transition replaced the transform transition before it could run.
1559
+ - Date picker days outside `minDate`/`maxDate`, weekends under
1560
+ `disableWeekends`, days rejected by `disableDayFn`, and the adjacent-month
1561
+ days from `showDaysInNextAndPreviousMonths` now use the M3 disabled text
1562
+ color and ignore the pointer. The rule looked for the state class on the
1563
+ day button, but the picker puts it on the cell, so these days looked
1564
+ selectable.
1565
+ - A footer whose only child is a plain `<nav>` link column now gets the full
1566
+ page footer styles. When the navigation bar arrived, only the first footer
1567
+ rule was narrowed to a lone `.navigation-bar`. The grid, `.filled`, link
1568
+ and legal bar rules still skipped any footer with a lone `<nav>`. Pane
1569
+ footers use the same guard, so they keep their flex action row.
1570
+ - Map markers and the column, bar and mixed chart hover layers mix
1571
+ `in oklab` like the rest of the framework. Each mix is with `transparent`,
1572
+ so the rendered colors do not change.
1573
+ - The date picker's unused `.year-text` no longer sets `on-primary`, a
1574
+ leftover from the removed primary header.
1575
+ - A `data-tooltip-id` that names no element now logs an error and shows the
1576
+ `data-tooltip` text. A `.tabs` bar with no links logs an error, and
1577
+ swipeable tabs whose links reach no panel act as normal tabs. Each of these
1578
+ used to throw, which stopped `AutoInit()` before the components after it.
1579
+ - Reopening a date picker no longer re-reads a value it wrote itself. Without
1580
+ a custom `parse`, `Date.parse` read a `dd/mm/yyyy` value of `05/10/2026` as
1581
+ 10 May and passed that to `onSelect`.
1582
+ - Space and Enter reach an autocomplete's text field while the list is
1583
+ closed. The menu's trigger keys cancelled them, so a space typed after
1584
+ Escape was lost and Enter could not submit the form. ArrowUp and ArrowDown
1585
+ open the list with the current matches.
1586
+ - Autocomplete fires `change` and `onAutocomplete` only when the selection
1587
+ changes, as documented, instead of after every search. `setMenuItems` no
1588
+ longer replaces `options.data`, so the documented custom `onSearch` filter
1589
+ keeps searching the full data set.
1590
+ - A chart cell such as `e5` or `1e400` is a gap. These passed the number
1591
+ check but read as `NaN` or `Infinity`, so one such cell turned every point
1592
+ in the chart into `NaN` and nothing was drawn.
1593
+
8
1594
  ## [0.14.1] - 2026-10-11
9
1595
 
10
1596
  ### Fixed
@@ -2253,7 +3839,9 @@ are no compatibility aliases.
2253
3839
  - `.tabs` nested in a header or app bar as a secondary row. `.tabs` is a
2254
3840
  standalone component; the `.tabs.transparent` app bar variant is gone with it.
2255
3841
 
2256
- [Unreleased]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.14.1...HEAD
3842
+ [Unreleased]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.16.0...HEAD
3843
+ [0.16.0]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.15.0...v0.16.0
3844
+ [0.15.0]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.14.1...v0.15.0
2257
3845
  [0.14.1]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.14.0...v0.14.1
2258
3846
  [0.14.0]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.13.1...v0.14.0
2259
3847
  [0.13.1]: https://github.com/BaezFJ/ExpressiveCSS/compare/v0.13.0...v0.13.1