@moni-labs/moni-ui 0.2.0 → 0.3.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 (323) hide show
  1. package/README.md +52 -194
  2. package/custom-elements.json +1636 -350
  3. package/dist/actions/index.d.ts +6 -0
  4. package/dist/actions/index.d.ts.map +1 -1
  5. package/dist/actions/index.js +6 -0
  6. package/dist/components/_base/field-styles.d.ts +51 -16
  7. package/dist/components/_base/field-styles.d.ts.map +1 -1
  8. package/dist/components/_base/field-styles.js +164 -36
  9. package/dist/components/_base/index.d.ts +25 -0
  10. package/dist/components/_base/index.d.ts.map +1 -1
  11. package/dist/components/_base/index.js +25 -0
  12. package/dist/components/_base/interaction-styles.d.ts +39 -12
  13. package/dist/components/_base/interaction-styles.d.ts.map +1 -1
  14. package/dist/components/_base/interaction-styles.js +85 -33
  15. package/dist/components/_base/moni-element.d.ts +43 -8
  16. package/dist/components/_base/moni-element.d.ts.map +1 -1
  17. package/dist/components/_base/moni-element.js +43 -8
  18. package/dist/components/_base/shared-styles.d.ts +41 -17
  19. package/dist/components/_base/shared-styles.d.ts.map +1 -1
  20. package/dist/components/_base/shared-styles.js +113 -21
  21. package/dist/components/index.d.ts +6 -0
  22. package/dist/components/index.d.ts.map +1 -1
  23. package/dist/components/index.js +6 -0
  24. package/dist/components/loading-shapes.d.ts +6 -0
  25. package/dist/components/loading-shapes.d.ts.map +1 -1
  26. package/dist/components/loading-shapes.js +6 -0
  27. package/dist/components/moni-app-bar.d.ts +128 -33
  28. package/dist/components/moni-app-bar.d.ts.map +1 -1
  29. package/dist/components/moni-app-bar.js +121 -26
  30. package/dist/components/moni-badge.d.ts +122 -14
  31. package/dist/components/moni-badge.d.ts.map +1 -1
  32. package/dist/components/moni-badge.js +122 -14
  33. package/dist/components/moni-bottom-sheet.d.ts +120 -15
  34. package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
  35. package/dist/components/moni-bottom-sheet.js +116 -12
  36. package/dist/components/moni-button-group.d.ts +53 -27
  37. package/dist/components/moni-button-group.d.ts.map +1 -1
  38. package/dist/components/moni-button-group.js +49 -23
  39. package/dist/components/moni-button-segment.d.ts +28 -8
  40. package/dist/components/moni-button-segment.d.ts.map +1 -1
  41. package/dist/components/moni-button-segment.js +27 -7
  42. package/dist/components/moni-button.d.ts +51 -32
  43. package/dist/components/moni-button.d.ts.map +1 -1
  44. package/dist/components/moni-button.js +50 -31
  45. package/dist/components/moni-card.d.ts +91 -31
  46. package/dist/components/moni-card.d.ts.map +1 -1
  47. package/dist/components/moni-card.js +86 -26
  48. package/dist/components/moni-carousel.d.ts +67 -17
  49. package/dist/components/moni-carousel.d.ts.map +1 -1
  50. package/dist/components/moni-carousel.js +59 -16
  51. package/dist/components/moni-checkbox.d.ts +122 -17
  52. package/dist/components/moni-checkbox.d.ts.map +1 -1
  53. package/dist/components/moni-checkbox.js +118 -14
  54. package/dist/components/moni-chip.d.ts +56 -30
  55. package/dist/components/moni-chip.d.ts.map +1 -1
  56. package/dist/components/moni-chip.js +51 -25
  57. package/dist/components/moni-color-field.d.ts +44 -6
  58. package/dist/components/moni-color-field.d.ts.map +1 -1
  59. package/dist/components/moni-color-field.js +43 -5
  60. package/dist/components/moni-context-menu.d.ts +44 -22
  61. package/dist/components/moni-context-menu.d.ts.map +1 -1
  62. package/dist/components/moni-context-menu.js +43 -21
  63. package/dist/components/moni-dialog.d.ts +107 -15
  64. package/dist/components/moni-dialog.d.ts.map +1 -1
  65. package/dist/components/moni-dialog.js +105 -14
  66. package/dist/components/moni-divider.d.ts +50 -15
  67. package/dist/components/moni-divider.d.ts.map +1 -1
  68. package/dist/components/moni-divider.js +49 -14
  69. package/dist/components/moni-expansion.d.ts +44 -8
  70. package/dist/components/moni-expansion.d.ts.map +1 -1
  71. package/dist/components/moni-expansion.js +43 -7
  72. package/dist/components/moni-fab-menu.d.ts +39 -20
  73. package/dist/components/moni-fab-menu.d.ts.map +1 -1
  74. package/dist/components/moni-fab-menu.js +38 -19
  75. package/dist/components/moni-fab.d.ts +49 -23
  76. package/dist/components/moni-fab.d.ts.map +1 -1
  77. package/dist/components/moni-fab.js +46 -20
  78. package/dist/components/moni-file-field.d.ts +54 -14
  79. package/dist/components/moni-file-field.d.ts.map +1 -1
  80. package/dist/components/moni-file-field.js +53 -13
  81. package/dist/components/moni-icon.d.ts +78 -11
  82. package/dist/components/moni-icon.d.ts.map +1 -1
  83. package/dist/components/moni-icon.js +77 -10
  84. package/dist/components/moni-list-item.d.ts +61 -30
  85. package/dist/components/moni-list-item.d.ts.map +1 -1
  86. package/dist/components/moni-list-item.js +55 -24
  87. package/dist/components/moni-list.d.ts +37 -13
  88. package/dist/components/moni-list.d.ts.map +1 -1
  89. package/dist/components/moni-list.js +36 -12
  90. package/dist/components/moni-loading-indicator.d.ts +38 -11
  91. package/dist/components/moni-loading-indicator.d.ts.map +1 -1
  92. package/dist/components/moni-loading-indicator.js +37 -10
  93. package/dist/components/moni-menu-item.d.ts +31 -8
  94. package/dist/components/moni-menu-item.d.ts.map +1 -1
  95. package/dist/components/moni-menu-item.js +30 -7
  96. package/dist/components/moni-menu.d.ts +58 -33
  97. package/dist/components/moni-menu.d.ts.map +1 -1
  98. package/dist/components/moni-menu.js +51 -26
  99. package/dist/components/moni-morph-modal.d.ts +7 -1
  100. package/dist/components/moni-morph-modal.d.ts.map +1 -1
  101. package/dist/components/moni-morph-modal.js +46 -24
  102. package/dist/components/moni-nav-item.d.ts +50 -10
  103. package/dist/components/moni-nav-item.d.ts.map +1 -1
  104. package/dist/components/moni-nav-item.js +48 -8
  105. package/dist/components/moni-nav.d.ts +57 -22
  106. package/dist/components/moni-nav.d.ts.map +1 -1
  107. package/dist/components/moni-nav.js +53 -18
  108. package/dist/components/moni-progress.d.ts +108 -20
  109. package/dist/components/moni-progress.d.ts.map +1 -1
  110. package/dist/components/moni-progress.js +104 -16
  111. package/dist/components/moni-radio.d.ts +106 -14
  112. package/dist/components/moni-radio.d.ts.map +1 -1
  113. package/dist/components/moni-radio.js +104 -13
  114. package/dist/components/moni-ripple.d.ts +121 -10
  115. package/dist/components/moni-ripple.d.ts.map +1 -1
  116. package/dist/components/moni-ripple.js +120 -9
  117. package/dist/components/moni-segmented-button.d.ts +31 -11
  118. package/dist/components/moni-segmented-button.d.ts.map +1 -1
  119. package/dist/components/moni-segmented-button.js +30 -10
  120. package/dist/components/moni-select-option.d.ts +43 -9
  121. package/dist/components/moni-select-option.d.ts.map +1 -1
  122. package/dist/components/moni-select-option.js +41 -7
  123. package/dist/components/moni-select.d.ts +59 -2
  124. package/dist/components/moni-select.d.ts.map +1 -1
  125. package/dist/components/moni-select.js +58 -1
  126. package/dist/components/moni-shape.d.ts +1 -1
  127. package/dist/components/moni-side-sheet.d.ts +56 -19
  128. package/dist/components/moni-side-sheet.d.ts.map +1 -1
  129. package/dist/components/moni-side-sheet.js +53 -16
  130. package/dist/components/moni-slider.d.ts +56 -25
  131. package/dist/components/moni-slider.d.ts.map +1 -1
  132. package/dist/components/moni-slider.js +55 -24
  133. package/dist/components/moni-snackbar.d.ts +86 -17
  134. package/dist/components/moni-snackbar.d.ts.map +1 -1
  135. package/dist/components/moni-snackbar.js +85 -16
  136. package/dist/components/moni-split-button.d.ts +38 -9
  137. package/dist/components/moni-split-button.d.ts.map +1 -1
  138. package/dist/components/moni-split-button.js +37 -8
  139. package/dist/components/moni-step.d.ts +42 -9
  140. package/dist/components/moni-step.d.ts.map +1 -1
  141. package/dist/components/moni-step.js +41 -8
  142. package/dist/components/moni-stepper.d.ts +43 -6
  143. package/dist/components/moni-stepper.d.ts.map +1 -1
  144. package/dist/components/moni-stepper.js +42 -5
  145. package/dist/components/moni-switch.d.ts +103 -16
  146. package/dist/components/moni-switch.d.ts.map +1 -1
  147. package/dist/components/moni-switch.js +99 -13
  148. package/dist/components/moni-tab.d.ts +35 -8
  149. package/dist/components/moni-tab.d.ts.map +1 -1
  150. package/dist/components/moni-tab.js +34 -7
  151. package/dist/components/moni-tabs.d.ts +51 -13
  152. package/dist/components/moni-tabs.d.ts.map +1 -1
  153. package/dist/components/moni-tabs.js +48 -10
  154. package/dist/components/moni-text-field.d.ts +55 -10
  155. package/dist/components/moni-text-field.d.ts.map +1 -1
  156. package/dist/components/moni-text-field.js +54 -9
  157. package/dist/components/moni-textarea.d.ts +51 -21
  158. package/dist/components/moni-textarea.d.ts.map +1 -1
  159. package/dist/components/moni-textarea.js +48 -18
  160. package/dist/components/moni-time-picker.d.ts +41 -11
  161. package/dist/components/moni-time-picker.d.ts.map +1 -1
  162. package/dist/components/moni-time-picker.js +40 -10
  163. package/dist/components/moni-toolbar.d.ts +43 -15
  164. package/dist/components/moni-toolbar.d.ts.map +1 -1
  165. package/dist/components/moni-toolbar.js +42 -14
  166. package/dist/components/moni-tooltip.d.ts +55 -25
  167. package/dist/components/moni-tooltip.d.ts.map +1 -1
  168. package/dist/components/moni-tooltip.js +54 -24
  169. package/dist/components/moni-typography.d.ts +43 -18
  170. package/dist/components/moni-typography.d.ts.map +1 -1
  171. package/dist/components/moni-typography.js +42 -17
  172. package/dist/index.d.ts +47 -0
  173. package/dist/index.d.ts.map +1 -1
  174. package/dist/index.js +59 -2
  175. package/dist/styles/tailwind.css +67 -0
  176. package/dist/styles/tokens.css +111 -99
  177. package/dist/utils/color.d.ts +181 -2
  178. package/dist/utils/color.d.ts.map +1 -1
  179. package/dist/utils/color.js +182 -4
  180. package/dist/utils/theme.svelte.d.ts +305 -2
  181. package/dist/utils/theme.svelte.d.ts.map +1 -1
  182. package/dist/utils/theme.svelte.js +331 -2
  183. package/dist/web-components.d.ts +28 -0
  184. package/dist/web-components.d.ts.map +1 -1
  185. package/dist/web-components.js +29 -2
  186. package/package.json +1 -1
  187. package/src/actions/index.ts +7 -0
  188. package/src/components/_base/field-styles.ts +165 -37
  189. package/src/components/_base/index.ts +27 -0
  190. package/src/components/_base/interaction-styles.ts +86 -33
  191. package/src/components/_base/moni-element.ts +44 -8
  192. package/src/components/_base/shared-styles.ts +114 -21
  193. package/src/components/index.ts +7 -0
  194. package/src/components/loading-shapes.ts +7 -0
  195. package/src/components/moni-app-bar.ts +127 -26
  196. package/src/components/moni-badge.ts +128 -14
  197. package/src/components/moni-bottom-sheet.ts +125 -13
  198. package/src/components/moni-button-group.ts +50 -23
  199. package/src/components/moni-button-segment.ts +28 -7
  200. package/src/components/moni-button.ts +51 -31
  201. package/src/components/moni-card.ts +90 -26
  202. package/src/components/moni-carousel.ts +67 -16
  203. package/src/components/moni-checkbox.ts +125 -14
  204. package/src/components/moni-chip.ts +52 -25
  205. package/src/components/moni-color-field.ts +44 -5
  206. package/src/components/moni-context-menu.ts +44 -21
  207. package/src/components/moni-dialog.ts +111 -14
  208. package/src/components/moni-divider.ts +50 -14
  209. package/src/components/moni-expansion.ts +44 -7
  210. package/src/components/moni-fab-menu.ts +39 -19
  211. package/src/components/moni-fab.ts +47 -20
  212. package/src/components/moni-file-field.ts +54 -13
  213. package/src/components/moni-icon.ts +80 -10
  214. package/src/components/moni-list-item.ts +56 -24
  215. package/src/components/moni-list.ts +37 -12
  216. package/src/components/moni-loading-indicator.ts +38 -10
  217. package/src/components/moni-menu-item.ts +31 -7
  218. package/src/components/moni-menu.ts +52 -26
  219. package/src/components/moni-morph-modal.ts +58 -24
  220. package/src/components/moni-nav-item.ts +49 -8
  221. package/src/components/moni-nav.ts +54 -18
  222. package/src/components/moni-progress.ts +109 -16
  223. package/src/components/moni-radio.ts +111 -13
  224. package/src/components/moni-ripple.ts +126 -9
  225. package/src/components/moni-segmented-button.ts +31 -10
  226. package/src/components/moni-select-option.ts +42 -7
  227. package/src/components/moni-select.ts +79 -1
  228. package/src/components/moni-side-sheet.ts +54 -16
  229. package/src/components/moni-slider.ts +56 -24
  230. package/src/components/moni-snackbar.ts +90 -16
  231. package/src/components/moni-split-button.ts +38 -8
  232. package/src/components/moni-step.ts +42 -8
  233. package/src/components/moni-stepper.ts +43 -5
  234. package/src/components/moni-switch.ts +106 -13
  235. package/src/components/moni-tab.ts +35 -7
  236. package/src/components/moni-tabs.ts +49 -10
  237. package/src/components/moni-text-field.ts +55 -9
  238. package/src/components/moni-textarea.ts +49 -18
  239. package/src/components/moni-time-picker.ts +41 -10
  240. package/src/components/moni-toolbar.ts +43 -14
  241. package/src/components/moni-tooltip.ts +55 -24
  242. package/src/components/moni-typography.ts +43 -17
  243. package/src/index.ts +67 -3
  244. package/src/styles/tailwind.css +67 -0
  245. package/src/styles/tokens.css +111 -99
  246. package/src/types/svelte-runes.d.ts +64 -2
  247. package/src/utils/color.ts +286 -5
  248. package/src/utils/theme.svelte.ts +411 -2
  249. package/src/web-components.ts +31 -2
  250. package/dist/assets/shapes/arch.svg +0 -1
  251. package/dist/assets/shapes/arrow.svg +0 -1
  252. package/dist/assets/shapes/boom.svg +0 -1
  253. package/dist/assets/shapes/burst.svg +0 -1
  254. package/dist/assets/shapes/circle.svg +0 -1
  255. package/dist/assets/shapes/clamshell.svg +0 -1
  256. package/dist/assets/shapes/diamond.svg +0 -1
  257. package/dist/assets/shapes/fan.svg +0 -1
  258. package/dist/assets/shapes/flower.svg +0 -1
  259. package/dist/assets/shapes/gem.svg +0 -1
  260. package/dist/assets/shapes/ghost-ish.svg +0 -1
  261. package/dist/assets/shapes/heart.svg +0 -1
  262. package/dist/assets/shapes/leaf-clover4.svg +0 -1
  263. package/dist/assets/shapes/leaf-clover8.svg +0 -1
  264. package/dist/assets/shapes/loading-indicator.svg +0 -1
  265. package/dist/assets/shapes/oval.svg +0 -1
  266. package/dist/assets/shapes/pentagon.svg +0 -1
  267. package/dist/assets/shapes/pill.svg +0 -1
  268. package/dist/assets/shapes/pixel-circle.svg +0 -1
  269. package/dist/assets/shapes/pixel-triangle.svg +0 -1
  270. package/dist/assets/shapes/puffy-diamond.svg +0 -1
  271. package/dist/assets/shapes/puffy.svg +0 -1
  272. package/dist/assets/shapes/semicircle.svg +0 -1
  273. package/dist/assets/shapes/sided-cookie12.svg +0 -1
  274. package/dist/assets/shapes/sided-cookie4.svg +0 -1
  275. package/dist/assets/shapes/sided-cookie6.svg +0 -1
  276. package/dist/assets/shapes/sided-cookie7.svg +0 -1
  277. package/dist/assets/shapes/sided-cookie9.svg +0 -1
  278. package/dist/assets/shapes/slanted.svg +0 -1
  279. package/dist/assets/shapes/soft-boom.svg +0 -1
  280. package/dist/assets/shapes/soft-burst.svg +0 -1
  281. package/dist/assets/shapes/square.svg +0 -1
  282. package/dist/assets/shapes/sunny.svg +0 -1
  283. package/dist/assets/shapes/triangle.svg +0 -1
  284. package/dist/assets/shapes/very-sunny.svg +0 -1
  285. package/dist/assets/shapes/wavy-circle.svg +0 -1
  286. package/dist/assets/shapes/wavy.svg +0 -1
  287. package/src/assets/shapes/arch.svg +0 -1
  288. package/src/assets/shapes/arrow.svg +0 -1
  289. package/src/assets/shapes/boom.svg +0 -1
  290. package/src/assets/shapes/burst.svg +0 -1
  291. package/src/assets/shapes/circle.svg +0 -1
  292. package/src/assets/shapes/clamshell.svg +0 -1
  293. package/src/assets/shapes/diamond.svg +0 -1
  294. package/src/assets/shapes/fan.svg +0 -1
  295. package/src/assets/shapes/flower.svg +0 -1
  296. package/src/assets/shapes/gem.svg +0 -1
  297. package/src/assets/shapes/ghost-ish.svg +0 -1
  298. package/src/assets/shapes/heart.svg +0 -1
  299. package/src/assets/shapes/leaf-clover4.svg +0 -1
  300. package/src/assets/shapes/leaf-clover8.svg +0 -1
  301. package/src/assets/shapes/loading-indicator.svg +0 -1
  302. package/src/assets/shapes/oval.svg +0 -1
  303. package/src/assets/shapes/pentagon.svg +0 -1
  304. package/src/assets/shapes/pill.svg +0 -1
  305. package/src/assets/shapes/pixel-circle.svg +0 -1
  306. package/src/assets/shapes/pixel-triangle.svg +0 -1
  307. package/src/assets/shapes/puffy-diamond.svg +0 -1
  308. package/src/assets/shapes/puffy.svg +0 -1
  309. package/src/assets/shapes/semicircle.svg +0 -1
  310. package/src/assets/shapes/sided-cookie12.svg +0 -1
  311. package/src/assets/shapes/sided-cookie4.svg +0 -1
  312. package/src/assets/shapes/sided-cookie6.svg +0 -1
  313. package/src/assets/shapes/sided-cookie7.svg +0 -1
  314. package/src/assets/shapes/sided-cookie9.svg +0 -1
  315. package/src/assets/shapes/slanted.svg +0 -1
  316. package/src/assets/shapes/soft-boom.svg +0 -1
  317. package/src/assets/shapes/soft-burst.svg +0 -1
  318. package/src/assets/shapes/square.svg +0 -1
  319. package/src/assets/shapes/sunny.svg +0 -1
  320. package/src/assets/shapes/triangle.svg +0 -1
  321. package/src/assets/shapes/very-sunny.svg +0 -1
  322. package/src/assets/shapes/wavy-circle.svg +0 -1
  323. package/src/assets/shapes/wavy.svg +0 -1
