mtrl 0.3.1 → 0.3.3

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 (162) hide show
  1. package/.env +15 -0
  2. package/CONTRIBUTING.md +62 -23
  3. package/DOCS.md +3 -3
  4. package/README.md +43 -20
  5. package/TESTING.md +128 -18
  6. package/dist/index.js +14865 -0
  7. package/git-user-stats.js +545 -0
  8. package/index.ts +9 -67
  9. package/package.json +8 -3
  10. package/src/components/badge/api.ts +15 -1
  11. package/src/components/badge/badge.ts +43 -4
  12. package/src/components/badge/config.ts +40 -8
  13. package/src/components/badge/index.ts +64 -3
  14. package/src/components/badge/types.ts +175 -33
  15. package/src/components/button/api.ts +63 -1
  16. package/src/components/button/button.ts +39 -3
  17. package/src/components/button/config.ts +21 -4
  18. package/src/components/button/index.ts +26 -1
  19. package/src/components/button/types.ts +7 -1
  20. package/src/components/card/api.ts +78 -9
  21. package/src/components/card/card.ts +58 -3
  22. package/src/components/card/config.ts +41 -11
  23. package/src/components/card/features.ts +39 -12
  24. package/src/components/card/index.ts +84 -19
  25. package/src/components/card/types.ts +218 -29
  26. package/src/components/carousel/carousel.ts +92 -28
  27. package/src/components/carousel/constants.ts +107 -21
  28. package/src/components/carousel/index.ts +31 -13
  29. package/src/components/checkbox/checkbox.ts +83 -16
  30. package/src/components/checkbox/index.ts +43 -1
  31. package/src/components/checkbox/types.ts +219 -32
  32. package/src/components/chips/api.ts +194 -0
  33. package/src/components/{chip → chips/chip}/api.ts +42 -2
  34. package/src/components/chips/chip/chip.ts +131 -0
  35. package/src/components/{chip → chips/chip}/config.ts +3 -3
  36. package/src/components/chips/chip/index.ts +3 -0
  37. package/src/components/chips/chips.md +481 -0
  38. package/src/components/chips/chips.ts +75 -0
  39. package/src/components/chips/config.ts +109 -0
  40. package/src/components/chips/constants.ts +61 -0
  41. package/src/components/chips/features/chip-items.ts +33 -0
  42. package/src/components/chips/features/container.ts +77 -0
  43. package/src/components/chips/features/controller.ts +448 -0
  44. package/src/components/chips/features/index.ts +5 -0
  45. package/src/components/chips/features/label.ts +108 -0
  46. package/src/components/chips/index.ts +11 -0
  47. package/src/components/chips/schema.ts +61 -0
  48. package/src/components/{chip → chips}/types.ts +203 -92
  49. package/src/components/dialog/dialog.ts +99 -16
  50. package/src/components/dialog/index.ts +97 -1
  51. package/src/components/dialog/types.ts +375 -69
  52. package/src/components/divider/config.ts +90 -6
  53. package/src/components/divider/divider.ts +32 -2
  54. package/src/components/divider/features.ts +26 -0
  55. package/src/components/divider/index.ts +30 -0
  56. package/src/components/divider/types.ts +86 -9
  57. package/src/components/extended-fab/api.ts +53 -1
  58. package/src/components/extended-fab/config.ts +29 -1
  59. package/src/components/extended-fab/extended-fab.ts +28 -0
  60. package/src/components/extended-fab/index.ts +36 -0
  61. package/src/components/extended-fab/types.ts +458 -13
  62. package/src/components/fab/api.ts +42 -2
  63. package/src/components/fab/config.ts +29 -1
  64. package/src/components/fab/fab.ts +16 -2
  65. package/src/components/fab/index.ts +35 -0
  66. package/src/components/fab/types.ts +374 -10
  67. package/src/components/list/api.ts +12 -2
  68. package/src/components/list/config.ts +21 -0
  69. package/src/components/list/features.ts +6 -0
  70. package/src/components/list/index.ts +56 -1
  71. package/src/components/list/list-item.ts +46 -2
  72. package/src/components/list/list.ts +73 -2
  73. package/src/components/list/types.ts +172 -0
  74. package/src/components/list/utils.ts +26 -2
  75. package/src/components/menu/api.ts +217 -20
  76. package/src/components/menu/config.ts +27 -0
  77. package/src/components/menu/features/visibility.ts +55 -6
  78. package/src/components/menu/index.ts +64 -0
  79. package/src/components/menu/menu-item.ts +46 -3
  80. package/src/components/menu/menu.ts +77 -1
  81. package/src/components/menu/types.ts +404 -39
  82. package/src/components/navigation/nav-item.ts +13 -2
  83. package/src/components/sheet/config.ts +1 -2
  84. package/src/components/sheet/features/gestures.ts +1 -1
  85. package/src/components/sheet/features/position.ts +1 -2
  86. package/src/components/sheet/features/state.ts +1 -1
  87. package/src/components/sheet/index.ts +10 -2
  88. package/src/components/sheet/sheet.ts +1 -2
  89. package/src/components/sheet/types.ts +29 -1
  90. package/src/components/slider/api.ts +1 -1
  91. package/src/components/slider/config.ts +1 -1
  92. package/src/components/slider/features/controller.ts +1 -1
  93. package/src/components/slider/features/handlers.ts +1 -1
  94. package/src/components/slider/features/states.ts +1 -1
  95. package/src/components/slider/index.ts +12 -5
  96. package/src/components/slider/schema.ts +1 -1
  97. package/src/components/slider/types.ts +31 -0
  98. package/src/components/tabs/tab-api.ts +1 -1
  99. package/src/components/tabs/types.ts +1 -1
  100. package/src/components/tooltip/api.ts +6 -2
  101. package/src/components/tooltip/config.ts +9 -28
  102. package/src/components/tooltip/index.ts +10 -1
  103. package/src/components/tooltip/types.ts +38 -3
  104. package/src/core/dom/create.ts +57 -51
  105. package/src/index.ts +129 -31
  106. package/src/styles/abstract/_mixins.scss +23 -9
  107. package/src/styles/abstract/_variables.scss +14 -4
  108. package/src/styles/components/_card.scss +1 -1
  109. package/src/styles/components/_chip.scss +323 -113
  110. package/src/styles/components/_tabs.scss +1 -1
  111. package/src/styles/themes/_autumn.scss +3 -0
  112. package/CLAUDE.md +0 -33
  113. package/src/components/checkbox/constants.ts +0 -37
  114. package/src/components/chip/chip-set.ts +0 -225
  115. package/src/components/chip/chip.ts +0 -118
  116. package/src/components/chip/constants.ts +0 -28
  117. package/src/components/chip/index.ts +0 -12
  118. package/src/components/list/constants.ts +0 -116
  119. package/src/components/sheet/constants.ts +0 -20
  120. package/src/components/slider/constants.ts +0 -32
  121. package/src/components/tooltip/constants.ts +0 -27
  122. package/test/components/badge.test.ts +0 -545
  123. package/test/components/bottom-app-bar.test.ts +0 -303
  124. package/test/components/button.test.ts +0 -233
  125. package/test/components/card.test.ts +0 -560
  126. package/test/components/carousel.test.ts +0 -951
  127. package/test/components/checkbox.test.ts +0 -462
  128. package/test/components/chip.test.ts +0 -692
  129. package/test/components/datepicker.test.ts +0 -1124
  130. package/test/components/dialog.test.ts +0 -990
  131. package/test/components/divider.test.ts +0 -412
  132. package/test/components/extended-fab.test.ts +0 -672
  133. package/test/components/fab.test.ts +0 -561
  134. package/test/components/list.test.ts +0 -365
  135. package/test/components/menu.test.ts +0 -718
  136. package/test/components/navigation.test.ts +0 -186
  137. package/test/components/progress.test.ts +0 -567
  138. package/test/components/radios.test.ts +0 -699
  139. package/test/components/search.test.ts +0 -1135
  140. package/test/components/segmented-button.test.ts +0 -732
  141. package/test/components/sheet.test.ts +0 -641
  142. package/test/components/slider.test.ts +0 -1220
  143. package/test/components/snackbar.test.ts +0 -461
  144. package/test/components/switch.test.ts +0 -452
  145. package/test/components/tabs.test.ts +0 -1369
  146. package/test/components/textfield.test.ts +0 -400
  147. package/test/components/timepicker.test.ts +0 -592
  148. package/test/components/tooltip.test.ts +0 -630
  149. package/test/components/top-app-bar.test.ts +0 -566
  150. package/test/core/dom.attributes.test.ts +0 -148
  151. package/test/core/dom.classes.test.ts +0 -152
  152. package/test/core/dom.events.test.ts +0 -243
  153. package/test/core/emitter.test.ts +0 -141
  154. package/test/core/ripple.test.ts +0 -99
  155. package/test/core/state.store.test.ts +0 -189
  156. package/test/core/utils.normalize.test.ts +0 -61
  157. package/test/core/utils.object.test.ts +0 -120
  158. package/test/setup.js +0 -371
  159. package/test/setup.ts +0 -451
  160. package/tsconfig.json +0 -22
  161. package/typedoc.json +0 -28
  162. package/typedoc.simple.json +0 -14
