aeico-components 0.1.4 → 0.1.6

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 (299) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +0 -0
  3. package/dist/chunks/action-button.cjs +296 -0
  4. package/dist/chunks/action-button.cjs.map +1 -0
  5. package/dist/chunks/action-button.js +297 -0
  6. package/dist/chunks/action-button.js.map +1 -0
  7. package/dist/chunks/alert.cjs +4 -4
  8. package/dist/chunks/alert.cjs.map +1 -1
  9. package/dist/chunks/alert.js +5 -5
  10. package/dist/chunks/alert.js.map +1 -1
  11. package/dist/chunks/badge.cjs +1 -1
  12. package/dist/chunks/badge.cjs.map +1 -1
  13. package/dist/chunks/badge.js +2 -2
  14. package/dist/chunks/badge.js.map +1 -1
  15. package/dist/chunks/breadcrumb-item.cjs +2 -2
  16. package/dist/chunks/breadcrumb-item.cjs.map +1 -1
  17. package/dist/chunks/breadcrumb-item.js +3 -3
  18. package/dist/chunks/breadcrumb-item.js.map +1 -1
  19. package/dist/chunks/button-group.cjs +1 -1
  20. package/dist/chunks/button-group.cjs.map +1 -1
  21. package/dist/chunks/button-group.js +2 -2
  22. package/dist/chunks/button-group.js.map +1 -1
  23. package/dist/chunks/button.cjs +12 -15
  24. package/dist/chunks/button.cjs.map +1 -1
  25. package/dist/chunks/button.js +13 -16
  26. package/dist/chunks/button.js.map +1 -1
  27. package/dist/chunks/card.cjs +1 -1
  28. package/dist/chunks/card.cjs.map +1 -1
  29. package/dist/chunks/card.js +2 -2
  30. package/dist/chunks/card.js.map +1 -1
  31. package/dist/chunks/checkbox.cjs +18 -5
  32. package/dist/chunks/checkbox.cjs.map +1 -1
  33. package/dist/chunks/checkbox.js +18 -5
  34. package/dist/chunks/checkbox.js.map +1 -1
  35. package/dist/chunks/copy-button.cjs +168 -0
  36. package/dist/chunks/copy-button.cjs.map +1 -0
  37. package/dist/chunks/copy-button.js +169 -0
  38. package/dist/chunks/copy-button.js.map +1 -0
  39. package/dist/chunks/detail.cjs +7 -4
  40. package/dist/chunks/detail.cjs.map +1 -1
  41. package/dist/chunks/detail.js +8 -5
  42. package/dist/chunks/detail.js.map +1 -1
  43. package/dist/chunks/dialog.cjs +1 -1
  44. package/dist/chunks/dialog.cjs.map +1 -1
  45. package/dist/chunks/dialog.js +2 -2
  46. package/dist/chunks/dialog.js.map +1 -1
  47. package/dist/chunks/divider.cjs +1 -1
  48. package/dist/chunks/divider.cjs.map +1 -1
  49. package/dist/chunks/divider.js +2 -2
  50. package/dist/chunks/divider.js.map +1 -1
  51. package/dist/chunks/drawer.cjs +180 -0
  52. package/dist/chunks/drawer.cjs.map +1 -0
  53. package/dist/chunks/drawer.js +181 -0
  54. package/dist/chunks/drawer.js.map +1 -0
  55. package/dist/chunks/dropdown-button.cjs +2 -2
  56. package/dist/chunks/dropdown-button.cjs.map +1 -1
  57. package/dist/chunks/dropdown-button.js +6 -6
  58. package/dist/chunks/dropdown-button.js.map +1 -1
  59. package/dist/chunks/icon.cjs +31 -1
  60. package/dist/chunks/icon.cjs.map +1 -1
  61. package/dist/chunks/icon.js +32 -2
  62. package/dist/chunks/icon.js.map +1 -1
  63. package/dist/chunks/menu.cjs +396 -0
  64. package/dist/chunks/menu.cjs.map +1 -0
  65. package/dist/chunks/menu.js +397 -0
  66. package/dist/chunks/menu.js.map +1 -0
  67. package/dist/chunks/navbar.cjs +2 -3
  68. package/dist/chunks/navbar.cjs.map +1 -1
  69. package/dist/chunks/navbar.js +3 -4
  70. package/dist/chunks/navbar.js.map +1 -1
  71. package/dist/chunks/pagination.cjs +475 -0
  72. package/dist/chunks/pagination.cjs.map +1 -0
  73. package/dist/chunks/pagination.js +476 -0
  74. package/dist/chunks/pagination.js.map +1 -0
  75. package/dist/chunks/progress-bar.cjs +101 -0
  76. package/dist/chunks/progress-bar.cjs.map +1 -0
  77. package/dist/chunks/progress-bar.js +102 -0
  78. package/dist/chunks/progress-bar.js.map +1 -0
  79. package/dist/chunks/radio.cjs +11 -7
  80. package/dist/chunks/radio.cjs.map +1 -1
  81. package/dist/chunks/radio.js +11 -7
  82. package/dist/chunks/radio.js.map +1 -1
  83. package/dist/chunks/select.cjs +97 -66
  84. package/dist/chunks/select.cjs.map +1 -1
  85. package/dist/chunks/select.js +97 -66
  86. package/dist/chunks/select.js.map +1 -1
  87. package/dist/chunks/slider.cjs +9 -46
  88. package/dist/chunks/slider.cjs.map +1 -1
  89. package/dist/chunks/slider.js +9 -46
  90. package/dist/chunks/slider.js.map +1 -1
  91. package/dist/chunks/spinner.cjs +102 -0
  92. package/dist/chunks/spinner.cjs.map +1 -0
  93. package/dist/chunks/spinner.js +103 -0
  94. package/dist/chunks/spinner.js.map +1 -0
  95. package/dist/chunks/switch.cjs +110 -16
  96. package/dist/chunks/switch.cjs.map +1 -1
  97. package/dist/chunks/switch.js +111 -17
  98. package/dist/chunks/switch.js.map +1 -1
  99. package/dist/chunks/tab-panel.cjs +6 -7
  100. package/dist/chunks/tab-panel.cjs.map +1 -1
  101. package/dist/chunks/tab-panel.js +7 -8
  102. package/dist/chunks/tab-panel.js.map +1 -1
  103. package/dist/chunks/tag.cjs +1 -1
  104. package/dist/chunks/tag.cjs.map +1 -1
  105. package/dist/chunks/tag.js +2 -2
  106. package/dist/chunks/tag.js.map +1 -1
  107. package/dist/chunks/text-input.cjs +11 -16
  108. package/dist/chunks/text-input.cjs.map +1 -1
  109. package/dist/chunks/text-input.js +11 -16
  110. package/dist/chunks/text-input.js.map +1 -1
  111. package/dist/chunks/textarea.cjs +137 -0
  112. package/dist/chunks/textarea.cjs.map +1 -0
  113. package/dist/chunks/textarea.js +138 -0
  114. package/dist/chunks/textarea.js.map +1 -0
  115. package/dist/chunks/tooltip.cjs +293 -0
  116. package/dist/chunks/tooltip.cjs.map +1 -0
  117. package/dist/chunks/tooltip.js +294 -0
  118. package/dist/chunks/tooltip.js.map +1 -0
  119. package/dist/chunks/tree.cjs +468 -0
  120. package/dist/chunks/tree.cjs.map +1 -0
  121. package/dist/chunks/tree.js +469 -0
  122. package/dist/chunks/tree.js.map +1 -0
  123. package/dist/chunks/variables.cjs +2 -2
  124. package/dist/chunks/variables.js +2 -2
  125. package/dist/copy-button.cjs +6 -0
  126. package/dist/copy-button.cjs.map +1 -0
  127. package/dist/copy-button.js +6 -0
  128. package/dist/copy-button.js.map +1 -0
  129. package/dist/drawer.cjs +6 -0
  130. package/dist/drawer.cjs.map +1 -0
  131. package/dist/drawer.js +6 -0
  132. package/dist/drawer.js.map +1 -0
  133. package/dist/dropdown.js +4 -4
  134. package/dist/index.cjs +186 -0
  135. package/dist/index.cjs.map +1 -1
  136. package/dist/index.js +201 -15
  137. package/dist/index.js.map +1 -1
  138. package/dist/menu.cjs +6 -0
  139. package/dist/menu.cjs.map +1 -0
  140. package/dist/menu.js +6 -0
  141. package/dist/menu.js.map +1 -0
  142. package/dist/pagination.cjs +6 -0
  143. package/dist/pagination.cjs.map +1 -0
  144. package/dist/pagination.js +6 -0
  145. package/dist/pagination.js.map +1 -0
  146. package/dist/progress-bar.cjs +6 -0
  147. package/dist/progress-bar.cjs.map +1 -0
  148. package/dist/progress-bar.js +6 -0
  149. package/dist/progress-bar.js.map +1 -0
  150. package/dist/select.cjs +1 -1
  151. package/dist/select.cjs.map +1 -1
  152. package/dist/select.js +2 -2
  153. package/dist/select.js.map +1 -1
  154. package/dist/spinner.cjs +6 -0
  155. package/dist/spinner.cjs.map +1 -0
  156. package/dist/spinner.js +6 -0
  157. package/dist/spinner.js.map +1 -0
  158. package/dist/textarea.cjs +5 -0
  159. package/dist/textarea.cjs.map +1 -0
  160. package/dist/textarea.js +5 -0
  161. package/dist/textarea.js.map +1 -0
  162. package/dist/tooltip.cjs +6 -0
  163. package/dist/tooltip.cjs.map +1 -0
  164. package/dist/tooltip.js +6 -0
  165. package/dist/tooltip.js.map +1 -0
  166. package/dist/tree.cjs +6 -0
  167. package/dist/tree.cjs.map +1 -0
  168. package/dist/tree.js +6 -0
  169. package/dist/tree.js.map +1 -0
  170. package/dist/types/aeico-field.d.ts +57 -5
  171. package/dist/types/alert/alert.d.ts +1 -0
  172. package/dist/types/button/button.d.ts +2 -1
  173. package/dist/types/checkbox/checkbox.d.ts +5 -5
  174. package/dist/types/copy-button/copy-button.d.ts +32 -0
  175. package/dist/types/copy-button/defines.d.ts +1 -0
  176. package/dist/types/copy-button/index.d.ts +3 -0
  177. package/dist/types/detail/defines.d.ts +1 -0
  178. package/dist/types/detail/detail.d.ts +3 -1
  179. package/dist/types/detail/index.d.ts +1 -1
  180. package/dist/types/detail-group/detail-group.d.ts +39 -0
  181. package/dist/types/detail-group/index.d.ts +2 -0
  182. package/dist/types/drawer/defines.d.ts +1 -0
  183. package/dist/types/drawer/drawer.d.ts +31 -0
  184. package/dist/types/drawer/index.d.ts +3 -0
  185. package/dist/types/icon/built-in-icons.d.ts +1 -0
  186. package/dist/types/icon/icon.d.ts +1 -0
  187. package/dist/types/icon/registry.d.ts +8 -0
  188. package/dist/types/index.d.ts +19 -0
  189. package/dist/types/menu/defines.d.ts +15 -0
  190. package/dist/types/menu/index.d.ts +5 -0
  191. package/dist/types/menu/menu-item.d.ts +63 -0
  192. package/dist/types/menu/menu.d.ts +34 -0
  193. package/dist/types/number-input/index.d.ts +2 -0
  194. package/dist/types/number-input/number-input.d.ts +35 -0
  195. package/dist/types/pagination/defines.d.ts +2 -0
  196. package/dist/types/pagination/index.d.ts +3 -0
  197. package/dist/types/pagination/pagination.d.ts +77 -0
  198. package/dist/types/progress-bar/defines.d.ts +1 -0
  199. package/dist/types/progress-bar/index.d.ts +3 -0
  200. package/dist/types/progress-bar/progress-bar.d.ts +37 -0
  201. package/dist/types/radio-group/radio-group.d.ts +1 -1
  202. package/dist/types/select/select.d.ts +3 -3
  203. package/dist/types/spinner/defines.d.ts +3 -0
  204. package/dist/types/spinner/index.d.ts +3 -0
  205. package/dist/types/spinner/spinner.d.ts +35 -0
  206. package/dist/types/switch/defines.d.ts +1 -0
  207. package/dist/types/switch/switch.d.ts +13 -9
  208. package/dist/types/text-input/text-input.d.ts +0 -4
  209. package/dist/types/textarea/index.d.ts +1 -0
  210. package/dist/types/textarea/textarea.d.ts +26 -0
  211. package/dist/types/tooltip/defines.d.ts +2 -0
  212. package/dist/types/tooltip/index.d.ts +4 -0
  213. package/dist/types/tooltip/tooltip.d.ts +48 -0
  214. package/dist/types/tree/defines.d.ts +23 -0
  215. package/dist/types/tree/index.d.ts +5 -0
  216. package/dist/types/tree/tree-item.d.ts +54 -0
  217. package/dist/types/tree/tree.d.ts +64 -0
  218. package/package.json +6 -6
  219. package/src/aeico-field.ts +154 -15
  220. package/src/alert/alert.ts +3 -2
  221. package/src/button/button.ts +11 -13
  222. package/src/checkbox/checkbox.ts +21 -6
  223. package/src/copy-button/copy-button.ts +146 -0
  224. package/src/copy-button/defines.ts +5 -0
  225. package/src/copy-button/index.ts +3 -0
  226. package/src/detail/defines.ts +1 -0
  227. package/src/detail/detail.ts +5 -1
  228. package/src/detail/index.ts +1 -1
  229. package/src/detail-group/detail-group.ts +104 -0
  230. package/src/detail-group/index.ts +2 -0
  231. package/src/drawer/defines.ts +1 -0
  232. package/src/drawer/drawer.ts +157 -0
  233. package/src/drawer/index.ts +3 -0
  234. package/src/icon/built-in-icons.ts +21 -0
  235. package/src/icon/icon.ts +1 -0
  236. package/src/icon/registry.ts +22 -0
  237. package/src/index.ts +32 -0
  238. package/src/menu/defines.ts +17 -0
  239. package/src/menu/index.ts +5 -0
  240. package/src/menu/menu-item.ts +315 -0
  241. package/src/menu/menu.ts +81 -0
  242. package/src/navbar/navbar.ts +1 -3
  243. package/src/number-input/index.ts +2 -0
  244. package/src/number-input/number-input.ts +137 -0
  245. package/src/pagination/defines.ts +2 -0
  246. package/src/pagination/index.ts +3 -0
  247. package/src/pagination/pagination.ts +310 -0
  248. package/src/progress-bar/defines.ts +8 -0
  249. package/src/progress-bar/index.ts +3 -0
  250. package/src/progress-bar/progress-bar.ts +80 -0
  251. package/src/radio-group/radio-group.ts +12 -5
  252. package/src/select/select.ts +112 -71
  253. package/src/slider/slider.ts +9 -2
  254. package/src/spinner/defines.ts +12 -0
  255. package/src/spinner/index.ts +3 -0
  256. package/src/spinner/spinner.ts +81 -0
  257. package/src/styles/components/action-button.css +37 -0
  258. package/src/styles/components/checkbox.css +4 -26
  259. package/src/styles/components/copy-button.css +119 -0
  260. package/src/styles/components/detail-group.css +10 -0
  261. package/src/styles/components/detail.css +10 -1
  262. package/src/styles/components/drawer.css +161 -0
  263. package/src/styles/components/field-label.css +120 -0
  264. package/src/styles/components/menu-item.css +168 -0
  265. package/src/styles/components/menu.css +17 -0
  266. package/src/styles/components/number-input.css +167 -0
  267. package/src/styles/components/pagination.css +205 -0
  268. package/src/styles/components/progress-bar.css +44 -0
  269. package/src/styles/components/radio-group.css +0 -23
  270. package/src/styles/components/select.css +12 -39
  271. package/src/styles/components/slider.css +0 -42
  272. package/src/styles/components/spinner.css +80 -0
  273. package/src/styles/components/switch.css +68 -19
  274. package/src/styles/components/tab-panel.css +1 -1
  275. package/src/styles/components/tabs.css +1 -0
  276. package/src/styles/components/text-input.css +7 -45
  277. package/src/styles/components/textarea.css +75 -0
  278. package/src/styles/components/tooltip.css +103 -0
  279. package/src/styles/components/tree-item.css +152 -0
  280. package/src/styles/components/tree.css +10 -0
  281. package/src/styles/layout.css +457 -25
  282. package/src/switch/defines.ts +1 -0
  283. package/src/switch/switch.ts +65 -16
  284. package/src/tabs/tab.ts +1 -1
  285. package/src/tabs/tabs.ts +1 -2
  286. package/src/text-input/text-input.ts +10 -15
  287. package/src/textarea/index.ts +1 -0
  288. package/src/textarea/textarea.ts +107 -0
  289. package/src/tooltip/defines.ts +11 -0
  290. package/src/tooltip/index.ts +4 -0
  291. package/src/tooltip/tooltip.ts +183 -0
  292. package/src/tree/defines.ts +26 -0
  293. package/src/tree/index.ts +5 -0
  294. package/src/tree/tree-item.ts +258 -0
  295. package/src/tree/tree.ts +237 -0
  296. package/dist/chunks/aeico-field.cjs +0 -179
  297. package/dist/chunks/aeico-field.cjs.map +0 -1
  298. package/dist/chunks/aeico-field.js +0 -180
  299. package/dist/chunks/aeico-field.js.map +0 -1