@@ -1,2 +1,8 @@
1
+ /**
2
+ * @file actions/index.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
1
7
  export {};
2
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/actions/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,CAAC"}
@@ -1 +1,7 @@
1
+ /**
2
+ * @file actions/index.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
1
7
  export {};
@@ -1,23 +1,58 @@
1
1
  /**
2
- * Shared visual rules for every field-like input shell.
2
+ * @file components/_base/field-styles.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
7
+ /**
8
+ * Shared visual rules for all field-like input components.
9
+ *
10
+ * This stylesheet provides the complete CSS foundation for the Moni input
11
+ * field pattern, ported and extended from the BeerCSS field system. It is
12
+ * consumed by: `moni-text-field`, `moni-textarea`, `moni-select`,
13
+ * `moni-color-field`, and `moni-file-field`.
14
+ *
15
+ * **Required DOM structure:**
16
+ * Each consumer must render this exact DOM hierarchy inside its shadow root for
17
+ * all selectors (especially the floating label) to function correctly:
18
+ *
19
+ * ```html
20
+ * <div class="field [label] [fill|border] [small|large|extra] [prefix|suffix|icon] [invalid] [round*]">
21
+ * <i class="leading-icon">...</i> <!-- optional leading icon -->
22
+ * <input | select | textarea> <!-- native form control -->
23
+ * <label>Label text</label> <!-- MUST be immediately after the control -->
24
+ * <i class="trailing-icon">...</i> <!-- optional trailing icon -->
25
+ * <span class="suffix-text">...</span> <!-- optional suffix text -->
26
+ * <slot name="trailing"></slot> <!-- optional trailing slot -->
27
+ * <output>Helper or error text</output> <!-- helper / validation message -->
28
+ * </div>
29
+ * ```
30
+ *
31
+ * **Critical ordering rule:**
32
+ * The `<label>` element MUST be the immediate next sibling of the
33
+ * `<input|select|textarea>`. The CSS adjacent sibling combinator (`+ label`)
34
+ * and the `:focus + label` selector depend on this ordering to animate the
35
+ * floating label lift. Breaking the order will prevent the label from animating.
3
36
  *
4
- * Direct port of `beercss-CDN/elements/fields.css`. Each consumer (text-field,
5
- * textarea, select, color-field, file-field) is expected to render a DOM tree
6
- * of the form:
37
+ * **Modifier classes:**
38
+ * - `.label` — Activates the floating label behavior.
39
+ * - `.fill` — Uses `surface-container-highest` as the input background (filled style).
40
+ * - `.border` — Applies an `outline-variant` border (outlined style).
41
+ * - `.small` / `.large` / `.extra` — Adjusts height and padding.
42
+ * - `.prefix` / `.suffix` — Shifts input padding to make room for icons.
43
+ * - `.invalid` — Applies error color to borders, label, and helper text.
44
+ * - `.round` / `.round-*` — Applies pill-shaped border radius to the field.
45
+ * - `.square` — Removes all border-radius (overrides everything via `!important`).
7
46
  *
8
- * <div class="field label fill|small|large|extra|prefix|icon|suffix|invalid">
9
- * [leading <i class="leading-icon">] optional
10
- * <input|select|textarea> ← input area
11
- * <label> ← immediate next sibling (for label lift)
12
- * [trailing <i class="trailing-icon">] optional
13
- * [suffix text] ← optional
14
- * <slot name="trailing"> ← optional slot
15
- * <output> ← helper text or error
16
- * </div>
47
+ * **Internal CSS custom properties:**
48
+ * | Property | Default | Description |
49
+ * |------------|---------|------------------------------------------|
50
+ * | `--_input` | `3rem` | Height of the input area. |
51
+ * | `--_start` | `1.2rem`| Block-start padding for label alignment. |
52
+ * | `--_middle`| computed| Vertical center of the input (for icons).|
17
53
  *
18
- * The selector order is rigid: input must be followed by label so the
19
- * `+ label` and `:focus + label` selectors in BeerCSS can lift the floating
20
- * label. If a component reorders the DOM, the label may not animate properly.
54
+ * @see {@link sharedStyles} — Token bridge consumed by this stylesheet.
55
+ * @see {@link interactionStyles} — State layer (not used directly in fields).
21
56
  */