@@ -1,692 +0,0 @@
1
- // test/components/chip.test.ts
2
- import { describe, test, expect } from 'bun:test';
3
- import {
4
- type ChipComponent,
5
- type ChipConfig,
6
- type ChipVariant
7
- } from '../../src/components/chip/types';
8
-
9
- // Constants for chip variants
10
- const CHIP_VARIANTS = {
11
- FILLED: 'filled',
12
- OUTLINED: 'outlined',
13
- ELEVATED: 'elevated',
14
- ASSIST: 'assist',
15
- FILTER: 'filter',
16
- INPUT: 'input',
17
- SUGGESTION: 'suggestion'
18
- } as const;
19
-
20
- // Mock chip implementation
21
- const createMockChip = (config: ChipConfig = {}): ChipComponent => {
22
- // Create the main element
23
- const element = document.createElement('div');
24
- element.className = 'mtrl-chip';
25
-
26
- // Set default configuration
27
- const componentConfig = {
28
- componentName: 'chip',
29
- prefix: config.prefix || 'mtrl',
30
- variant: config.variant || CHIP_VARIANTS.FILLED,
31
- disabled: config.disabled || false,
32
- selected: config.selected || false,
33
- ripple: config.ripple !== undefined ? config.ripple : true
34
- };
35
-
36
- // Apply variant class
37
- if (componentConfig.variant) {
38
- element.classList.add(`mtrl-chip--${componentConfig.variant}`);
39
- }
40
-
41
- // Apply disabled state
42
- if (componentConfig.disabled) {
43
- element.classList.add('mtrl-chip--disabled');
44
- element.setAttribute('aria-disabled', 'true');
45
- }
46
-
47
- // Apply selected state
48
- if (componentConfig.selected) {
49
- element.classList.add('mtrl-chip--selected');
50
- element.setAttribute('aria-selected', 'true');
51
- }
52
-
53
- // Apply value if provided
54
- if (config.value) {
55
- element.setAttribute('data-value', config.value);
56
- }
57
-
58
- // Apply additional classes
59
- if (config.class) {
60
- const classes = config.class.split(' ');
61
- classes.forEach(className => element.classList.add(className));
62
- }
63
-
64
- // Create ripple element if enabled
65
- if (componentConfig.ripple) {
66
- const ripple = document.createElement('span');
67
- ripple.className = 'mtrl-chip__ripple';
68
- element.appendChild(ripple);
69
- }
70
-
71
- // Create text element
72
- const textElement = document.createElement('span');
73
- textElement.className = 'mtrl-chip__text';
74
- if (config.text) {
75
- textElement.textContent = config.text;
76
- }
77
- element.appendChild(textElement);
78
-
79
- // Create leading icon element if provided
80
- let leadingIconElement: HTMLElement | null = null;
81
- if (config.leadingIcon || config.icon) {
82
- leadingIconElement = document.createElement('span');
83
- leadingIconElement.className = 'mtrl-chip__icon mtrl-chip__icon--leading';
84
- leadingIconElement.innerHTML = config.leadingIcon || config.icon || '';
85
- element.insertBefore(leadingIconElement, textElement);
86
- }
87
-
88
- // Create trailing icon element if provided
89
- let trailingIconElement: HTMLElement | null = null;
90
- if (config.trailingIcon) {
91
- trailingIconElement = document.createElement('span');
92
- trailingIconElement.className = 'mtrl-chip__icon mtrl-chip__icon--trailing';
93
- trailingIconElement.innerHTML = config.trailingIcon;
94
- element.appendChild(trailingIconElement);
95
-
96
- // Add click handler if provided
97
- if (config.onTrailingIconClick) {
98
- trailingIconElement.addEventListener('click', (e) => {
99
- e.stopPropagation();
100
- if (config.onTrailingIconClick) {
101
- config.onTrailingIconClick(chip);
102
- }
103
- });
104
- }
105
- }
106
-
107
- // Set up event handlers
108
- const eventHandlers: Record<string, Function[]> = {};
109
-
110
- const emit = (event: string, data?: any) => {
111
- if (eventHandlers[event]) {
112
- eventHandlers[event].forEach(handler => handler(data));
113
- }
114
- };
115
-
116
- // Click handler to toggle selected state if selectable
117
- const handleClick = () => {
118
- if (componentConfig.disabled) return;
119
-
120
- if (config.selectable ||
121
- componentConfig.variant === CHIP_VARIANTS.FILTER ||
122
- componentConfig.variant === CHIP_VARIANTS.INPUT) {
123
- chip.toggleSelected();
124
-
125
- if (config.onChange) {
126
- config.onChange(chip);
127
- }
128
-
129
- emit('change', { selected: chip.isSelected() });
130
- }
131
-
132
- emit('click');
133
- };
134
-
135
- // Add click handler to the element
136
- element.addEventListener('click', handleClick);
137
-
138
- // Initialize text API
139
- const textAPI = {
140
- setText: (content: string) => {
141
- textElement.textContent = content;
142
- return textAPI;
143
- },
144
- getText: () => textElement.textContent || '',
145
- getElement: () => textElement
146
- };
147
-
148
- // Initialize icon API
149
- const iconAPI = {
150
- setIcon: (html: string) => {
151
- if (!leadingIconElement) {
152
- leadingIconElement = document.createElement('span');
153
- leadingIconElement.className = 'mtrl-chip__icon mtrl-chip__icon--leading';
154
- element.insertBefore(leadingIconElement, textElement);
155
- }
156
- leadingIconElement.innerHTML = html;
157
- return iconAPI;
158
- },
159
- getIcon: () => leadingIconElement ? leadingIconElement.innerHTML : '',
160
- getElement: () => leadingIconElement
161
- };
162
-
163
- // Create the chip component
164
- const chip: ChipComponent = {
165
- element,
166
- text: textAPI,
167
- icon: iconAPI,
168
-
169
- disabled: {
170
- enable: () => {
171
- element.classList.remove('mtrl-chip--disabled');
172
- element.removeAttribute('aria-disabled');
173
- },
174
- disable: () => {
175
- element.classList.add('mtrl-chip--disabled');
176
- element.setAttribute('aria-disabled', 'true');
177
- },
178
- isDisabled: () => element.classList.contains('mtrl-chip--disabled')
179
- },
180
-
181
- lifecycle: {
182
- destroy: () => {
183
- chip.destroy();
184
- }
185
- },
186
-
187
- getClass: (name: string) => {
188
- const prefix = componentConfig.prefix;
189
- return name ? `${prefix}-${name}` : `${prefix}-chip`;
190
- },
191
-
192
- getValue: () => element.getAttribute('data-value'),
193
-
194
- setValue: (value: string) => {
195
- element.setAttribute('data-value', value);
196
- return chip;
197
- },
198
-
199
- enable: () => {
200
- chip.disabled.enable();
201
- return chip;
202
- },
203
-
204
- disable: () => {
205
- chip.disabled.disable();
206
- return chip;
207
- },
208
-
209
- isDisabled: () => chip.disabled.isDisabled(),
210
-
211
- setText: (content: string) => {
212
- textAPI.setText(content);
213
- return chip;
214
- },
215
-
216
- getText: () => textAPI.getText(),
217
-
218
- setIcon: (icon: string) => {
219
- iconAPI.setIcon(icon);
220
- return chip;
221
- },
222
-
223
- getIcon: () => iconAPI.getIcon(),
224
-
225
- setLeadingIcon: (icon: string) => {
226
- iconAPI.setIcon(icon);
227
- return chip;
228
- },
229
-
230
- setTrailingIcon: (icon: string, onClick?: (chip: ChipComponent) => void) => {
231
- if (!trailingIconElement) {
232
- trailingIconElement = document.createElement('span');
233
- trailingIconElement.className = 'mtrl-chip__icon mtrl-chip__icon--trailing';
234
- element.appendChild(trailingIconElement);
235
- }
236
-
237
- trailingIconElement.innerHTML = icon;
238
-
239
- // Clear previous handlers and add new one if provided
240
- const newTrailingElement = trailingIconElement.cloneNode(true);
241
- trailingIconElement.parentNode?.replaceChild(newTrailingElement, trailingIconElement);
242
- trailingIconElement = newTrailingElement as HTMLElement;
243
-
244
- if (onClick) {
245
- trailingIconElement.addEventListener('click', (e) => {
246
- e.stopPropagation();
247
- onClick(chip);
248
- });
249
- }
250
-
251
- return chip;
252
- },
253
-
254
- isSelected: () => element.classList.contains('mtrl-chip--selected'),
255
-
256
- setSelected: (selected: boolean) => {
257
- if (selected) {
258
- element.classList.add('mtrl-chip--selected');
259
- element.setAttribute('aria-selected', 'true');
260
-
261
- if (config.onSelect) {
262
- config.onSelect(chip);
263
- }
264
- } else {
265
- element.classList.remove('mtrl-chip--selected');
266
- element.removeAttribute('aria-selected');
267
- }
268
-
269
- return chip;
270
- },
271
-
272
- toggleSelected: () => {
273
- const newSelectedState = !chip.isSelected();
274
- chip.setSelected(newSelectedState);
275
- return chip;
276
- },
277
-
278
- destroy: () => {
279
- // Remove event listeners
280
- element.removeEventListener('click', handleClick);
281
-
282
- // Remove element from DOM if it has a parent
283
- if (element.parentNode) {
284
- element.parentNode.removeChild(element);
285
- }
286
-
287
- // Clear event handlers
288
- for (const event in eventHandlers) {
289
- eventHandlers[event] = [];
290
- }
291
- },
292
-
293
- on: (event: string, handler: Function) => {
294
- if (!eventHandlers[event]) {
295
- eventHandlers[event] = [];
296
- }
297
- eventHandlers[event].push(handler);
298
- return chip;
299
- },
300
-
301
- off: (event: string, handler: Function) => {
302
- if (eventHandlers[event]) {
303
- eventHandlers[event] = eventHandlers[event].filter(h => h !== handler);
304
- }
305
- return chip;
306
- },
307
-
308
- addClass: (...classes: string[]) => {
309
- classes.forEach(className => element.classList.add(className));
310
- return chip;
311
- }
312
- };
313
-
314
- return chip;
315
- };
316
-
317
- describe('Chip Component', () => {
318
- test('should create a chip element', () => {
319
- const chip = createMockChip();
320
- expect(chip.element).toBeDefined();
321
- expect(chip.element.tagName).toBe('DIV');
322
- expect(chip.element.className).toContain('mtrl-chip');
323
- });
324
-
325
- test('should apply variant classes', () => {
326
- const variants: ChipVariant[] = [
327
- CHIP_VARIANTS.FILLED,
328
- CHIP_VARIANTS.OUTLINED,
329
- CHIP_VARIANTS.ELEVATED,
330
- CHIP_VARIANTS.ASSIST,
331
- CHIP_VARIANTS.FILTER,
332
- CHIP_VARIANTS.INPUT,
333
- CHIP_VARIANTS.SUGGESTION
334
- ];
335
-
336
- variants.forEach(variant => {
337
- const chip = createMockChip({ variant });
338
- expect(chip.element.className).toContain(`mtrl-chip--${variant}`);
339
- });
340
- });
341
-
342
- test('should set initial text content', () => {
343
- const chip = createMockChip({ text: 'Test Chip' });
344
-
345
- const textElement = chip.element.querySelector('.mtrl-chip__text');
346
- expect(textElement).toBeDefined();
347
- expect(textElement?.textContent).toBe('Test Chip');
348
- expect(chip.getText()).toBe('Test Chip');
349
- });
350
-
351
- test('should set initial leading icon', () => {
352
- const iconHtml = '<svg><path></path></svg>';
353
- const chip = createMockChip({ leadingIcon: iconHtml });
354
-
355
- const iconElement = chip.element.querySelector('.mtrl-chip__icon--leading');
356
- expect(iconElement).toBeDefined();
357
- expect(iconElement?.innerHTML).toBe(iconHtml);
358
- expect(chip.getIcon()).toBe(iconHtml);
359
- });
360
-
361
- test('should use icon as alias for leadingIcon', () => {
362
- const iconHtml = '<svg><path></path></svg>';
363
- const chip = createMockChip({ icon: iconHtml });
364
-
365
- const iconElement = chip.element.querySelector('.mtrl-chip__icon--leading');
366
- expect(iconElement).toBeDefined();
367
- expect(iconElement?.innerHTML).toBe(iconHtml);
368
- expect(chip.getIcon()).toBe(iconHtml);
369
- });
370
-
371
- test('should set initial trailing icon', () => {
372
- const iconHtml = '<svg><path></path></svg>';
373
- const chip = createMockChip({ trailingIcon: iconHtml });
374
-
375
- const iconElement = chip.element.querySelector('.mtrl-chip__icon--trailing');
376
- expect(iconElement).toBeDefined();
377
- expect(iconElement?.innerHTML).toBe(iconHtml);
378
- });
379
-
380
- test('should set value attribute', () => {
381
- const chip = createMockChip({ value: 'chip-123' });
382
-
383
- expect(chip.element.getAttribute('data-value')).toBe('chip-123');
384
- expect(chip.getValue()).toBe('chip-123');
385
- });
386
-
387
- test('should create ripple element by default', () => {
388
- const chip = createMockChip();
389
-
390
- const rippleElement = chip.element.querySelector('.mtrl-chip__ripple');
391
- expect(rippleElement).toBeDefined();
392
- });
393
-
394
- test('should not create ripple element when disabled', () => {
395
- const chip = createMockChip({ ripple: false });
396
-
397
- const rippleElement = chip.element.querySelector('.mtrl-chip__ripple');
398
- expect(rippleElement).toBeNull();
399
- });
400
-
401
- test('should apply disabled state', () => {
402
- const chip = createMockChip({ disabled: true });
403
-
404
- expect(chip.element.className).toContain('mtrl-chip--disabled');
405
- expect(chip.element.getAttribute('aria-disabled')).toBe('true');
406
- expect(chip.isDisabled()).toBe(true);
407
- });
408
-
409
- test('should apply selected state', () => {
410
- const chip = createMockChip({ selected: true });
411
-
412
- expect(chip.element.className).toContain('mtrl-chip--selected');
413
- expect(chip.element.getAttribute('aria-selected')).toBe('true');
414
- expect(chip.isSelected()).toBe(true);
415
- });
416
-
417
- test('should be able to change text content', () => {
418
- const chip = createMockChip({ text: 'Initial Text' });
419
-
420
- expect(chip.getText()).toBe('Initial Text');
421
-
422
- chip.setText('Updated Text');
423
-
424
- expect(chip.getText()).toBe('Updated Text');
425
-
426
- const textElement = chip.element.querySelector('.mtrl-chip__text');
427
- expect(textElement?.textContent).toBe('Updated Text');
428
- });
429
-
430
- test('should be able to change leading icon', () => {
431
- const chip = createMockChip();
432
-
433
- const initialIconElement = chip.element.querySelector('.mtrl-chip__icon--leading');
434
- expect(initialIconElement).toBeNull();
435
-
436
- const iconHtml = '<svg><path></path></svg>';
437
- chip.setIcon(iconHtml);
438
-
439
- const updatedIconElement = chip.element.querySelector('.mtrl-chip__icon--leading');
440
- expect(updatedIconElement).toBeDefined();
441
- expect(updatedIconElement?.innerHTML).toBe(iconHtml);
442
- expect(chip.getIcon()).toBe(iconHtml);
443
- });
444
-
445
- test('should be able to change trailing icon', () => {
446
- const chip = createMockChip();
447
-
448
- const initialIconElement = chip.element.querySelector('.mtrl-chip__icon--trailing');
449
- expect(initialIconElement).toBeNull();
450
-
451
- const iconHtml = '<svg><path></path></svg>';
452
- chip.setTrailingIcon(iconHtml);
453
-
454
- const updatedIconElement = chip.element.querySelector('.mtrl-chip__icon--trailing');
455
- expect(updatedIconElement).toBeDefined();
456
- expect(updatedIconElement?.innerHTML).toBe(iconHtml);
457
- });
458
-
459
- test('should handle trailing icon click events', () => {
460
- let clickHandled = false;
461
-
462
- const chip = createMockChip({
463
- trailingIcon: '<svg></svg>',
464
- onTrailingIconClick: () => {
465
- clickHandled = true;
466
- }
467
- });
468
-
469
- const trailingIcon = chip.element.querySelector('.mtrl-chip__icon--trailing');
470
- expect(trailingIcon).toBeDefined();
471
-
472
- const clickEvent = new Event('click');
473
- clickEvent.stopPropagation = () => {};
474
- trailingIcon?.dispatchEvent(clickEvent);
475
-
476
- expect(clickHandled).toBe(true);
477
- });
478
-
479
- test('should be able to change selected state', () => {
480
- const chip = createMockChip();
481
-
482
- expect(chip.isSelected()).toBe(false);
483
-
484
- chip.setSelected(true);
485
-
486
- expect(chip.isSelected()).toBe(true);
487
- expect(chip.element.className).toContain('mtrl-chip--selected');
488
- expect(chip.element.getAttribute('aria-selected')).toBe('true');
489
-
490
- chip.setSelected(false);
491
-
492
- expect(chip.isSelected()).toBe(false);
493
- expect(chip.element.className).not.toContain('mtrl-chip--selected');
494
- expect(chip.element.getAttribute('aria-selected')).toBeNull();
495
- });
496
-
497
- test('should be able to toggle selected state', () => {
498
- const chip = createMockChip();
499
-
500
- expect(chip.isSelected()).toBe(false);
501
-
502
- chip.toggleSelected();
503
-
504
- expect(chip.isSelected()).toBe(true);
505
-
506
- chip.toggleSelected();
507
-
508
- expect(chip.isSelected()).toBe(false);
509
- });
510
-
511
- test('should be able to change disabled state', () => {
512
- const chip = createMockChip();
513
-
514
- expect(chip.isDisabled()).toBe(false);
515
-
516
- chip.disable();
517
-
518
- expect(chip.isDisabled()).toBe(true);
519
- expect(chip.element.className).toContain('mtrl-chip--disabled');
520
- expect(chip.element.getAttribute('aria-disabled')).toBe('true');
521
-
522
- chip.enable();
523
-
524
- expect(chip.isDisabled()).toBe(false);
525
- expect(chip.element.className).not.toContain('mtrl-chip--disabled');
526
- expect(chip.element.getAttribute('aria-disabled')).toBeNull();
527
- });
528
-
529
- test('should be able to change value', () => {
530
- const chip = createMockChip();
531
-
532
- expect(chip.getValue()).toBeNull();
533
-
534
- chip.setValue('new-value');
535
-
536
- expect(chip.getValue()).toBe('new-value');
537
- expect(chip.element.getAttribute('data-value')).toBe('new-value');
538
- });
539
-
540
- test('should add event listeners', () => {
541
- const chip = createMockChip();
542
- let eventFired = false;
543
-
544
- chip.on('click', () => {
545
- eventFired = true;
546
- });
547
-
548
- // Simulate click
549
- chip.element.dispatchEvent(new Event('click'));
550
-
551
- expect(eventFired).toBe(true);
552
- });
553
-
554
- test('should remove event listeners', () => {
555
- const chip = createMockChip();
556
- let count = 0;
557
-
558
- const handler = () => {
559
- count++;
560
- };
561
-
562
- chip.on('click', handler);
563
-
564
- // First click
565
- chip.element.dispatchEvent(new Event('click'));
566
- expect(count).toBe(1);
567
-
568
- // Remove listener
569
- chip.off('click', handler);
570
-
571
- // Second click
572
- chip.element.dispatchEvent(new Event('click'));
573
- expect(count).toBe(1); // Count should not increase
574
- });
575
-
576
- test('should add CSS classes', () => {
577
- const chip = createMockChip();
578
-
579
- chip.addClass('custom-class', 'special-chip');
580
-
581
- expect(chip.element.className).toContain('custom-class');
582
- expect(chip.element.className).toContain('special-chip');
583
- });
584
-
585
- test('should toggle selected state when clicked for filter chips', () => {
586
- const chip = createMockChip({ variant: CHIP_VARIANTS.FILTER });
587
-
588
- expect(chip.isSelected()).toBe(false);
589
-
590
- // Simulate click
591
- chip.element.dispatchEvent(new Event('click'));
592
-
593
- expect(chip.isSelected()).toBe(true);
594
-
595
- // Click again
596
- chip.element.dispatchEvent(new Event('click'));
597
-
598
- expect(chip.isSelected()).toBe(false);
599
- });
600
-
601
- test('should call onChange when selection changes', () => {
602
- let changeHandled = false;
603
- let selectedState = false;
604
-
605
- const chip = createMockChip({
606
- variant: CHIP_VARIANTS.FILTER,
607
- onChange: (c) => {
608
- changeHandled = true;
609
- selectedState = c.isSelected();
610
- }
611
- });
612
-
613
- // Simulate click
614
- chip.element.dispatchEvent(new Event('click'));
615
-
616
- expect(changeHandled).toBe(true);
617
- expect(selectedState).toBe(true);
618
- });
619
-
620
- test('should call onSelect when selected', () => {
621
- let selectHandled = false;
622
-
623
- const chip = createMockChip({
624
- onSelect: () => {
625
- selectHandled = true;
626
- }
627
- });
628
-
629
- chip.setSelected(true);
630
-
631
- expect(selectHandled).toBe(true);
632
- });
633
-
634
- test('should make any chip variant selectable with selectable flag', () => {
635
- const chip = createMockChip({
636
- variant: CHIP_VARIANTS.FILLED,
637
- selectable: true
638
- });
639
-
640
- expect(chip.isSelected()).toBe(false);
641
-
642
- // Simulate click
643
- chip.element.dispatchEvent(new Event('click'));
644
-
645
- expect(chip.isSelected()).toBe(true);
646
- });
647
-
648
- test('should not toggle selection when disabled', () => {
649
- const chip = createMockChip({
650
- variant: CHIP_VARIANTS.FILTER,
651
- disabled: true
652
- });
653
-
654
- expect(chip.isSelected()).toBe(false);
655
-
656
- // Simulate click
657
- chip.element.dispatchEvent(new Event('click'));
658
-
659
- expect(chip.isSelected()).toBe(false);
660
- });
661
-
662
- test('should be properly destroyed', () => {
663
- const chip = createMockChip();
664
- document.body.appendChild(chip.element);
665
-
666
- expect(document.body.contains(chip.element)).toBe(true);
667
-
668
- chip.destroy();
669
-
670
- expect(document.body.contains(chip.element)).toBe(false);
671
- });
672
-
673
- test('should handle basic chip set creation', () => {
674
- // Create a chip set container
675
- const chipSetElement = document.createElement('div');
676
- chipSetElement.className = 'mtrl-chip-set';
677
-
678
- // Add chips to the set
679
- const chip1 = createMockChip({ text: 'Chip 1' });
680
- const chip2 = createMockChip({ text: 'Chip 2', selected: true });
681
- const chip3 = createMockChip({ text: 'Chip 3' });
682
-
683
- chipSetElement.appendChild(chip1.element);
684
- chipSetElement.appendChild(chip2.element);
685
- chipSetElement.appendChild(chip3.element);
686
-
687
- // Check if all chips are in the set
688
- expect(chipSetElement.children.length).toBe(3);
689
- expect(chipSetElement.children[0].className).toContain('mtrl-chip');
690
- expect(chipSetElement.children[1].className).toContain('mtrl-chip--selected');
691
- });
692
- });