@@ -1,4 +1,4 @@
1
- /*
1
+ /*
2
2
  layout.css — Light DOM utility classes
3
3
  This file is for use in the user's light DOM (regular HTML),
4
4
  NOT imported by any Web Component internally.
@@ -8,36 +8,468 @@
8
8
  or:
9
9
  <link rel="stylesheet" href="path/to/layout.css">
10
10
 
11
+ All utility rules live inside @layer aeico-layout so that your own
12
+ un-layered (or later-layered) styles always override them without !important.
13
+
11
14
  The layout tokens defined here on :root are intentionally mirrored
12
15
  in variables.css (:root, :host) so that ae-navbar's shadow DOM
13
16
  inner content also aligns automatically.
14
17
  */
15
18
 
16
- /* Layout tokens — defined on :root so all light DOM elements can use them */
19
+ /**
20
+ * Tokens — defined on :root outside @layer so they are always resolvable,
21
+ * even when the cascade layer order is re-arranged by the consuming app.
22
+ */
17
23
  :root {
18
- --container-max-width: 1280px;
19
- --container-padding-x: 1.5rem;
20
- }
24
+ --container-max-width: 1280px;
25
+ --container-padding-x: 1.5rem;
26
+ --container-sm-max-width: 720px;
27
+ --container-md-max-width: 960px;
28
+ --container-xl-max-width: 1440px;
21
29
 