22
57
  export declare const fieldStyles: import("lit").CSSResult;
23
58
  export default fieldStyles;
@@ -1 +1 @@
1
- {"version":3,"file":"field-styles.d.ts","sourceRoot":"","sources":["../../../src/components/_base/field-styles.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,WAAW,yBAgevB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"field-styles.d.ts","sourceRoot":"","sources":["../../../src/components/_base/field-styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,eAAO,MAAM,WAAW,yBA6jBvB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,35 +1,77 @@
1
+ /**
2
+ * @file components/_base/field-styles.ts
3
+ * @package @moni-labs/moni-ui
4
+ * @license MIT
5
+ * @contributors Moni Labs & Contributors
6
+ */
1
7
  import { css } from 'lit';
2
8
  /**
3
- * Shared visual rules for every field-like input shell.
9
+ * Shared visual rules for all field-like input components.
10
+ *
11
+ * This stylesheet provides the complete CSS foundation for the Moni input
12
+ * field pattern, ported and extended from the BeerCSS field system. It is
13
+ * consumed by: `moni-text-field`, `moni-textarea`, `moni-select`,
14
+ * `moni-color-field`, and `moni-file-field`.
15
+ *
16
+ * **Required DOM structure:**
17
+ * Each consumer must render this exact DOM hierarchy inside its shadow root for
18
+ * all selectors (especially the floating label) to function correctly:
19
+ *
20
+ * ```html
21
+ * <div class="field [label] [fill|border] [small|large|extra] [prefix|suffix|icon] [invalid] [round*]">
22
+ * <i class="leading-icon">...</i> <!-- optional leading icon -->
23
+ * <input | select | textarea> <!-- native form control -->
24
+ * <label>Label text</label> <!-- MUST be immediately after the control -->
25
+ * <i class="trailing-icon">...</i> <!-- optional trailing icon -->
26
+ * <span class="suffix-text">...</span> <!-- optional suffix text -->
27
+ * <slot name="trailing"></slot> <!-- optional trailing slot -->
28
+ * <output>Helper or error text</output> <!-- helper / validation message -->
29
+ * </div>
30
+ * ```
31
+ *
32
+ * **Critical ordering rule:**
33
+ * The `<label>` element MUST be the immediate next sibling of the
34
+ * `<input|select|textarea>`. The CSS adjacent sibling combinator (`+ label`)
35
+ * and the `:focus + label` selector depend on this ordering to animate the
36
+ * floating label lift. Breaking the order will prevent the label from animating.
4
37
  *
5
- * Direct port of `beercss-CDN/elements/fields.css`. Each consumer (text-field,
6
- * textarea, select, color-field, file-field) is expected to render a DOM tree
7
- * of the form:
38
+ * **Modifier classes:**
39
+ * - `.label` — Activates the floating label behavior.
40
+ * - `.fill` — Uses `surface-container-highest` as the input background (filled style).
41
+ * - `.border` — Applies an `outline-variant` border (outlined style).
42
+ * - `.small` / `.large` / `.extra` — Adjusts height and padding.
43
+ * - `.prefix` / `.suffix` — Shifts input padding to make room for icons.
44
+ * - `.invalid` — Applies error color to borders, label, and helper text.
45
+ * - `.round` / `.round-*` — Applies pill-shaped border radius to the field.
46
+ * - `.square` — Removes all border-radius (overrides everything via `!important`).
8
47
  *
9
- * <div class="field label fill|small|large|extra|prefix|icon|suffix|invalid">
10
- * [leading <i class="leading-icon">] optional
11
- * <input|select|textarea> ← input area
12
- * <label> ← immediate next sibling (for label lift)
13
- * [trailing <i class="trailing-icon">] optional
14
- * [suffix text] ← optional
15
- * <slot name="trailing"> ← optional slot
16
- * <output> ← helper text or error
17
- * </div>
48
+ * **Internal CSS custom properties:**
49
+ * | Property | Default | Description |
50
+ * |------------|---------|------------------------------------------|
51
+ * | `--_input` | `3rem` | Height of the input area. |
52
+ * | `--_start` | `1.2rem`| Block-start padding for label alignment. |
53
+ * | `--_middle`| computed| Vertical center of the input (for icons).|
18
54
  *
19
- * The selector order is rigid: input must be followed by label so the
20
- * `+ label` and `:focus + label` selectors in BeerCSS can lift the floating
21
- * label. If a component reorders the DOM, the label may not animate properly.
55
+ * @see {@link sharedStyles} — Token bridge consumed by this stylesheet.
56
+ * @see {@link interactionStyles} — State layer (not used directly in fields).
22
57
  */
23
58
  export const fieldStyles = css `
24
59
  :host {
25
60
  display: block;
61
+ /* Fields are full-width by default; the parent layout controls sizing. */
26
62
  inline-size: 100%;
27
63
  }
28
64
 
65
+ /* ─── Base field container ───────────────────────────────────────────────── */
29
66
  .field {
67
+ /* Internal height token — overridden by size modifiers (.small, .large, .extra). */
30
68
  --_input: 3rem;
69
+ /* Vertical start offset used for textarea padding and label positioning. */
31
70
  --_start: 1.2rem;
71
+ /* Computed vertical center — used to position absolutely-placed icons. */
32
72
  --_middle: calc(var(--_input, 0) / 2);
73
+
74
+ /* Default field shape: bottom border only (BeerCSS / MD3 "filled" style). */
33
75
  border-radius: 0.25rem 0.25rem 0 0;
34
76
  min-block-size: var(--_input);
35
77
  display: flex;
@@ -38,17 +80,22 @@ export const fieldStyles = css `
38
80
  inline-size: 100%;
39
81
  }
40
82
 
41
- /* Square overrides anything (border, round variants) via !important. */
83
+ /* ─── Shape overrides ────────────────────────────────────────────────────── */
84
+
85
+ /* Square: removes all border-radius regardless of other modifiers.
86
+ Uses !important to win specificity over .border and [class*='round']. */
42
87
  .field.square,
43
88
  .field.square.border,
44
89
  .field.square[class*='round'] {
45
90
  border-radius: 0 !important;
46
91
  }
47
-
48
92
  .field.square > :is(input, textarea, select) {
49
93
  border-radius: 0 !important;
50
94
  }
51
95
 
96
+ /* ─── Fill variant ───────────────────────────────────────────────────────── */
97
+ /* Unsets background/color on the container; the background is applied
98
+ directly to the <input> so that the floating label overlaps it correctly. */
52
99
  .field.fill {
53
100
  --_background: var(--surface-container-highest);
54
101
  background-color: unset !important;
@@ -56,9 +103,11 @@ export const fieldStyles = css `
56
103
  }
57
104
  .field.fill > :is(input, select, textarea) {
58
105
  background-color: var(--_background);
106
+ /* z-index: 0 ensures the background renders above the ::before layer. */
59
107
  z-index: 0;
60
108
  }
61
109
 
110
+ /* ─── Size variants ──────────────────────────────────────────────────────── */
62
111
  .field.small {
63
112
  --_input: 2.5rem;
64
113
  --_start: 1rem;
@@ -72,10 +121,14 @@ export const fieldStyles = css `
72
121
  --_start: 1.6rem;
73
122
  }
74
123
 
124
+ /* ─── Border (outlined) variant ─────────────────────────────────────────── */
125
+ /* Adds full border-radius and outline-variant stroke on all four sides. */
75
126
  .field.border {
76
127
  border-radius: 0.25rem;
77
128
  }
78
129
 
130
+ /* ─── Round / pill variants ──────────────────────────────────────────────── */
131
+ /* Applied when class matches the 'round' substring (e.g. .round, .round-sm). */
79
132
  .field[class*='round'].small {
80
133
  border-radius: 1.25rem;
81
134
  }
@@ -89,10 +142,8 @@ export const fieldStyles = css `
89
142
  border-radius: 2rem;
90
143
  }
91
144
 
92
- /* Generic icon baseline (BeerCSS: .field > :is(i, img, svg, progress.circle, a)).
93
- The explicit .leading-icon / .trailing-icon classes below win over
94
- the position-suffix selectors and guarantee correct placement even when
95
- the icon is wrapped in a custom element (e.g. <moni-icon>). */
145
+ /* ─── Icon positioning ───────────────────────────────────────────────────── */
146
+ /* Generic rule: absolutely positions any icon/image/svg inside the field. */
96
147
  .field > :is(i, img, svg) {
97
148
  position: absolute;
98
149
  inset: calc((var(--_input, 0) / 2) - 0.75rem) auto auto auto;
@@ -103,31 +154,37 @@ export const fieldStyles = css `
103
154
  margin: auto 0;
104
155
  pointer-events: none;
105
156
  }
