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