mtrl 0.1.3 → 0.2.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 (224) hide show
  1. package/README.md +70 -22
  2. package/index.ts +33 -0
  3. package/package.json +14 -5
  4. package/src/components/button/{styles.scss → _styles.scss} +2 -2
  5. package/src/components/button/api.ts +89 -0
  6. package/src/components/button/button.ts +50 -0
  7. package/src/components/button/config.ts +75 -0
  8. package/src/components/button/constants.ts +17 -0
  9. package/src/components/button/index.ts +4 -0
  10. package/src/components/button/types.ts +118 -0
  11. package/src/components/card/{styles.scss → _styles.scss} +79 -7
  12. package/src/components/card/{actions.js → actions.ts} +15 -18
  13. package/src/components/card/{api.js → api.ts} +33 -33
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/{constants.js → constants.ts} +11 -10
  17. package/src/components/card/{content.js → content.ts} +15 -18
  18. package/src/components/card/{features.js → features.ts} +104 -94
  19. package/src/components/card/{header.js → header.ts} +21 -25
  20. package/src/components/card/index.ts +19 -0
  21. package/src/components/card/media.ts +52 -0
  22. package/src/components/card/types.ts +174 -0
  23. package/src/components/checkbox/api.ts +82 -0
  24. package/src/components/checkbox/checkbox.ts +75 -0
  25. package/src/components/checkbox/config.ts +90 -0
  26. package/src/components/checkbox/index.ts +4 -0
  27. package/src/components/checkbox/types.ts +146 -0
  28. package/src/components/chip/_styles.scss +372 -0
  29. package/src/components/chip/api.ts +115 -0
  30. package/src/components/chip/chip-set.ts +225 -0
  31. package/src/components/chip/chip.ts +82 -0
  32. package/src/components/chip/config.ts +92 -0
  33. package/src/components/chip/constants.ts +38 -0
  34. package/src/components/chip/index.ts +4 -0
  35. package/src/components/chip/types.ts +172 -0
  36. package/src/components/list/api.ts +72 -0
  37. package/src/components/list/config.ts +43 -0
  38. package/src/components/list/{constants.js → constants.ts} +34 -7
  39. package/src/components/list/features.ts +224 -0
  40. package/src/components/list/index.ts +14 -0
  41. package/src/components/list/list-item.ts +120 -0
  42. package/src/components/list/list.ts +37 -0
  43. package/src/components/list/types.ts +179 -0
  44. package/src/components/list/utils.ts +47 -0
  45. package/src/components/menu/api.ts +119 -0
  46. package/src/components/menu/config.ts +54 -0
  47. package/src/components/menu/constants.ts +154 -0
  48. package/src/components/menu/features/items-manager.ts +457 -0
  49. package/src/components/menu/features/keyboard-navigation.ts +133 -0
  50. package/src/components/menu/features/positioning.ts +127 -0
  51. package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
  52. package/src/components/menu/index.ts +14 -0
  53. package/src/components/menu/menu-item.ts +43 -0
  54. package/src/components/menu/menu.ts +53 -0
  55. package/src/components/menu/types.ts +178 -0
  56. package/src/components/navigation/api.ts +79 -0
  57. package/src/components/navigation/config.ts +61 -0
  58. package/src/components/navigation/{constants.js → constants.ts} +10 -10
  59. package/src/components/navigation/index.ts +14 -0
  60. package/src/components/navigation/nav-item.ts +148 -0
  61. package/src/components/navigation/navigation.ts +50 -0
  62. package/src/components/navigation/types.ts +212 -0
  63. package/src/components/progress/_styles.scss +204 -0
  64. package/src/components/progress/api.ts +179 -0
  65. package/src/components/progress/config.ts +124 -0
  66. package/src/components/progress/constants.ts +43 -0
  67. package/src/components/progress/index.ts +5 -0
  68. package/src/components/progress/progress.ts +163 -0
  69. package/src/components/progress/types.ts +102 -0
  70. package/src/components/snackbar/api.ts +162 -0
  71. package/src/components/snackbar/config.ts +62 -0
  72. package/src/components/snackbar/{constants.js → constants.ts} +21 -4
  73. package/src/components/snackbar/features.ts +76 -0
  74. package/src/components/snackbar/index.ts +4 -0
  75. package/src/components/snackbar/position.ts +71 -0
  76. package/src/components/snackbar/queue.ts +76 -0
  77. package/src/components/snackbar/snackbar.ts +60 -0
  78. package/src/components/snackbar/types.ts +58 -0
  79. package/src/components/switch/api.ts +77 -0
  80. package/src/components/switch/config.ts +74 -0
  81. package/src/components/switch/index.ts +4 -0
  82. package/src/components/switch/switch.ts +52 -0
  83. package/src/components/switch/types.ts +142 -0
  84. package/src/components/textfield/api.ts +72 -0
  85. package/src/components/textfield/config.ts +54 -0
  86. package/src/components/textfield/{constants.js → constants.ts} +38 -5
  87. package/src/components/textfield/index.ts +4 -0
  88. package/src/components/textfield/textfield.ts +50 -0
  89. package/src/components/textfield/types.ts +139 -0
  90. package/src/core/compose/base.ts +43 -0
  91. package/src/core/compose/component.ts +247 -0
  92. package/src/core/compose/features/checkable.ts +155 -0
  93. package/src/core/compose/features/disabled.ts +116 -0
  94. package/src/core/compose/features/events.ts +65 -0
  95. package/src/core/compose/features/icon.ts +67 -0
  96. package/src/core/compose/features/index.ts +35 -0
  97. package/src/core/compose/features/input.ts +174 -0
  98. package/src/core/compose/features/lifecycle.ts +139 -0
  99. package/src/core/compose/features/position.ts +94 -0
  100. package/src/core/compose/features/ripple.ts +55 -0
  101. package/src/core/compose/features/size.ts +29 -0
  102. package/src/core/compose/features/style.ts +31 -0
  103. package/src/core/compose/features/text.ts +44 -0
  104. package/src/core/compose/features/textinput.ts +225 -0
  105. package/src/core/compose/features/textlabel.ts +92 -0
  106. package/src/core/compose/features/track.ts +84 -0
  107. package/src/core/compose/features/variant.ts +29 -0
  108. package/src/core/compose/features/withEvents.ts +137 -0
  109. package/src/core/compose/index.ts +54 -0
  110. package/src/core/compose/{pipe.js → pipe.ts} +16 -11
  111. package/src/core/config/component-config.ts +136 -0
  112. package/src/core/config.ts +211 -0
  113. package/src/core/dom/{attributes.js → attributes.ts} +11 -11
  114. package/src/core/dom/classes.ts +60 -0
  115. package/src/core/dom/create.ts +188 -0
  116. package/src/core/dom/events.ts +209 -0
  117. package/src/core/dom/index.ts +10 -0
  118. package/src/core/dom/utils.ts +97 -0
  119. package/src/core/index.ts +111 -0
  120. package/src/core/state/disabled.ts +81 -0
  121. package/src/core/state/emitter.ts +94 -0
  122. package/src/core/state/events.ts +88 -0
  123. package/src/core/state/index.ts +16 -0
  124. package/src/core/state/lifecycle.ts +131 -0
  125. package/src/core/state/store.ts +197 -0
  126. package/src/core/utils/index.ts +45 -0
  127. package/src/core/utils/{mobile.js → mobile.ts} +48 -24
  128. package/src/core/utils/object.ts +41 -0
  129. package/src/core/utils/validate.ts +234 -0
  130. package/src/{index.js → index.ts} +3 -2
  131. package/index.js +0 -11
  132. package/src/components/button/api.js +0 -54
  133. package/src/components/button/button.js +0 -81
  134. package/src/components/button/config.js +0 -10
  135. package/src/components/button/constants.js +0 -63
  136. package/src/components/button/index.js +0 -2
  137. package/src/components/card/card.js +0 -102
  138. package/src/components/card/config.js +0 -16
  139. package/src/components/card/index.js +0 -7
  140. package/src/components/card/media.js +0 -56
  141. package/src/components/checkbox/api.js +0 -45
  142. package/src/components/checkbox/checkbox.js +0 -96
  143. package/src/components/checkbox/index.js +0 -2
  144. package/src/components/container/api.js +0 -42
  145. package/src/components/container/container.js +0 -45
  146. package/src/components/container/index.js +0 -2
  147. package/src/components/container/styles.scss +0 -66
  148. package/src/components/list/index.js +0 -2
  149. package/src/components/list/list-item.js +0 -147
  150. package/src/components/list/list.js +0 -267
  151. package/src/components/menu/api.js +0 -117
  152. package/src/components/menu/constants.js +0 -42
  153. package/src/components/menu/features/items-manager.js +0 -375
  154. package/src/components/menu/features/keyboard-navigation.js +0 -129
  155. package/src/components/menu/features/positioning.js +0 -125
  156. package/src/components/menu/index.js +0 -2
  157. package/src/components/menu/menu-item.js +0 -41
  158. package/src/components/menu/menu.js +0 -54
  159. package/src/components/navigation/api.js +0 -43
  160. package/src/components/navigation/index.js +0 -2
  161. package/src/components/navigation/nav-item.js +0 -137
  162. package/src/components/navigation/navigation.js +0 -55
  163. package/src/components/snackbar/api.js +0 -125
  164. package/src/components/snackbar/features.js +0 -69
  165. package/src/components/snackbar/index.js +0 -2
  166. package/src/components/snackbar/position.js +0 -63
  167. package/src/components/snackbar/queue.js +0 -74
  168. package/src/components/snackbar/snackbar.js +0 -70
  169. package/src/components/switch/api.js +0 -44
  170. package/src/components/switch/index.js +0 -2
  171. package/src/components/switch/switch.js +0 -71
  172. package/src/components/textfield/api.js +0 -49
  173. package/src/components/textfield/index.js +0 -2
  174. package/src/components/textfield/textfield.js +0 -68
  175. package/src/core/build/_ripple.scss +0 -79
  176. package/src/core/build/constants.js +0 -51
  177. package/src/core/build/icon.js +0 -78
  178. package/src/core/build/ripple.js +0 -159
  179. package/src/core/build/text.js +0 -54
  180. package/src/core/compose/base.js +0 -8
  181. package/src/core/compose/component.js +0 -225
  182. package/src/core/compose/features/checkable.js +0 -114
  183. package/src/core/compose/features/disabled.js +0 -64
  184. package/src/core/compose/features/events.js +0 -48
  185. package/src/core/compose/features/icon.js +0 -33
  186. package/src/core/compose/features/index.js +0 -20
  187. package/src/core/compose/features/input.js +0 -100
  188. package/src/core/compose/features/lifecycle.js +0 -69
  189. package/src/core/compose/features/position.js +0 -60
  190. package/src/core/compose/features/ripple.js +0 -32
  191. package/src/core/compose/features/size.js +0 -9
  192. package/src/core/compose/features/style.js +0 -12
  193. package/src/core/compose/features/text.js +0 -17
  194. package/src/core/compose/features/textinput.js +0 -114
  195. package/src/core/compose/features/textlabel.js +0 -28
  196. package/src/core/compose/features/track.js +0 -49
  197. package/src/core/compose/features/variant.js +0 -9
  198. package/src/core/compose/features/withEvents.js +0 -67
  199. package/src/core/compose/index.js +0 -16
  200. package/src/core/config.js +0 -140
  201. package/src/core/dom/classes.js +0 -70
  202. package/src/core/dom/create.js +0 -132
  203. package/src/core/dom/events.js +0 -175
  204. package/src/core/dom/index.js +0 -5
  205. package/src/core/dom/utils.js +0 -22
  206. package/src/core/index.js +0 -23
  207. package/src/core/state/disabled.js +0 -51
  208. package/src/core/state/emitter.js +0 -63
  209. package/src/core/state/events.js +0 -29
  210. package/src/core/state/index.js +0 -6
  211. package/src/core/state/lifecycle.js +0 -64
  212. package/src/core/state/store.js +0 -112
  213. package/src/core/utils/index.js +0 -39
  214. package/src/core/utils/object.js +0 -22
  215. package/src/core/utils/validate.js +0 -37
  216. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  217. /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
  218. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  219. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  220. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  221. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  222. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  223. /package/src/components/switch/{constants.js → constants.ts} +0 -0
  224. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -0,0 +1,372 @@