157
+ /* Leading icon: explicit class wins over :first-child heuristic. */
106
158
  .field > :is(i, img, svg):first-child,
107
159
  .field > .leading-icon {
108
160
  inset: calc(var(--_middle, 0) - 0.75rem) auto auto 1rem;
109
161
  }
110
162
 
111
- /* Trailing icon: BeerCSS uses :last-child:not(:first-child) which fails
112
- when an output follows. The class selectors below always win and
113
- guarantee correct positioning on the right edge. */
163
+ /* Trailing icon: BeerCSS uses :last-child:not(:first-child) which fails when
164
+ an <output> follows the icon. The explicit class always wins and places
165
+ the icon on the right edge regardless of sibling count. */
114
166
  .field > :is(i, img, svg):last-child:not(:first-child),
115
167
  .field > .trailing-icon {
116
168
  inset: calc(var(--_middle, 0) - 0.75rem) 1rem auto auto;
169
+ /* Prevent the inline-start override from the generic rule above. */
117
170
  inset-inline-start: auto !important;
118
171
  }
119
172
 
173
+ /* Error state: trailing icons inherit the error color. */
120
174
  .field.invalid > i {
121
175
  color: var(--error);
122
176
  }
123
177
 
124
- /* Input / textarea / select — native form elements get a full reset. */
178
+ /* ─── Native form element reset ──────────────────────────────────────────── */
179
+ /* 'all: unset' strips browser-default styles (appearance, border, font, etc.)
180
+ so the field's visual design is fully controlled by Moni's CSS. */
125
181
  .field > :is(input, textarea, select) {
126
182
  all: unset;
127
183
  position: relative;
128
184
  display: block;
129
185
  box-sizing: border-box;
130
186
  border-radius: inherit;
187
+ /* Default border is transparent; visible only in .border and focus states. */
131
188
  border: 0.0625rem solid transparent;
132
189
  padding: 0 0.9375rem;
133
190
  font-family: inherit;
@@ -136,30 +193,42 @@ export const fieldStyles = css `
136
193
  outline: none;
137
194
  z-index: 1;
138
195
  background: none;
139
- resize: none;
196
+ resize: none; /* Textareas use field-sizing:content instead of manual resize. */
140
197
  text-align: start;
141
198
  cursor: text;
142
199
  color: var(--on-surface);
143
200
  }
144
201
 
202
+ /* Ensure date/time input values align to start (browser quirk on some platforms). */
145
203
  input::-webkit-date-and-time-value {
146
204
  text-align: start;
147
205
  }
206
+
207
+ /* Autofill: preserve text color when the browser applies its autofill highlight.
208
+ -webkit-background-clip + -webkit-text-fill-color override the yellow tint. */
148
209
  :is(input, select, textarea):is(:-webkit-autofill, :autofill) {
149
210
  -webkit-background-clip: text;
150
211
  -webkit-text-fill-color: var(--on-surface);
151
212
  }
152
213
 
214
+ /* On focus, increase border width by 1px — shift padding inward by 1px
215
+ to prevent layout shift from the border width change. */
153
216
  .field > :is(input, textarea, select):focus {
154
217
  border: 0.125rem solid transparent;
155
218
  padding-inline: 0.875rem;
156
219
  }
157
220
 
221
+ /* Textareas without explicit rows grow automatically using field-sizing:content.
222
+ A max-height of 12rem (~8 lines) prevents uncontrolled page growth. */
158
223
  .field > textarea:not([rows]) {
159
224
  field-sizing: content;
160
225
  max-block-size: 12rem;
161
226
  }
162
227
 
228
+ /* ─── Transparent native picker controls ─────────────────────────────────── */
229
+ /* File and color inputs, and date/time picker indicators are hidden so the
230
+ component can render its own UI. The native controls are still active for
231
+ accessibility (click propagates through the transparent overlay). */
163
232
  input[type='file'],
164
233
  input[type='color'],
165
234
  :not(.field) > input:is([type^='date'], [type^='time'], [type='month'], [type='week']),
@@ -176,12 +245,15 @@ export const fieldStyles = css `
176
245
  z-index: 2 !important;
177
246
  }