22
- /*
23
- .container
24
- Fixed max-width, centred, with horizontal padding.
25
- Same padding-x as ae-navbar's inner content area.
26
- */
27
- .container {
28
- width: 100%;
29
- max-width: var(--container-max-width, 1280px);
30
- margin-inline: auto;
31
- padding-inline: var(--container-padding-x, 1.5rem);
32
- box-sizing: border-box;
30
+ /* Spacing scale — numeric steps based on a 4px unit.
31
+ * Usage: gap: var(--space-4); padding: var(--space-2) var(--space-6);
32
+ */
33
+ --space-1: 0.25rem; /* 4px */
34
+ --space-2: 0.5rem; /* 8px */
35
+ --space-3: 0.75rem; /* 12px */
36
+ --space-4: 1rem; /* 16px */
37
+ --space-6: 1.5rem; /* 24px */
38
+ --space-8: 2rem; /* 32px */
39
+ --space-10: 2.5rem; /* 40px */
40
+ --space-12: 3rem; /* 48px */
41
+ --space-16: 4rem; /* 64px */
33
42
  }
34
43
 
35
- /*
36
- .container-fluid
37
- Full-width, only applies horizontal padding.
38
- */
39
- .container-fluid {
40
- width: 100%;
41
- padding-inline: var(--container-padding-x, 1.5rem);
42
- box-sizing: border-box;
43
- }
44
+ /**
45
+ * @layer aeico-layout — all utility rules live here.
46
+ * Unlayered user styles win automatically. To override from a named layer,
47
+ * declare the order before importing this file:
48
+ * @layer aeico-layout, your-layer;
49
+ */
50
+ @layer aeico-layout {
51
+
52
+ /* #region Container */
53
+
54
+ /*
55
+ * .container
56
+ * Fixed max-width, centred, with horizontal padding.
57
+ * Same padding-x as ae-navbar's inner content area.
58
+ */
59
+ .container {
60
+ width: 100%;
61
+ max-width: var(--container-max-width, 1280px);
62
+ margin-inline: auto;
63
+ padding-inline: var(--container-padding-x, 1.5rem);
64
+ box-sizing: border-box;
65
+ }
66
+
67
+ /*
68
+ * .container-fluid
69
+ * Full-width, only applies horizontal padding.
70
+ */
71
+ .container-fluid {
72
+ width: 100%;
73
+ padding-inline: var(--container-padding-x, 1.5rem);
74
+ box-sizing: border-box;
75
+ }
76
+
77
+ /**
78
+ * Container size variants
79
+ *
80
+ * Narrower and wider alternatives to .container, sharing the same box model.
81
+ * Override the width tokens globally to affect all instances at once:
82
+ * --container-sm-max-width (default 720px)
83
+ * --container-md-max-width (default 960px)
84
+ * --container-xl-max-width (default 1440px)
85
+ */
86
+ .container-sm,
87
+ .container-md,
88
+ .container-xl {
89
+ width: 100%;
90
+ margin-inline: auto;
91
+ padding-inline: var(--container-padding-x, 1.5rem);
92
+ box-sizing: border-box;
93
+ }
94
+
95
+ .container-sm { max-width: var(--container-sm-max-width, 720px); }
96
+ .container-md { max-width: var(--container-md-max-width, 960px); }
97
+ .container-xl { max-width: var(--container-xl-max-width, 1440px); }
98
+
99
+ /* #endregion */
100
+
101
+ /* #region Stack */
102
+
103
+ /**
104
+ * Stack
105
+ *
106
+ * Vertical flex container. Children are laid out top-to-bottom with a
107
+ * consistent gap driven by --stack-gap (defaults to --space-4 / 16px).
108
+ *
109
+ * Override per-component: .my-section { --stack-gap: var(--space-6) }
110
+ * Or use a gap modifier: <div class="stack stack-6">
111
+ *
112
+ * Gap modifier scale (maps to spacing tokens):
113
+ * .stack-1 4px .stack-2 8px .stack-3 12px .stack-4 16px
114
+ * .stack-6 24px .stack-8 32px .stack-10 40px .stack-12 48px .stack-16 64px
115
+ */
116
+ .stack {
117
+ display: flex;
118
+ flex-direction: column;
119
+ gap: var(--stack-gap, var(--space-4, 1rem));
120
+ }
121
+
122
+ /* Reset block margins on direct children — prevents h1/p/ul from adding
123
+ unintended spacing on top of the flex gap. */
124
+ .stack > * { margin-block: 0; margin-inline: 0; }
125
+
126
+ /* Default alignment — zero specificity so a single class rule overrides it. */
127
+ :where(.stack) { align-items: stretch; }
128
+
129
+ .stack-1 { --stack-gap: var(--space-1, 0.25rem); }
130
+ .stack-2 { --stack-gap: var(--space-2, 0.5rem); }
131
+ .stack-3 { --stack-gap: var(--space-3, 0.75rem); }
132
+ .stack-4 { --stack-gap: var(--space-4, 1rem); }
133
+ .stack-6 { --stack-gap: var(--space-6, 1.5rem); }
134
+ .stack-8 { --stack-gap: var(--space-8, 2rem); }
135
+ .stack-10 { --stack-gap: var(--space-10, 2.5rem); }
136
+ .stack-12 { --stack-gap: var(--space-12, 3rem); }
137
+ .stack-16 { --stack-gap: var(--space-16, 4rem); }
138
+
139
+ /* Alignment modifiers */
140
+ .stack-center { align-items: center; }
141
+ .stack-stretch { align-items: stretch; }
142
+ .stack-start { align-items: flex-start; }
143
+ .stack-end { align-items: flex-end; }
144
+
145
+ /* #endregion */
146
+
147
+ /* #region Cluster */
148
+
149
+ /**
150
+ * Cluster
151
+ *
152
+ * Horizontal flex container with wrapping. Items flow left-to-right and wrap
153
+ * to the next line when the container is too narrow.
154
+ *
155
+ * Override per-component: .my-toolbar { --cluster-gap: var(--space-2) }
156
+ * Or use a gap modifier: <div class="cluster cluster-2">
157
+ *
158
+ * Inline token overrides (no extra class needed):
159
+ * style="--cluster-align: flex-start; --cluster-justify: center"
160
+ *
161
+ * Justify modifiers: .cluster-between .cluster-center .cluster-end
162
+ */
163
+ .cluster {
164
+ display: flex;
165
+ flex-wrap: wrap;
166
+ gap: var(--cluster-gap, var(--space-4, 1rem));
167
+ }
168
+
169
+ /* Defaults — override via CSS custom properties or modifier classes.
170
+ :where() keeps specificity at zero so a plain class rule always wins. */
171
+ :where(.cluster) {
172
+ align-items: var(--cluster-align, center);
173
+ justify-content: var(--cluster-justify, flex-start);
174
+ }
175
+
176
+ .cluster-1 { --cluster-gap: var(--space-1, 0.25rem); }
177
+ .cluster-2 { --cluster-gap: var(--space-2, 0.5rem); }
178
+ .cluster-3 { --cluster-gap: var(--space-3, 0.75rem); }
179
+ .cluster-4 { --cluster-gap: var(--space-4, 1rem); }
180
+ .cluster-6 { --cluster-gap: var(--space-6, 1.5rem); }
181
+ .cluster-8 { --cluster-gap: var(--space-8, 2rem); }
182
+ .cluster-10 { --cluster-gap: var(--space-10, 2.5rem); }
183
+ .cluster-12 { --cluster-gap: var(--space-12, 3rem); }
184
+ .cluster-16 { --cluster-gap: var(--space-16, 4rem); }
185
+
186
+ /* Justify modifiers */
187
+ .cluster-between { --cluster-justify: space-between; }
188
+ .cluster-center { --cluster-justify: center; }
189
+ .cluster-end { --cluster-justify: flex-end; }
190
+
191
+ /* #endregion */
192
+
193
+ /* #region Grid */
194
+
195
+ /**
196
+ * Grid
197
+ *
198
+ * CSS Grid container driven by two custom properties:
199
+ * --grid-cols number of equal columns (default 1)
200
+ * --grid-gap gap between cells (default --space-4 / 16px)
201
+ *
202
+ * Fixed-column presets:
203
+ * <div class="grid grid-cols-3">
204
+ * Override inline: style="--grid-cols: 5; --grid-gap: var(--space-6)"
205
+ *
206
+ * Auto-responsive variant (.grid-auto):
207
+ * Fills as many columns as fit; minimum column width set by --grid-min-col.
208
+ * <div class="grid-auto" style="--grid-min-col: 200px">
209
+ *
210
+ * Responsive column modifiers (breakpoints: sm≥576 md≥768 lg≥992 xl≥1200):
211
+ * <div class="grid grid-cols-1 grid-cols-md-2 grid-cols-lg-3">
212
+ *
213
+ * Full-width span:
214
+ * <div class="grid-span"> inside any .grid or .grid-auto
215
+ */
216
+ .grid {
217
+ display: grid;
218
+ grid-template-columns: repeat(var(--grid-cols, 1), 1fr);
219
+ gap: var(--grid-gap, var(--space-4, 1rem));
220
+ }
221
+
222
+ /* Reset block margins on direct children — same rationale as .stack. */
223
+ .grid > * { margin-block: 0; margin-inline: 0; }
224
+
225
+ /* Fixed-column presets */
226
+ .grid-cols-2 { --grid-cols: 2; }
227
+ .grid-cols-3 { --grid-cols: 3; }
228
+ .grid-cols-4 { --grid-cols: 4; }
229
+ .grid-cols-6 { --grid-cols: 6; }
230
+ .grid-cols-12 { --grid-cols: 12; }
231
+
232
+ /**
233
+ * Auto-responsive grid
234
+ *
235
+ * min() guard prevents columns exceeding 100% of the container width,
236
+ * avoiding horizontal overflow when --grid-min-col > container width.
237
+ */
238
+ .grid-auto {
239
+ display: grid;
240
+ grid-template-columns: repeat(auto-fill, minmax(min(var(--grid-min-col, 240px), 100%), 1fr));
241
+ gap: var(--grid-gap, var(--space-4, 1rem));
242
+ }
243
+
244
+ /* .grid-span — child spans all columns */
245
+ .grid-span { grid-column: 1 / -1; }
246
+
247
+ /* Responsive column modifiers — sm ≥ 576px */
248
+ @media (min-width: 576px) {
249
+ .grid-cols-sm-1 { --grid-cols: 1; }
250
+ .grid-cols-sm-2 { --grid-cols: 2; }
251
+ .grid-cols-sm-3 { --grid-cols: 3; }
252
+ .grid-cols-sm-4 { --grid-cols: 4; }
253
+ }
254
+
255
+ /* Responsive column modifiers — md ≥ 768px */
256
+ @media (min-width: 768px) {
257
+ .grid-cols-md-1 { --grid-cols: 1; }
258
+ .grid-cols-md-2 { --grid-cols: 2; }
259
+ .grid-cols-md-3 { --grid-cols: 3; }
260
+ .grid-cols-md-4 { --grid-cols: 4; }
261
+ .grid-cols-md-6 { --grid-cols: 6; }
262
+ }
263
+
264
+ /* Responsive column modifiers — lg ≥ 992px */
265
+ @media (min-width: 992px) {
266
+ .grid-cols-lg-1 { --grid-cols: 1; }
267
+ .grid-cols-lg-2 { --grid-cols: 2; }
268
+ .grid-cols-lg-3 { --grid-cols: 3; }
269
+ .grid-cols-lg-4 { --grid-cols: 4; }
270
+ .grid-cols-lg-6 { --grid-cols: 6; }
271
+ .grid-cols-lg-12 { --grid-cols: 12; }
272
+ }
273
+
274
+ /* Responsive column modifiers — xl ≥ 1200px */
275
+ @media (min-width: 1200px) {
276
+ .grid-cols-xl-1 { --grid-cols: 1; }
277
+ .grid-cols-xl-2 { --grid-cols: 2; }
278
+ .grid-cols-xl-3 { --grid-cols: 3; }
279
+ .grid-cols-xl-4 { --grid-cols: 4; }
280
+ .grid-cols-xl-6 { --grid-cols: 6; }
281
+ .grid-cols-xl-12 { --grid-cols: 12; }
282
+ }
283
+
284
+ /* #endregion */
285
+
286
+ /* #region Flank */
287
+
288
+ /**
289
+ * Flank
290
+ *
291
+ * A two-column layout where one side ("the flank") has a fixed or intrinsic
292
+ * width and the other side ("the content") fills the remaining space.
293
+ * Wraps to a single column when the content area would be narrower than
294
+ * --flank-content-min (default 50%).
295
+ *
296
+ * --flank-size width of the flanking element (default: auto / intrinsic)
297
+ * --flank-content-min min inline size of content before wrapping (default: 50%)
298
+ * --flank-gap gap between children (default: --space-4)
299
+ *
300
+ * Default (.flank): first child = flank, last child = content
301
+ * Reversed (.flank-end): first child = content, last child = flank
302
+ *
303
+ * Example:
304
+ * <div class="flank" style="--flank-size: 12rem">
305
+ * <img src="avatar.png" />
306
+ * <div>…content…</div>
307
+ * </div>
308
+ */
309
+ .flank {
310
+ display: flex;
311
+ flex-wrap: wrap;
312
+ gap: var(--flank-gap, var(--space-4, 1rem));
313
+ }
314
+
315
+ :where(.flank) { align-items: flex-start; }
316
+
317
+ /* First child = flank sidebar */
318
+ .flank > :first-child {
319
+ flex-basis: var(--flank-size, auto);
320
+ flex-grow: 1;
321
+ }
322
+
323
+ /* Last child = content area */
324
+ .flank > :last-child {
325
+ flex-basis: 0;
326
+ flex-grow: 999;
327
+ min-inline-size: var(--flank-content-min, 50%);
328
+ }
329
+
330
+ /* .flank-end — last child becomes the flank, first child is the content */
331
+ .flank-end > :last-child {
332
+ flex-basis: var(--flank-size, auto);
333
+ flex-grow: 1;
334
+ min-inline-size: unset;
335
+ }
336
+
337
+ .flank-end > :first-child {
338
+ flex-basis: 0;
339
+ flex-grow: 999;
340
+ min-inline-size: var(--flank-content-min, 50%);
341
+ }
342
+
343
+ /* #endregion */
344
+
345
+ /* #region Frame */
346
+
347
+ /**
348
+ * Frame
349
+ *
350
+ * Aspect-ratio container that crops its content (images, videos, embeds)
351
+ * to a fixed ratio without distortion.
352
+ *
353
+ * --frame-ratio aspect ratio (default: 16 / 9)
354
+ *
355
+ * Ratio presets:
356
+ * .frame-square 1 / 1
357
+ * .frame-landscape 16 / 9 (default)
358
+ * .frame-portrait 9 / 16
359
+ *
360
+ * Example:
361
+ * <div class="frame frame-landscape">
362
+ * <img src="hero.jpg" alt="…" />
363
+ * </div>
364
+ */
365
+ .frame {
366
+ display: flex;
367
+ overflow: hidden;
368
+ aspect-ratio: var(--frame-ratio, 16 / 9);
369
+ }
370
+
371
+ :where(.frame) {
372
+ align-items: center;
373
+ justify-content: center;
374
+ }
375
+
376
+ .frame > img,
377
+ .frame > video {
378
+ inline-size: 100%;
379
+ block-size: 100%;
380
+ object-fit: cover;
381
+ }
382
+
383
+ .frame-square { --frame-ratio: 1 / 1; }
384
+ .frame-landscape { --frame-ratio: 16 / 9; }
385
+ .frame-portrait { --frame-ratio: 9 / 16; }
386
+
387
+ /* #endregion */
388
+
389
+ /* #region Split */
390
+
391
+ /**
392
+ * Split
393
+ *
394
+ * A space-between layout for toolbars, card headers, and navigation bars.
395
+ * Unlike .cluster.cluster-between, Split does not wrap by default and
396
+ * supports a column direction (.split-col) for vertical splits.
397
+ *
398
+ * --split-gap gap between children (default: --space-4)
399
+ *
400
+ * Modifiers:
401
+ * .split-col vertical split (flex-direction: column)
402
+ *
403
+ * Example:
404
+ * <header class="split">
405
+ * <span>Title</span>
406
+ * <nav>…actions…</nav>
407
+ * </header>
408
+ */
409
+ .split {
410
+ display: flex;
411
+ gap: var(--split-gap, var(--space-4, 1rem));
412
+ }
413
+
414
+ :where(.split) {
415
+ align-items: center;
416
+ justify-content: space-between;
417
+ flex-wrap: nowrap;
418
+ }
419
+
420
+ .split-col {
421
+ flex-direction: column;
422
+ align-items: stretch;
423
+ justify-content: space-between;
424
+ }
425
+
426
+ /* #endregion */
427
+
428
+ /* #region Gap utilities */
429
+
430
+ /**
431
+ * Gap utilities
432
+ *
433
+ * Apply to any flex or grid container to set gap via spacing tokens.
434
+ * .gap-{n} both row and column gap
435
+ * .gap-x-{n} column gap only
436
+ * .gap-y-{n} row gap only
437
+ *
438
+ * Available steps: 0 1 2 3 4 6 8 10 12 16
439
+ */
440
+ .gap-0 { gap: 0; }
441
+ .gap-1 { gap: var(--space-1, 0.25rem); }
442
+ .gap-2 { gap: var(--space-2, 0.5rem); }
443
+ .gap-3 { gap: var(--space-3, 0.75rem); }
444
+ .gap-4 { gap: var(--space-4, 1rem); }
445
+ .gap-6 { gap: var(--space-6, 1.5rem); }
446
+ .gap-8 { gap: var(--space-8, 2rem); }
447
+ .gap-10 { gap: var(--space-10, 2.5rem); }
448
+ .gap-12 { gap: var(--space-12, 3rem); }
449
+ .gap-16 { gap: var(--space-16, 4rem); }
450
+
451
+ .gap-x-0 { column-gap: 0; }
452
+ .gap-x-1 { column-gap: var(--space-1, 0.25rem); }
453
+ .gap-x-2 { column-gap: var(--space-2, 0.5rem); }
454
+ .gap-x-3 { column-gap: var(--space-3, 0.75rem); }
455
+ .gap-x-4 { column-gap: var(--space-4, 1rem); }
456
+ .gap-x-6 { column-gap: var(--space-6, 1.5rem); }
457
+ .gap-x-8 { column-gap: var(--space-8, 2rem); }
458
+ .gap-x-10 { column-gap: var(--space-10, 2.5rem); }
459
+ .gap-x-12 { column-gap: var(--space-12, 3rem); }
460
+ .gap-x-16 { column-gap: var(--space-16, 4rem); }
461
+
462
+ .gap-y-0 { row-gap: 0; }
463
+ .gap-y-1 { row-gap: var(--space-1, 0.25rem); }
464
+ .gap-y-2 { row-gap: var(--space-2, 0.5rem); }
465
+ .gap-y-3 { row-gap: var(--space-3, 0.75rem); }
466
+ .gap-y-4 { row-gap: var(--space-4, 1rem); }
467
+ .gap-y-6 { row-gap: var(--space-6, 1.5rem); }
468
+ .gap-y-8 { row-gap: var(--space-8, 2rem); }
469
+ .gap-y-10 { row-gap: var(--space-10, 2.5rem); }
470
+ .gap-y-12 { row-gap: var(--space-12, 3rem); }
471
+ .gap-y-16 { row-gap: var(--space-16, 4rem); }
472
+
473
+ /* #endregion */
474
+
475
+ } /* end @layer aeico-layout */
@@ -0,0 +1 @@
1
+ export type SwitchIconPlacement = 'knob' | 'track';
@@ -1,25 +1,43 @@
1
- import AeicoField from '../aeico-field';
2
- import type { InferProps, Props } from 'aeico';
3
- import { html } from 'aeico';
1
+ import AeicoField, { type FieldAction } from '../aeico-field';
2
+ import type { InferProps } from 'aeico';
3
+ import { html, prop } from 'aeico';
4
+ import type { SwitchIconPlacement } from './defines';
5
+ import '../icon/icon';
4
6
  import styleVariables from '../styles/variables.css?inline';