1
+ // src/components/chip/_styles.scss
2
+ @use '../../styles/abstract/base' as base;
3
+ @use '../../styles/abstract/variables' as v;
4
+ @use '../../styles/abstract/functions' as f;
5
+ @use '../../styles/abstract/mixins' as m;
6
+ @use '../../styles/abstract/theme' as t;
7
+
8
+ $component: '#{base.$prefix}-chip';
9
+
10
+ .#{$component} {
11
+ // Base styles
12
+ position: relative;
13
+ display: inline-flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ height: 32px;
17
+ padding: 0 12px;
18
+ border: none;
19
+ border-radius: 8px;
20
+ background-color: transparent;
21
+ color: inherit;
22
+ font: inherit;
23
+ text-decoration: none;
24
+ cursor: pointer;
25
+ user-select: none;
26
+ vertical-align: middle;
27
+ appearance: none;
28
+ overflow: hidden;
29
+ transition: background-color 0.15s ease, box-shadow 0.15s ease, color 0.15s ease,
30
+ border-color 0.15s ease, opacity 0.15s ease;
31
+
32
+ // Typography
33
+ @include m.typography('label-large');
34
+
35
+ // Focus styles
36
+ &:focus {
37
+ outline: none;
38
+ }
39
+
40
+ &:focus-visible {
41
+ outline: 2px solid t.color('outline');
42
+ outline-offset: 2px;
43
+ }
44
+
45
+ // Disabled state
46
+ &[aria-disabled="true"] {
47
+ pointer-events: none;
48
+ opacity: 0.38;
49
+ }
50
+
51
+ // Leading icon styles
52
+ &-icon {
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: 18px;
57
+ height: 18px;
58
+ margin-right: 8px;
59
+
60
+ svg {
61
+ width: 18px;
62
+ height: 18px;
63
+ }
64
+ }
65
+
66
+ // Trailing icon styles
67
+ &-trailing-icon {
68
+ display: inline-flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ width: 18px;
72
+ height: 18px;
73
+ margin-left: 8px;
74
+
75
+ svg {
76
+ width: 18px;
77
+ height: 18px;
78
+ }
79
+
80
+ &:hover {
81
+ opacity: 0.8;
82
+ }
83
+ }
84
+
85
+ // Text content
86
+ &-text {
87
+ // Text truncation for long chip labels
88
+ @include m.truncate;
89
+ max-width: 150px;
90
+ }
91
+
92
+ // Ripple container
93
+ .ripple {
94
+ position: absolute;
95
+ border-radius: 50%;
96
+ transform: scale(0);
97
+ pointer-events: none;
98
+ background-color: currentColor;
99
+ opacity: 0.12;
100
+ }
101
+
102
+ // === VARIANTS ===
103
+
104
+ // Filled chip (default)
105
+ &--filled {
106
+ background-color: t.color('surface-container-highest');
107
+ color: t.color('on-surface');
108
+
109
+ &:hover {
110
+ @include m.state-layer(t.color('on-surface'), 'hover');
111
+ }
112
+
113
+ &:active {
114
+ @include m.state-layer(t.color('on-surface'), 'pressed');
115
+ }
116
+
117
+ &.#{$component}--selected {
118
+ background-color: t.color('secondary-container');
119
+ color: t.color('on-secondary-container');
120
+
121
+ &:hover {
122
+ @include m.state-layer(t.color('on-secondary-container'), 'hover');
123
+ }
124
+
125
+ &:active {
126
+ @include m.state-layer(t.color('on-secondary-container'), 'pressed');
127
+ }
128
+ }
129
+ }
130
+
131
+ // Outlined chip
132
+ &--outlined {
133
+ border: 1px solid t.color('outline');
134
+ color: t.color('on-surface');
135
+
136
+ &:hover {
137
+ @include m.state-layer(t.color('on-surface'), 'hover');
138
+ }
139
+
140
+ &:active {
141
+ @include m.state-layer(t.color('on-surface'), 'pressed');
142
+ }
143
+
144
+ &.#{$component}--selected {
145
+ border-color: t.color('secondary');
146
+ background-color: t.color('secondary-container');
147
+ color: t.color('on-secondary-container');
148
+
149
+ &:hover {
150
+ @include m.state-layer(t.color('on-secondary-container'), 'hover');
151
+ }
152
+
153
+ &:active {
154
+ @include m.state-layer(t.color('on-secondary-container'), 'pressed');
155
+ }
156
+ }
157
+ }
158
+
159
+ // Elevated chip
160
+ &--elevated {
161
+ background-color: t.color('surface-container-low');
162
+ color: t.color('on-surface');
163
+ @include m.elevation(1);
164
+
165
+ &:hover {
166
+ @include m.state-layer(t.color('on-surface'), 'hover');
167
+ @include m.elevation(2);
168
+ }
169
+
170
+ &:active {
171
+ @include m.state-layer(t.color('on-surface'), 'pressed');
172
+ @include m.elevation(1);
173
+ }
174
+
175
+ &.#{$component}--selected {
176
+ background-color: t.color('secondary-container');
177
+ color: t.color('on-secondary-container');
178
+
179
+ &:hover {
180
+ @include m.state-layer(t.color('on-secondary-container'), 'hover');
181
+ }
182
+
183
+ &:active {
184
+ @include m.state-layer(t.color('on-secondary-container'), 'pressed');
185
+ }
186
+ }
187
+
188
+ &[aria-disabled="true"] {
189
+ @include m.elevation(0);
190
+ box-shadow: none;
191
+ }
192
+ }
193
+
194
+ // Assist chip
195
+ &--assist {
196
+ background-color: t.color('surface-container');
197
+ color: t.color('on-surface');
198
+
199
+ &:hover {
200
+ @include m.state-layer(t.color('on-surface'), 'hover');
201
+ }
202
+
203
+ &:active {
204
+ @include m.state-layer(t.color('on-surface'), 'pressed');
205
+ }
206
+
207
+ .#{$component}-icon {
208
+ color: t.color('primary');
209
+ }
210
+ }
211
+
212
+ // Filter chip
213
+ &--filter {
214
+ background-color: t.color('surface-container-highest');
215
+ color: t.color('on-surface');
216
+
217
+ &:hover {
218
+ @include m.state-layer(t.color('on-surface'), 'hover');
219
+ }
220
+
221
+ &:active {
222
+ @include m.state-layer(t.color('on-surface'), 'pressed');
223
+ }
224
+
225
+ &.#{$component}--selected {
226
+ background-color: t.color('secondary-container');
227
+ color: t.color('on-secondary-container');
228
+
229
+ &:hover {
230
+ @include m.state-layer(t.color('on-secondary-container'), 'hover');
231
+ }
232
+
233
+ &:active {
234
+ @include m.state-layer(t.color('on-secondary-container'), 'pressed');
235
+ }
236
+
237
+ // Checkmark icon for selected filter chips
238
+ .#{$component}-icon {
239
+ color: t.color('on-secondary-container');
240
+ }
241
+ }
242
+ }
243
+
244
+ // Input chip
245
+ &--input {
246
+ background-color: t.color('surface-container-highest');
247
+ color: t.color('on-surface');
248
+ padding-right: 8px; // Less padding on the right to accommodate the trailing icon
249
+
250
+ &:hover {
251
+ @include m.state-layer(t.color('on-surface'), 'hover');
252
+ }
253
+
254
+ .#{$component}-trailing-icon {
255
+ color: t.color('on-surface-variant');
256
+
257
+ &:hover {
258
+ color: t.color('on-surface');
259
+ }
260
+ }
261
+ }
262
+
263
+ // Suggestion chip
264
+ &--suggestion {
265
+ background-color: t.color('surface-container');
266
+ color: t.color('on-surface');
267
+
268
+ &:hover {
269
+ @include m.state-layer(t.color('on-surface'), 'hover');
270
+ }
271
+
272
+ &:active {
273
+ @include m.state-layer(t.color('on-surface'), 'pressed');
274
+ }
275
+ }
276
+
277
+ // === SIZES ===
278
+
279
+ &--small {
280
+ height: 24px;
281
+ padding: 0 8px;
282
+ font-size: 12px;
283
+
284
+ .#{$component}-icon,
285
+ .#{$component}-trailing-icon {
286
+ width: 16px;
287
+ height: 16px;
288
+
289
+ svg {
290
+ width: 16px;
291
+ height: 16px;
292
+ }
293
+ }
294
+
295
+ .#{$component}-icon {
296
+ margin-right: 4px;
297
+ }
298
+
299
+ .#{$component}-trailing-icon {
300
+ margin-left: 4px;
301
+ }
302
+ }
303
+
304
+ &--large {
305
+ height: 40px;
306
+ padding: 0 16px;
307
+ font-size: 15px;
308
+ border-radius: 12px;
309
+
310
+ .#{$component}-icon,
311
+ .#{$component}-trailing-icon {
312
+ width: 20px;
313
+ height: 20px;
314
+
315
+ svg {
316
+ width: 20px;
317
+ height: 20px;
318
+ }
319
+ }
320
+
321
+ .#{$component}-icon {
322
+ margin-right: 10px;
323
+ }
324
+
325
+ .#{$component}-trailing-icon {
326
+ margin-left: 10px;
327
+ }
328
+ }
329
+
330
+ // === SPECIAL CASES ===
331
+
332
+ // For chips with only icons (no text)
333
+ &--icon-only {
334
+ padding: 0;
335
+ width: 32px;
336
+
337
+ &.#{$component}--small {
338
+ width: 24px;
339
+ }
340
+
341
+ &.#{$component}--large {
342
+ width: 40px;
343
+ }
344
+
345
+ .#{$component}-icon {
346
+ margin-right: 0;
347
+ }
348
+ }
349
+ }
350
+
351
+ // === CHIP SET STYLES ===
352
+
353
+ .#{$component}-set {
354
+ display: flex;
355
+ flex-wrap: wrap;
356
+ gap: 8px;
357
+
358
+ &--scrollable {
359
+ flex-wrap: nowrap;
360
+ overflow-x: auto;
361
+ scrollbar-width: none; // Firefox
362
+
363
+ &::-webkit-scrollbar {
364
+ display: none; // Chrome, Safari, Edge
365
+ }
366
+ }
367
+
368
+ &--vertical {
369
+ flex-direction: column;
370
+ align-items: flex-start;
371
+ }
372
+ }
@@ -0,0 +1,115 @@
1
+ // src/components/chip/api.js
2
+
3
+ /**
4
+ * Enhances a chip component with API methods
5
+ * @param {Object} options - API configuration options
6
+ * @param {Object} options.disabled - Object containing enable/disable methods
7
+ * @param {Object} options.lifecycle - Object containing lifecycle methods
8
+ * @returns {Function} Higher-order function that adds API methods to component
9
+ * @internal This is an internal utility for the Chip component
10
+ */
11
+ export const withAPI = ({ disabled, lifecycle }) => (component) => ({
12
+ ...component,
13
+ element: component.element,
14
+
15
+ /**
16
+ * Gets the chip's value
17
+ * @returns {string} The chip's value attribute
18
+ */
19
+ getValue: () => component.element.getAttribute('data-value'),
20
+
21
+ /**
22
+ * Sets the chip's value
23
+ * @param {string} value - Value to set
24
+ * @returns {Object} The chip instance for chaining
25
+ */
26
+ setValue (value) {
27
+ component.element.setAttribute('data-value', value)
28
+ return this
29
+ },
30
+
31
+ /**
32
+ * Enables the chip
33
+ * @returns {Object} The chip instance for chaining
34
+ */
35
+ enable () {
36
+ disabled.enable()
37
+ component.element.setAttribute('aria-disabled', 'false')
38
+ return this
39
+ },
40
+
41
+ /**
42
+ * Disables the chip
43
+ * @returns {Object} The chip instance for chaining
44
+ */
45
+ disable () {
46
+ disabled.disable()
47
+ component.element.setAttribute('aria-disabled', 'true')
48
+ return this
49
+ },
50
+
51
+ /**
52
+ * Sets the chip's text content
53
+ * @param {string} content - Text content
54
+ * @returns {Object} The chip instance for chaining
55
+ */
56
+ setText (content) {
57
+ component.text.setText(content)
58
+ return this
59
+ },
60
+
61
+ /**
62
+ * Gets the chip's text content
63
+ * @returns {string} The chip's text content
64
+ */
65
+ getText () {
66
+ return component.text.getText()
67
+ },
68
+
69
+ /**
70
+ * Sets the chip's leading icon
71
+ * @param {string} icon - Icon HTML content
72
+ * @returns {Object} The chip instance for chaining
73
+ */
74
+ setIcon (icon) {
75
+ component.icon.setIcon(icon)
76
+ return this
77
+ },
78
+
79
+ /**
80
+ * Gets the chip's icon content
81
+ * @returns {string} The chip's icon HTML
82
+ */
83
+ getIcon () {
84
+ return component.icon.getIcon()
85
+ },
86
+
87
+ /**
88
+ * Sets the chip's trailing icon
89
+ * @param {string} icon - Icon HTML content
90
+ * @returns {Object} The chip instance for chaining
91
+ */
92
+ setTrailingIcon (icon) {
93
+ const trailingIconSelector = `.${component.getClass('chip')}-trailing-icon`
94
+ let trailingIconElement = component.element.querySelector(trailingIconSelector)
95
+
96
+ if (!trailingIconElement && icon) {
97
+ trailingIconElement = document.createElement('span')
98
+ trailingIconElement.className = `${component.getClass('chip')}-trailing-icon`
99
+ component.element.appendChild(trailingIconElement)
100
+ }
101
+
102
+ if (trailingIconElement) {
103
+ trailingIconElement.innerHTML = icon || ''
104
+ }
105
+
106
+ return this
107
+ },
108
+
109
+ /**
110
+ * Destroys the chip component and cleans up resources
111
+ */
112
+ destroy () {
113
+ lifecycle.destroy()
114
+ }
115
+ })
@@ -0,0 +1,225 @@
1
+ // src/components/chip/chip-set.js
2
+ import { PREFIX } from '../../core/config'
3
+ import createChip from './chip'
4
+
5
+ /**
6
+ * Creates a chip set container for grouping related chips
7
+ * @param {Object} config - ChipSet configuration
8
+ * @param {Array} [config.chips=[]] - Array of chip configurations to initialize
9
+ * @param {boolean} [config.scrollable=false] - Whether the chip set is horizontally scrollable
10
+ * @param {boolean} [config.vertical=false] - Whether the chip set is vertically stacked
11
+ * @param {string} [config.class] - Additional CSS classes
12
+ * @param {string} [config.selector] - CSS selector for filtering behavior
13
+ * @param {boolean} [config.multiSelect=false] - Whether multiple chips can be selected simultaneously
14
+ * @param {Function} [config.onChange] - Callback function when chip selection changes
15
+ * @returns {Object} ChipSet component instance
16
+ */
17
+ const createChipSet = (config = {}) => {
18
+ const {
19
+ chips = [],
20
+ scrollable = false,
21
+ vertical = false,
22
+ class: customClass,
23
+ selector = null,
24
+ multiSelect = false,
25
+ onChange = null
26
+ } = config
27
+
28
+ // Create container element
29
+ const element = document.createElement('div')
30
+ element.className = `${PREFIX}-chip-set`
31
+
32
+ if (customClass) {
33
+ element.classList.add(customClass)
34
+ }
35
+
36
+ if (scrollable) {
37
+ element.classList.add(`${PREFIX}-chip-set--scrollable`)
38
+ }
39
+
40
+ if (vertical) {
41
+ element.classList.add(`${PREFIX}-chip-set--vertical`)
42
+ }
43
+
44
+ // Store chip instances
45
+ const chipInstances = []
46
+
47
+ /**
48
+ * Updates chip selection states based on multiSelect configuration
49
+ * @param {Object} selectedChip - The chip that was clicked/selected
50
+ */
51
+ const handleSelection = (selectedChip) => {
52
+ if (!multiSelect) {
53
+ // Single selection mode - deselect all other chips
54
+ chipInstances.forEach(chip => {
55
+ if (chip !== selectedChip && chip.isSelected()) {
56
+ chip.setSelected(false)
57
+ }
58
+ })
59
+ }
60
+
61
+ // Call onChange callback if provided
62
+ if (typeof onChange === 'function') {
63
+ const selectedChips = chipInstances.filter(chip => chip.isSelected())
64
+ onChange(selectedChips, selectedChip)
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Adds a chip to the chip set
70
+ * @param {Object} chipConfig - Configuration for the chip
71
+ * @returns {Object} The created chip instance
72
+ */
73
+ const addChip = (chipConfig) => {
74
+ const chipInstance = createChip({
75
+ ...chipConfig,
76
+ onSelect: (chip) => {
77
+ handleSelection(chip)
78
+ if (chipConfig.onSelect) {
79
+ chipConfig.onSelect(chip)
80
+ }
81
+ }
82
+ })
83
+
84
+ element.appendChild(chipInstance.element)
85
+ chipInstances.push(chipInstance)
86
+
87
+ // Add click handler to toggle selection
88
+ chipInstance.element.addEventListener('click', () => {
89
+ if (!chipInstance.element.getAttribute('aria-disabled') === 'true') {
90
+ chipInstance.toggleSelected()
91
+ handleSelection(chipInstance)
92
+ }
93
+ })
94
+
95
+ return chipInstance
96
+ }
97
+
98
+ // Initialize with provided chips
99
+ chips.forEach(chipConfig => addChip(chipConfig))
100
+
101
+ return {
102
+ element,
103
+
104
+ /**
105
+ * Adds a new chip to the chip set
106
+ * @param {Object} chipConfig - Configuration for the chip
107
+ * @returns {Object} The chip set instance for chaining
108
+ */
109
+ addChip (chipConfig) {
110
+ addChip(chipConfig)
111
+ return this
112
+ },
113
+
114
+ /**
115
+ * Removes a chip from the chip set
116
+ * @param {Object|number} chipOrIndex - Chip instance or index to remove
117
+ * @returns {Object} The chip set instance for chaining
118
+ */
119
+ removeChip (chipOrIndex) {
120
+ const index = typeof chipOrIndex === 'number'
121
+ ? chipOrIndex
122
+ : chipInstances.indexOf(chipOrIndex)
123
+
124
+ if (index >= 0 && index < chipInstances.length) {
125
+ const chip = chipInstances[index]
126
+ chip.destroy()
127
+ chipInstances.splice(index, 1)
128
+ }
129
+
130
+ return this
131
+ },
132
+
133
+ /**
134
+ * Gets all chip instances in the set
135
+ * @returns {Array} Array of chip instances
136
+ */
137
+ getChips () {
138
+ return [...chipInstances]
139
+ },
140
+
141
+ /**
142
+ * Gets currently selected chips
143
+ * @returns {Array} Array of selected chip instances
144
+ */
145
+ getSelectedChips () {
146
+ return chipInstances.filter(chip => chip.isSelected())
147
+ },
148
+
149
+ /**
150
+ * Gets the values of selected chips
151
+ * @returns {Array} Array of selected chip values
152
+ */
153
+ getSelectedValues () {
154
+ return this.getSelectedChips().map(chip => chip.getValue())
155
+ },
156
+
157
+ /**
158
+ * Selects chips by their values
159
+ * @param {Array|string} values - Value or array of values to select
160
+ * @returns {Object} The chip set instance for chaining
161
+ */
162
+ selectByValue (values) {
163
+ const valueArray = Array.isArray(values) ? values : [values]
164
+
165
+ chipInstances.forEach(chip => {
166
+ const shouldSelect = valueArray.includes(chip.getValue())
167
+ if (shouldSelect !== chip.isSelected()) {
168
+ chip.setSelected(shouldSelect)
169
+ }
170
+ })
171
+
172
+ return this
173
+ },
174
+
175
+ /**
176
+ * Clears all selections
177
+ * @returns {Object} The chip set instance for chaining
178
+ */
179
+ clearSelection () {
180
+ chipInstances.forEach(chip => {
181
+ chip.setSelected(false)
182
+ })
183
+ return this
184
+ },
185
+
186
+ /**
187
+ * Sets the scrollable state of the chip set
188
+ * @param {boolean} isScrollable - Whether the chip set should be scrollable
189
+ * @returns {Object} The chip set instance for chaining
190
+ */
191
+ setScrollable (isScrollable) {
192
+ if (isScrollable) {
193
+ element.classList.add(`${PREFIX}-chip-set--scrollable`)
194
+ } else {
195
+ element.classList.remove(`${PREFIX}-chip-set--scrollable`)
196
+ }
197
+ return this
198
+ },
199
+
200
+ /**
201
+ * Sets the vertical layout state
202
+ * @param {boolean} isVertical - Whether the chip set should be vertically stacked
203
+ * @returns {Object} The chip set instance for chaining
204
+ */
205
+ setVertical (isVertical) {
206
+ if (isVertical) {
207
+ element.classList.add(`${PREFIX}-chip-set--vertical`)
208
+ } else {
209
+ element.classList.remove(`${PREFIX}-chip-set--vertical`)
210
+ }
211
+ return this
212
+ },
213
+
214
+ /**
215
+ * Destroys the chip set and all contained chips
216
+ */
217
+ destroy () {
218
+ chipInstances.forEach(chip => chip.destroy())
219
+ chipInstances.length = 0
220
+ element.remove()
221
+ }
222
+ }
223
+ }
224
+
225
+ export default createChipSet