178
247
 
248
+ /* On fine-pointer (mouse) devices, push the calendar picker indicator behind
249
+ the field content so it doesn't interfere with other clickable elements. */
179
250
  @media (pointer: fine) {
180
251
  .field > input::-webkit-calendar-picker-indicator {
181
252
  z-index: -1 !important;
182
253
  }
183
254
  }
184
255
 
256
+ /* Remove browser-native search field decorations. */
185
257
  input::-webkit-search-decoration,
186
258
  input::-webkit-search-cancel-button,
187
259
  input::-webkit-search-results-button,
@@ -191,10 +263,12 @@ export const fieldStyles = css `
191
263
  display: none;
192
264
  }
193
265
 
266
+ /* Remove the browser spinner on number inputs — use explicit stepper UI instead. */
194
267
  input[type='number'] {
195
268
  appearance: textfield;
196
269
  }
197
270
 
271
+ /* ─── Border variant: field-level border colors ──────────────────────────── */
198
272
  .field.border > :is(input, textarea, select) {
199
273
  border-color: var(--outline);
200
274
  }
@@ -202,6 +276,7 @@ export const fieldStyles = css `
202
276
  border-color: var(--primary);
203
277
  }
204
278
 
279
+ /* Round variants add extra inline padding to clear the curved edges. */
205
280
  .field[class*='round'] > :is(input, textarea, select) {
206
281
  padding-inline: 1.4376rem;
207
282
  }