5
7
  import sizeCSS from '../styles/size.css?inline';
6
8
  import colorCSS from '../styles/color.css?inline';
9
+ import fieldLabelCSS from '../styles/components/field-label.css?inline';
10
+ import actionButtonCSS from '../styles/components/action-button.css?inline';
7
11
  import styles from '../styles/components/switch.css?inline';
8
12
 
9
- class Switch extends AeicoField {
13
+ class Switch extends AeicoField<boolean> {
10
14
  protected fieldElement: HTMLInputElement | null = null;
11
15
 
12
16
  static tagName = 'switch';
13
17
 
14
- static props: Props = {
15
- checked: { type: Boolean },
16
- defaultChecked: { type: Boolean },
17
- };
18
+ @prop({ type: Boolean })
19
+ accessor checked: boolean | undefined;
18
20
 
19
- declare checked?: boolean;
20
- declare defaultChecked?: boolean;
21
+ @prop({ type: Boolean })
22
+ accessor defaultChecked: boolean | undefined;
21
23
 
22
- protected static styles = [styleVariables, sizeCSS, colorCSS, styles];
24
+ @prop({ type: String })
25
+ accessor icon: string | undefined;
26
+
27
+ @prop({ type: String })
28
+ accessor iconChecked: string | undefined;
29
+
30
+ @prop({ type: String })
31
+ accessor iconPlacement: SwitchIconPlacement | undefined;
32
+
33
+ protected static styles = [
34
+ styleVariables,
35
+ sizeCSS,
36
+ colorCSS,
37
+ fieldLabelCSS,
38
+ actionButtonCSS,
39
+ styles,
40
+ ];
23
41
 
24
42
  protected getValue(): boolean {
25
43
  return this.fieldElement?.checked ?? false;
@@ -31,11 +49,11 @@ class Switch extends AeicoField {
31
49
  }
32
50
  }
33
51
 
34
- protected getEventPayload(checked: boolean, oldChecked: boolean, action: any) {
52
+ protected getEventPayload(checked: boolean, oldChecked: boolean, action: FieldAction) {
35
53
  return { checked, oldChecked, action };
36
54
  }
37
55
 
38
- protected setValue(checked: boolean, options?: { silent?: boolean; action?: any }): void {
56
+ protected setValue(checked: boolean, options?: { silent?: boolean; action?: FieldAction }): void {
39
57
  const oldChecked = this.getValue();
40
58
  this.checked = checked;
41
59
  this.writeValue(checked);
@@ -58,20 +76,51 @@ class Switch extends AeicoField {
58
76
  }
59
77
 
60
78
  render() {
61
- return html(({ div, input, span }) => {
62
- div({ className: 'switch-container' }, () => {
79
+ return html(({ div, input, span, aeIcon }) => {
80
+ const id = this.getFieldId();
81
+ this.renderLabel(id);
82
+ div({ className: 'switch-container field-body' }, () => {
63
83
  div({ className: 'switch-wrapper' }, () => {
64
84
  this.fieldElement = input({
85
+ id,
65
86
  type: 'checkbox',
66
87
  className: 'field-input',
67
88
  checked: Boolean(this.checked),
68
89
  disabled: Boolean(this.disabled),
90
+ required: Boolean(this.required),
69
91
  '@change': this.boundOnChange,
70
92
  });
71
- span({ className: 'toggle-slider' });
93
+ const hasIcon = this.icon || this.iconChecked;
94
+ const placement = this.iconPlacement ?? 'knob';
95
+ span({ className: 'toggle-slider' }, () => {
96
+ if (!hasIcon) return;
97
+ if (placement === 'track') {
98
+ span({ className: 'track-icon track-icon-left' }, () => {
99
+ aeIcon({ name: this.iconChecked ?? this.icon! });
100
+ });
101
+ span({ className: 'track-icon track-icon-right' }, () => {
102
+ aeIcon({ name: this.icon ?? this.iconChecked! });
103
+ });
104
+ } else {
105
+ if (this.icon && this.iconChecked) {
106
+ span({ className: 'toggle-knob-icon icon-unchecked' }, () => {
107
+ aeIcon({ name: this.icon! });
108
+ });
109
+ span({ className: 'toggle-knob-icon icon-checked' }, () => {
110
+ aeIcon({ name: this.iconChecked! });
111
+ });
112
+ } else {
113
+ span({ className: 'toggle-knob-icon' }, () => {
114
+ aeIcon({ name: (this.icon ?? this.iconChecked)! });
115
+ });
116
+ }
117
+ }
118
+ });
72
119
  });
73
120
  this.renderActionButtons();
74
121
  });
122
+ this.renderHelperText();
123
+ this.renderError();
75
124
  });
76
125
  }
77
126
  }
package/src/tabs/tab.ts CHANGED
@@ -19,7 +19,6 @@ class Tab extends AeicoComponent {
19
19
  connectedCallback() {
20
20
  this.setAttribute('slot', 'tab');
21
21
  super.connectedCallback();
22
- this.listen('click', this._handleClick);
23
22
  }
24
23
 
25
24
  private _handleClick = () => {
@@ -42,6 +41,7 @@ class Tab extends AeicoComponent {
42
41
  'aria-selected': this.active,
43
42
  'aria-disabled': this.disabled,
44
43
  disabled: this.disabled,
44
+ '@click': this._handleClick,
45
45
  },
46
46
  () => {
47
47
  slot();
package/src/tabs/tabs.ts CHANGED
@@ -66,7 +66,6 @@ class Tabs extends AeicoComponent {
66
66
 
67
67
  connectedCallback() {
68
68
  super.connectedCallback();
69
- this.listen('_tab-click', this._handleTabClick);
70
69
  this._observer = new MutationObserver(() => this.update());
71
70
  this._observer.observe(this, { childList: true });
72
71
  }
@@ -113,7 +112,7 @@ class Tabs extends AeicoComponent {
113
112
 
114
113
  protected render() {
115
114
  return html(({ nav, div, slot }) => {
116
- nav({ part: 'tab-nav', role: 'tablist' }, () => {
115
+ nav({ part: 'tab-nav', role: 'tablist', '@_tab-click': this._handleTabClick }, () => {
117
116
  slot({ name: 'tab' });
118
117
  });
119
118
  div({ part: 'panels' }, () => {