@@ -209,13 +284,14 @@ export const fieldStyles = css `
209
284
  padding-inline: 1.375rem;
210
285
  }
211
286
 
287
+ /* ─── Icon padding accommodation ─────────────────────────────────────────── */
288
+ /* .prefix / .suffix shift the input's inline padding to make room for icons. */
212
289
  .field.prefix > :is(input, textarea, select) {
213
290
  padding-inline-start: 2.9375rem;
214
291
  }
215
292
  .field.prefix > :is(input, textarea, select):focus {
216
293
  padding-inline-start: 2.875rem;
217
294
  }
218
-
219
295
  .field.suffix > :is(input, textarea, select) {
220
296
  padding-inline-end: 2.9375rem;
221
297
  }
@@ -223,6 +299,8 @@ export const fieldStyles = css `
223
299
  padding-inline-end: 2.875rem;
224
300
  }
225
301
 
302
+ /* ─── Underline (non-border, non-round) bottom border ─────────────────────── */
303
+ /* Default M3 filled field style: only the bottom border is visible. */
226
304
  .field:not(.border, [class*='round']) > :is(input, textarea, select) {
227
305
  border-block-end-color: var(--outline);
228
306
  }
@@ -230,6 +308,7 @@ export const fieldStyles = css `
230
308
  border-block-end-color: var(--primary);
231
309
  }
232
310
 
311
+ /* Round non-bordered fields get a subtle elevation shadow instead of a border. */
233
312
  .field[class*='round']:not(.border, .fill) > :is(input, textarea, select),
234
313
  .field[class*='round']:not(.border) > :is(input, textarea, select):focus {
235
314
  box-shadow: var(--elevate1);
@@ -238,6 +317,7 @@ export const fieldStyles = css `
238
317
  box-shadow: var(--elevate2);
239
318
  }
240
319
 
320
+ /* ─── Invalid / error state borders ─────────────────────────────────────── */
241
321
  .field.invalid:not(.border, [class*='round']) > :is(input, textarea, select),
242
322
  .field.invalid:not(.border, [class*='round']) > :is(input, textarea, select):focus {
243
323
  border-block-end-color: var(--error);
@@ -247,6 +327,9 @@ export const fieldStyles = css `
247
327
  border-color: var(--error);
248
328
  }
249
329
 
330
+ /* ─── Disabled state ─────────────────────────────────────────────────────── */
331
+ /* Reduces opacity on the entire field container when the native control is
332
+ disabled, rather than applying separate rules to each child. */
250
333
  .field:has(> :disabled) {
251
334
  opacity: 0.5;
252
335
  cursor: not-allowed;
@@ -255,6 +338,8 @@ export const fieldStyles = css `
255
338
  cursor: not-allowed;
256
339
  }
257
340
 
341
+ /* ─── Select element ─────────────────────────────────────────────────────── */
342
+ /* Remove browser-native select appearance; the component renders its own dropdown. */
258
343
  .field > select {
259
344
  user-select: none;
260
345
  appearance: none;
@@ -262,17 +347,23 @@ export const fieldStyles = css `
262
347
  background-image: none;
263
348
  }
264
349
 
350
+ /* ─── Block-start padding for label accommodation ────────────────────────── */
351
+ /* Inputs with a floating label need top padding to create space for the
352
+ label when it lifts above the input. Selects always lift their label. */
265
353
  .field > :is(input, select) {
266
354
  padding-block-start: 1rem;
267
355
  }
356
+ /* No-label and border+fill fields: remove the top padding offset. */
268
357
  .field:not(.label) > :is(input, select),
269
358
  .field.border:not(.fill) > :is(input, select) {
270
359
  padding-block-start: 0;
271
360
  }
361
+ /* Textareas use the --_start token to align with the label baseline. */
272
362
  .field > textarea {
273
363
  padding-block-start: var(--_start) !important;
274
364
  }
275
365
  .field > textarea:focus {
366
+ /* 0.01rem compensates for the border width increase on focus. */
276
367
  padding-block-start: calc(var(--_start, 0) - 0.01rem) !important;
277
368
  }
278
369
  .field:not(.label) > textarea,
@@ -284,29 +375,42 @@ export const fieldStyles = css `
284
375
  padding-block-start: calc(var(--_start, 0) - 0.51rem) !important;
285
376
  }
286
377
 
287
- /* Floating label */
378
+ /* ─── Floating label ─────────────────────────────────────────────────────── */
379
+ /* The label starts at full font-size (1rem) vertically centered in the field.
380
+ On focus or when value is present, it scales down to 0.75rem and lifts
381
+ to the top of the field container. */
288
382
  .field.label > label {
289
383
  --_start: 1rem;
290
384
  position: absolute;
291
385
  inset: -0.5rem 0.9375rem 0 var(--_start);
292
386
  display: flex;
387
+ /* Full height + 1rem (for label overhang) centers the label vertically. */
293
388
  block-size: calc(var(--_input, 0) + 1rem);
294
389
  line-height: calc(var(--_input, 0) + 1rem);
295
390
  font-size: 1rem;
296
391
  transition: all 0.2s;
297
392
  gap: 0.25rem;
298
393
  white-space: nowrap;
394
+ /* The label is purely decorative from a layout perspective; it must never
395
+ intercept pointer events meant for the underlying input. */
299
396
  pointer-events: none;
300
397
  color: var(--on-surface-variant);
301
398
  }
302
399
 
400
+ /* Round fields: label aligns with the increased inline padding. */
303
401
  .field.label[class*='round'] > label {
304
402
  inset: -0.5rem 1.9375rem 0 var(--_start);
305
403
  }
306
404
 
307
- /* Label lift selectors. Note the inclusion of .active + label so that
308
- readonly inputs (color-field, file-field) still trigger the float when
309
- the consumer sets class=active on the input. */
405
+ /* ─── Label lift selector group ──────────────────────────────────────────── */
406
+ /* The label lifts (scales down + moves up) in four conditions:
407
+ 1. label.active — the component sets this class directly (readonly inputs).
408
+ 2. :focus + label — when the native control is focused.
409
+ 3. [placeholder]:not(:placeholder-shown) + label — when a value is present.
410
+ 4. select + label — selects always show their label lifted.
411
+ 5. input.active + label — for programmatically activated inputs. */
412
+
413
+ /* Border + prefix + no-fill variant needs a reduced --_start offset. */
310
414
  .field.label.border.prefix:not(.fill)
311
415
  > :is(
312
416
  label.active,
@@ -318,6 +422,7 @@ export const fieldStyles = css `
318
422
  --_start: 1rem;
319
423
  }
320
424
 
425
+ /* Round field label and round border prefix field label override. */
321
426
  .field.label[class*='round'] > label,
322
427
  .field.label.border.prefix[class*='round']:not(.fill)
323
428
  > :is(
@@ -330,10 +435,12 @@ export const fieldStyles = css `
330
435
  --_start: 1.5rem;
331
436
  }
332
437
 
438
+ /* Prefix fields: shift the label's inline-start to clear the leading icon. */
333
439
  .field.label.prefix > label {
334
440
  --_start: 3rem;
335
441
  }
336
442
 
443
+ /* Lifted label: shrinks to 0.75rem and collapses to the top of the field. */
337
444
  .field.label
338
445
  > :is(
339
446
  label.active,
@@ -347,6 +454,7 @@ export const fieldStyles = css `
347
454
  font-size: 0.75rem;
348
455
  }
349
456
 
457
+ /* Border variant: label collapses to 1rem height with a notch cut effect. */
350
458
  .field.label.border:not(.fill)
351
459
  > :is(
352
460
  label.active,
@@ -359,6 +467,9 @@ export const fieldStyles = css `
359
467
  line-height: 1rem;
360
468
  }
361
469
 
470
+ /* ─── Border notch (label gap in the top border) ─────────────────────────── */
471
+ /* The ::after pseudo creates the horizontal line to the right of the lifted
472
+ label, visually cutting a notch into the top border of .field.border. */
362
473
  .field.label.border:not(.fill) > label::after {
363
474
  content: '';
364
475
  display: block;
@@ -370,9 +481,14 @@ export const fieldStyles = css `
370
481
  }
371
482
  .field.label.border:not(.fill) > :focus + label::after,
372
483
  .field.label.border:not(.fill) > input.active + label::after {
484
+ /* On focus, the notch line becomes primary-colored. */
373
485
  border-block-start: 0.125rem solid var(--primary);
374
486
  }
375
487
 
488
+ /* ─── Border notch clipping (clip-path) ──────────────────────────────────── */
489
+ /* When the label is lifted, a clip-path cuts a gap in the top border of the
490
+ input element itself, creating the appearance of the label floating within
491
+ the border's top edge. The clip-path dimensions account for label width. */
376
492
  .field.label.border:not(.fill)
377
493
  > :is(input, textarea):is(:focus, [placeholder]:not(:placeholder-shown), .active),
378
494
  .field.label.border:not(.fill) > select,
@@ -390,6 +506,7 @@ export const fieldStyles = css `
390
506
  );
391
507
  }
392
508
 
509
+ /* Prefix variant: clip starts further right to clear the leading icon text. */
393
510
  .field.label.border.prefix:not(.fill)
394
511
  > :is(input, textarea):is(:focus, [placeholder]:not(:placeholder-shown), .active),
395
512
  .field.label.border.prefix:not(.fill) > select,
@@ -407,6 +524,7 @@ export const fieldStyles = css `
407
524
  );
408
525
  }
409
526
 
527
+ /* Round and square border fields use a wider notch to clear the curved border. */
410
528
  .field.label.border[class*='round']:not(.fill)
411
529
  > :is(input, textarea):is(:focus, [placeholder]:not(:placeholder-shown), .active),
412
530
  .field.label.border[class*='round']:not(.fill) > select,
@@ -434,18 +552,22 @@ export const fieldStyles = css `
434
552
  clip-path: polygon(-2% -2%, 1.25rem -2%, 1.25rem 0.5rem, calc(100% - 2rem) 0.5rem, calc(100% - 2rem) -2%, 102% -2%, 102% 102%, -2% 102%);
435
553
  }
436
554
 
555
+ /* ─── Label color changes ─────────────────────────────────────────────────── */
556
+ /* On focus: label turns primary-colored to draw attention. */
437
557
  .field.label > :focus + label,
438
558
  .field.label > input.active + label {
439
559
  color: var(--primary);
440
560
  }
441
561
 
562
+ /* On error: label and notch line turn error-colored. */
442
563
  .field.label.invalid > label,
443
564
  .field.label.invalid > label::after {
444
565
  color: var(--error) !important;
445
566
  border-color: var(--error) !important;
446
567
  }
447
568
 
448
- /* Helper / error output */
569
+ /* ─── Helper / error output ──────────────────────────────────────────────── */
570
+ /* The <output> element below the field shows helper text or validation errors. */
449
571
  .field > output {
450
572
  display: inline-block;
451
573
  font-size: 0.75rem;
@@ -455,20 +577,23 @@ export const fieldStyles = css `
455
577
  align-self: start;
456
578
  color: var(--on-surface-variant);
457
579
  }
580
+ /* Error output overrides the neutral helper color. */
458
581
  .field > output.invalid {
459
582
  color: var(--error) !important;
460
583
  }
584
+ /* Round fields: increase horizontal padding to align with the curved edge. */
461
585
  .field[class*='round'] > output {
462
586
  padding: 0.25rem 1.5rem;
463
587
  }
588
+ /* Show only one output at a time: helper OR error, never both. */
464
589
  .field.invalid > output:not(.invalid),
465
590
  .field:not(.invalid) > output.invalid {
466
591
  display: none;
467
592
  }
468
593
 
469
- /* Footer wrapper for textarea (and other multi-line fields) that pairs
470
- a helper text on the left with a character counter on the right.
471
- Per M3 spec, supporting text and character counter share the footer. */
594
+ /* ─── Footer wrapper (textarea & multi-line fields) ───────────────────────── */
595
+ /* Lays out helper text (left) and character counter (right) on the same row,
596
+ matching the M3 spec for supporting-text + character-counter pairs. */
472
597
  .field > .footer {
473
598
  display: flex;
474
599
  align-items: center;
@@ -489,13 +614,16 @@ export const fieldStyles = css `
489
614
  .field > .footer > output.invalid {
490
615
  color: var(--error) !important;
491
616
  }
617
+ /* Character counter — right-aligned, same typographic style as the helper. */
492
618
  .field > .footer > .counter {
493
619
  padding: 0.25rem 1rem;
494
620
  color: var(--on-surface-variant);
495
621
  }
622
+ /* Spacer pushes counter to the right when there is no helper text. */
496
623
  .field > .footer > .spacer {
497
624
  flex: 1;
498
625
  }
626
+ /* Same exclusive show logic as direct <output> elements. */
499
627
  .field.invalid > .footer > output:not(.invalid),
500
628
  .field:not(.invalid) > .footer > output.invalid {
501
629
  display: none;