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,699 +0,0 @@
1
- // test/components/radios.test.ts
2
- import { describe, test, expect } from 'bun:test';
3
- import {
4
- type RadiosComponent,
5
- type RadiosConfig,
6
- type RadioOptionConfig,
7
- type RadioItem
8
- } from '../../src/components/radios/types';
9
-
10
- // Mock radios implementation
11
- const createMockRadios = (config: RadiosConfig): RadiosComponent => {
12
- // Create main container element
13
- const element = document.createElement('div');
14
- element.className = 'mtrl-radios';
15
-
16
- if (config.class) {
17
- const classes = config.class.split(' ');
18
- classes.forEach(className => element.classList.add(className));
19
- }
20
-
21
- if (config.disabled) {
22
- element.classList.add('mtrl-radios--disabled');
23
- }
24
-
25
- // Store settings
26
- const settings = {
27
- name: config.name,
28
- componentName: config.componentName || 'radios',
29
- prefix: config.prefix || 'mtrl',
30
- ripple: config.ripple !== undefined ? config.ripple : true,
31
- disabled: config.disabled || false,
32
- value: config.value || ''
33
- };
34
-
35
- // Create radio items
36
- const radios: RadioItem[] = [];
37
-
38
- // Track event handlers
39
- const eventHandlers: Record<string, Function[]> = {};
40
-
41
- // Emit an event
42
- const emit = (event: string, data?: any) => {
43
- if (eventHandlers[event]) {
44
- eventHandlers[event].forEach(handler => handler(data));
45
- }
46
- };
47
-
48
- // Helper function to create a radio item
49
- const createRadioItem = (option: RadioOptionConfig): RadioItem => {
50
- const radioElement = document.createElement('div');
51
- radioElement.className = 'mtrl-radio';
52
-
53
- const input = document.createElement('input');
54
- input.type = 'radio';
55
- input.name = settings.name;
56
- input.value = option.value;
57
- input.className = 'mtrl-radio__input';
58
- input.checked = option.value === settings.value;
59
-
60
- if (option.disabled || settings.disabled) {
61
- input.disabled = true;
62
- radioElement.classList.add('mtrl-radio--disabled');
63
- }
64
-
65
- const label = document.createElement('label');
66
- label.className = 'mtrl-radio__label';
67
- label.textContent = option.label;
68
- label.setAttribute('for', `${settings.name}-${option.value}`);
69
-
70
- if (option.labelBefore) {
71
- radioElement.classList.add('mtrl-radio--label-before');
72
- radioElement.appendChild(label);
73
- radioElement.appendChild(input);
74
- } else {
75
- radioElement.appendChild(input);
76
- radioElement.appendChild(label);
77
- }
78
-
79
- // Create ripple element if enabled
80
- if (settings.ripple) {
81
- const ripple = document.createElement('span');
82
- ripple.className = 'mtrl-radio__ripple';
83
- radioElement.appendChild(ripple);
84
- }
85
-
86
- // Handle change event
87
- const handleChange = () => {
88
- if (input.checked) {
89
- settings.value = option.value;
90
-
91
- // Update checked state of all radios
92
- radios.forEach(radio => {
93
- radio.input.checked = radio.input.value === settings.value;
94
- });
95
-
96
- emit('change', { value: settings.value });
97
- }
98
- };
99
-
100
- input.addEventListener('change', handleChange);
101
-
102
- const radioItem: RadioItem = {
103
- element: radioElement,
104
- input,
105
- label,
106
- config: { ...option },
107
- destroy: () => {
108
- input.removeEventListener('change', handleChange);
109
- if (radioElement.parentNode) {
110
- radioElement.parentNode.removeChild(radioElement);
111
- }
112
- }
113
- };
114
-
115
- return radioItem;
116
- };
117
-
118
- // Add initial options
119
- if (config.options) {
120
- config.options.forEach(option => {
121
- const radioItem = createRadioItem(option);
122
- radios.push(radioItem);
123
- element.appendChild(radioItem.element);
124
- });
125
- }
126
-
127
- // Create the radios component
128
- const radiosComponent: RadiosComponent = {
129
- element,
130
- radios,
131
-
132
- lifecycle: {
133
- destroy: () => {
134
- radiosComponent.destroy();
135
- }
136
- },
137
-
138
- getClass: (name: string) => {
139
- const prefix = settings.prefix;
140
- return name ? `${prefix}-${name}` : `${prefix}-radios`;
141
- },
142
-
143
- getValue: () => settings.value,
144
-
145
- setValue: (value: string) => {
146
- settings.value = value;
147
-
148
- // Update radio inputs
149
- radios.forEach(radio => {
150
- radio.input.checked = radio.config.value === value;
151
- });
152
-
153
- emit('change', { value });
154
-
155
- return radiosComponent;
156
- },
157
-
158
- getSelected: () => {
159
- const selectedRadio = radios.find(radio => radio.config.value === settings.value);
160
- return selectedRadio ? { ...selectedRadio.config } : null;
161
- },
162
-
163
- addOption: (option: RadioOptionConfig) => {
164
- // Check if option with this value already exists
165
- const existingIndex = radios.findIndex(radio => radio.config.value === option.value);
166
-
167
- if (existingIndex === -1) {
168
- const radioItem = createRadioItem(option);
169
- radios.push(radioItem);
170
- element.appendChild(radioItem.element);
171
- }
172
-
173
- return radiosComponent;
174
- },
175
-
176
- removeOption: (value: string) => {
177
- const index = radios.findIndex(radio => radio.config.value === value);
178
-
179
- if (index !== -1) {
180
- const radioItem = radios[index];
181
- radioItem.destroy();
182
- radios.splice(index, 1);
183
-
184
- // If we removed the selected option, clear the value
185
- if (settings.value === value) {
186
- settings.value = '';
187
- }
188
- }
189
-
190
- return radiosComponent;
191
- },
192
-
193
- enable: () => {
194
- settings.disabled = false;
195
- element.classList.remove('mtrl-radios--disabled');
196
-
197
- radios.forEach(radio => {
198
- if (!radio.config.disabled) {
199
- radio.input.disabled = false;
200
- radio.element.classList.remove('mtrl-radio--disabled');
201
- }
202
- });
203
-
204
- return radiosComponent;
205
- },
206
-
207
- disable: () => {
208
- settings.disabled = true;
209
- element.classList.add('mtrl-radios--disabled');
210
-
211
- radios.forEach(radio => {
212
- radio.input.disabled = true;
213
- radio.element.classList.add('mtrl-radio--disabled');
214
- });
215
-
216
- return radiosComponent;
217
- },
218
-
219
- enableOption: (value: string) => {
220
- const radio = radios.find(r => r.config.value === value);
221
-
222
- if (radio) {
223
- radio.config.disabled = false;
224
-
225
- if (!settings.disabled) {
226
- radio.input.disabled = false;
227
- radio.element.classList.remove('mtrl-radio--disabled');
228
- }
229
- }
230
-
231
- return radiosComponent;
232
- },
233
-
234
- disableOption: (value: string) => {
235
- const radio = radios.find(r => r.config.value === value);
236
-
237
- if (radio) {
238
- radio.config.disabled = true;
239
- radio.input.disabled = true;
240
- radio.element.classList.add('mtrl-radio--disabled');
241
- }
242
-
243
- return radiosComponent;
244
- },
245
-
246
- destroy: () => {
247
- // Clean up radio items
248
- radios.forEach(radio => radio.destroy());
249
- radios.length = 0;
250
-
251
- // Remove element from DOM if it has a parent
252
- if (element.parentNode) {
253
- element.parentNode.removeChild(element);
254
- }
255
-
256
- // Clear event handlers
257
- for (const event in eventHandlers) {
258
- eventHandlers[event] = [];
259
- }
260
- },
261
-
262
- on: (event: string, handler: Function) => {
263
- if (!eventHandlers[event]) {
264
- eventHandlers[event] = [];
265
- }
266
-
267
- eventHandlers[event].push(handler);
268
- return radiosComponent;
269
- },
270
-
271
- off: (event: string, handler: Function) => {
272
- if (eventHandlers[event]) {
273
- eventHandlers[event] = eventHandlers[event].filter(h => h !== handler);
274
- }
275
-
276
- return radiosComponent;
277
- }
278
- };
279
-
280
- return radiosComponent;
281
- };
282
-
283
- describe('Radios Component', () => {
284
- test('should create a radios component with options', () => {
285
- const options: RadioOptionConfig[] = [
286
- { value: 'option1', label: 'Option 1' },
287
- { value: 'option2', label: 'Option 2' },
288
- { value: 'option3', label: 'Option 3' }
289
- ];
290
-
291
- const radios = createMockRadios({
292
- name: 'test-radios',
293
- options
294
- });
295
-
296
- expect(radios.element).toBeDefined();
297
- expect(radios.element.tagName).toBe('DIV');
298
- expect(radios.element.className).toContain('mtrl-radios');
299
-
300
- expect(radios.radios.length).toBe(3);
301
-
302
- const radioElements = radios.element.querySelectorAll('.mtrl-radio');
303
- expect(radioElements.length).toBe(3);
304
-
305
- const inputs = radios.element.querySelectorAll('input[type="radio"]');
306
- expect(inputs.length).toBe(3);
307
-
308
- inputs.forEach((input: Element, index: number) => {
309
- expect((input as HTMLInputElement).name).toBe('test-radios');
310
- expect((input as HTMLInputElement).value).toBe(options[index].value);
311
-
312
- const label = input.parentElement?.querySelector('label');
313
- expect(label?.textContent).toBe(options[index].label);
314
- });
315
- });
316
-
317
- test('should set initial selected value', () => {
318
- const options: RadioOptionConfig[] = [
319
- { value: 'option1', label: 'Option 1' },
320
- { value: 'option2', label: 'Option 2' },
321
- { value: 'option3', label: 'Option 3' }
322
- ];
323
-
324
- const radios = createMockRadios({
325
- name: 'test-radios',
326
- options,
327
- value: 'option2'
328
- });
329
-
330
- expect(radios.getValue()).toBe('option2');
331
-
332
- const inputs = radios.element.querySelectorAll('input[type="radio"]');
333
- expect((inputs[0] as HTMLInputElement).checked).toBe(false);
334
- expect((inputs[1] as HTMLInputElement).checked).toBe(true);
335
- expect((inputs[2] as HTMLInputElement).checked).toBe(false);
336
- });
337
-
338
- test('should create with label before radio when configured', () => {
339
- const options: RadioOptionConfig[] = [
340
- { value: 'option1', label: 'Option 1', labelBefore: true }
341
- ];
342
-
343
- const radios = createMockRadios({
344
- name: 'test-radios',
345
- options
346
- });
347
-
348
- const radioElement = radios.element.querySelector('.mtrl-radio');
349
- expect(radioElement?.className).toContain('mtrl-radio--label-before');
350
-
351
- // First child should be label when labelBefore is true
352
- const firstChild = radioElement?.firstChild;
353
- expect(firstChild?.nodeName).toBe('LABEL');
354
- });
355
-
356
- test('should disable specific options', () => {
357
- const options: RadioOptionConfig[] = [
358
- { value: 'option1', label: 'Option 1' },
359
- { value: 'option2', label: 'Option 2', disabled: true },
360
- { value: 'option3', label: 'Option 3' }
361
- ];
362
-
363
- const radios = createMockRadios({
364
- name: 'test-radios',
365
- options
366
- });
367
-
368
- const inputs = radios.element.querySelectorAll('input[type="radio"]');
369
- expect((inputs[0] as HTMLInputElement).disabled).toBe(false);
370
- expect((inputs[1] as HTMLInputElement).disabled).toBe(true);
371
- expect((inputs[2] as HTMLInputElement).disabled).toBe(false);
372
-
373
- const radioElements = radios.element.querySelectorAll('.mtrl-radio');
374
- expect(radioElements[1].className).toContain('mtrl-radio--disabled');
375
- });
376
-
377
- test('should disable all options when component is disabled', () => {
378
- const options: RadioOptionConfig[] = [
379
- { value: 'option1', label: 'Option 1' },
380
- { value: 'option2', label: 'Option 2' },
381
- { value: 'option3', label: 'Option 3' }
382
- ];
383
-
384
- const radios = createMockRadios({
385
- name: 'test-radios',
386
- options,
387
- disabled: true
388
- });
389
-
390
- expect(radios.element.className).toContain('mtrl-radios--disabled');
391
-
392
- const inputs = radios.element.querySelectorAll('input[type="radio"]');
393
- inputs.forEach(input => {
394
- expect((input as HTMLInputElement).disabled).toBe(true);
395
- });
396
-
397
- const radioElements = radios.element.querySelectorAll('.mtrl-radio');
398
- radioElements.forEach(radio => {
399
- expect(radio.className).toContain('mtrl-radio--disabled');
400
- });
401
- });
402
-
403
- test('should create ripple effect by default', () => {
404
- const radios = createMockRadios({
405
- name: 'test-radios',
406
- options: [{ value: 'option1', label: 'Option 1' }]
407
- });
408
-
409
- const ripples = radios.element.querySelectorAll('.mtrl-radio__ripple');
410
- expect(ripples.length).toBe(1);
411
- });
412
-
413
- test('should not create ripple when disabled', () => {
414
- const radios = createMockRadios({
415
- name: 'test-radios',
416
- options: [{ value: 'option1', label: 'Option 1' }],
417
- ripple: false
418
- });
419
-
420
- const ripples = radios.element.querySelectorAll('.mtrl-radio__ripple');
421
- expect(ripples.length).toBe(0);
422
- });
423
-
424
- test('should change selected value', () => {
425
- const options: RadioOptionConfig[] = [
426
- { value: 'option1', label: 'Option 1' },
427
- { value: 'option2', label: 'Option 2' },
428
- { value: 'option3', label: 'Option 3' }
429
- ];
430
-
431
- const radios = createMockRadios({
432
- name: 'test-radios',
433
- options
434
- });
435
-
436
- expect(radios.getValue()).toBe('');
437
-
438
- radios.setValue('option2');
439
-
440
- expect(radios.getValue()).toBe('option2');
441
-
442
- const inputs = radios.element.querySelectorAll('input[type="radio"]');
443
- expect((inputs[0] as HTMLInputElement).checked).toBe(false);
444
- expect((inputs[1] as HTMLInputElement).checked).toBe(true);
445
- expect((inputs[2] as HTMLInputElement).checked).toBe(false);
446
- });
447
-
448
- test('should get selected option config', () => {
449
- const options: RadioOptionConfig[] = [
450
- { value: 'option1', label: 'Option 1' },
451
- { value: 'option2', label: 'Option 2' },
452
- { value: 'option3', label: 'Option 3' }
453
- ];
454
-
455
- const radios = createMockRadios({
456
- name: 'test-radios',
457
- options,
458
- value: 'option2'
459
- });
460
-
461
- const selected = radios.getSelected();
462
- expect(selected).toEqual(options[1]);
463
- });
464
-
465
- test('should add a new option', () => {
466
- const options: RadioOptionConfig[] = [
467
- { value: 'option1', label: 'Option 1' },
468
- { value: 'option2', label: 'Option 2' }
469
- ];
470
-
471
- const radios = createMockRadios({
472
- name: 'test-radios',
473
- options
474
- });
475
-
476
- expect(radios.radios.length).toBe(2);
477
-
478
- const newOption: RadioOptionConfig = {
479
- value: 'option3',
480
- label: 'Option 3'
481
- };
482
-
483
- radios.addOption(newOption);
484
-
485
- expect(radios.radios.length).toBe(3);
486
-
487
- const radioElements = radios.element.querySelectorAll('.mtrl-radio');
488
- expect(radioElements.length).toBe(3);
489
-
490
- const lastInput = radios.radios[2].input;
491
- expect(lastInput.value).toBe('option3');
492
-
493
- const lastLabel = radios.radios[2].label;
494
- expect(lastLabel.textContent).toBe('Option 3');
495
- });
496
-
497
- test('should remove an option', () => {
498
- const options: RadioOptionConfig[] = [
499
- { value: 'option1', label: 'Option 1' },
500
- { value: 'option2', label: 'Option 2' },
501
- { value: 'option3', label: 'Option 3' }
502
- ];
503
-
504
- const radios = createMockRadios({
505
- name: 'test-radios',
506
- options
507
- });
508
-
509
- expect(radios.radios.length).toBe(3);
510
-
511
- radios.removeOption('option2');
512
-
513
- expect(radios.radios.length).toBe(2);
514
-
515
- const radioElements = radios.element.querySelectorAll('.mtrl-radio');
516
- expect(radioElements.length).toBe(2);
517
-
518
- const remainingValues = radios.radios.map(radio => radio.config.value);
519
- expect(remainingValues).toEqual(['option1', 'option3']);
520
- });
521
-
522
- test('should clear value when selected option is removed', () => {
523
- const options: RadioOptionConfig[] = [
524
- { value: 'option1', label: 'Option 1' },
525
- { value: 'option2', label: 'Option 2' }
526
- ];
527
-
528
- const radios = createMockRadios({
529
- name: 'test-radios',
530
- options,
531
- value: 'option2'
532
- });
533
-
534
- expect(radios.getValue()).toBe('option2');
535
-
536
- radios.removeOption('option2');
537
-
538
- expect(radios.getValue()).toBe('');
539
- });
540
-
541
- test('should enable and disable the component', () => {
542
- const options: RadioOptionConfig[] = [
543
- { value: 'option1', label: 'Option 1' },
544
- { value: 'option2', label: 'Option 2' }
545
- ];
546
-
547
- const radios = createMockRadios({
548
- name: 'test-radios',
549
- options
550
- });
551
-
552
- expect(radios.element.className).not.toContain('mtrl-radios--disabled');
553
-
554
- radios.disable();
555
-
556
- expect(radios.element.className).toContain('mtrl-radios--disabled');
557
-
558
- const inputs = radios.element.querySelectorAll('input[type="radio"]');
559
- inputs.forEach(input => {
560
- expect((input as HTMLInputElement).disabled).toBe(true);
561
- });
562
-
563
- radios.enable();
564
-
565
- expect(radios.element.className).not.toContain('mtrl-radios--disabled');
566
-
567
- inputs.forEach(input => {
568
- expect((input as HTMLInputElement).disabled).toBe(false);
569
- });
570
- });
571
-
572
- test('should enable and disable specific options', () => {
573
- const options: RadioOptionConfig[] = [
574
- { value: 'option1', label: 'Option 1' },
575
- { value: 'option2', label: 'Option 2' }
576
- ];
577
-
578
- const radios = createMockRadios({
579
- name: 'test-radios',
580
- options
581
- });
582
-
583
- radios.disableOption('option1');
584
-
585
- const input1 = radios.radios[0].input;
586
- const input2 = radios.radios[1].input;
587
-
588
- expect(input1.disabled).toBe(true);
589
- expect(input2.disabled).toBe(false);
590
-
591
- expect(radios.radios[0].element.className).toContain('mtrl-radio--disabled');
592
- expect(radios.radios[1].element.className).not.toContain('mtrl-radio--disabled');
593
-
594
- radios.enableOption('option1');
595
-
596
- expect(input1.disabled).toBe(false);
597
- expect(radios.radios[0].element.className).not.toContain('mtrl-radio--disabled');
598
- });
599
-
600
- test('should emit change events', () => {
601
- const options: RadioOptionConfig[] = [
602
- { value: 'option1', label: 'Option 1' },
603
- { value: 'option2', label: 'Option 2' }
604
- ];
605
-
606
- const radios = createMockRadios({
607
- name: 'test-radios',
608
- options
609
- });
610
-
611
- let eventFired = false;
612
- let eventValue = '';
613
-
614
- radios.on('change', (data) => {
615
- eventFired = true;
616
- eventValue = data.value;
617
- });
618
-
619
- radios.setValue('option2');
620
-
621
- expect(eventFired).toBe(true);
622
- expect(eventValue).toBe('option2');
623
- });
624
-
625
- test('should handle input change events', () => {
626
- const options: RadioOptionConfig[] = [
627
- { value: 'option1', label: 'Option 1' },
628
- { value: 'option2', label: 'Option 2' }
629
- ];
630
-
631
- const radios = createMockRadios({
632
- name: 'test-radios',
633
- options
634
- });
635
-
636
- let eventFired = false;
637
- let eventValue = '';
638
-
639
- radios.on('change', (data) => {
640
- eventFired = true;
641
- eventValue = data.value;
642
- });
643
-
644
- // Simulate radio button change
645
- const input = radios.radios[1].input;
646
- input.checked = true;
647
- input.dispatchEvent(new Event('change'));
648
-
649
- expect(eventFired).toBe(true);
650
- expect(eventValue).toBe('option2');
651
- expect(radios.getValue()).toBe('option2');
652
- });
653
-
654
- test('should remove event listeners', () => {
655
- const radios = createMockRadios({
656
- name: 'test-radios',
657
- options: [
658
- { value: 'option1', label: 'Option 1' },
659
- { value: 'option2', label: 'Option 2' }
660
- ]
661
- });
662
-
663
- let eventCount = 0;
664
-
665
- const handler = () => {
666
- eventCount++;
667
- };
668
-
669
- radios.on('change', handler);
670
-
671
- radios.setValue('option1');
672
- expect(eventCount).toBe(1);
673
-
674
- radios.off('change', handler);
675
-
676
- radios.setValue('option2');
677
- expect(eventCount).toBe(1); // Count should not increase
678
- });
679
-
680
- test('should be properly destroyed', () => {
681
- const radios = createMockRadios({
682
- name: 'test-radios',
683
- options: [
684
- { value: 'option1', label: 'Option 1' },
685
- { value: 'option2', label: 'Option 2' }
686
- ]
687
- });
688
-
689
- document.body.appendChild(radios.element);
690
-
691
- expect(document.body.contains(radios.element)).toBe(true);
692
- expect(radios.radios.length).toBe(2);
693
-
694
- radios.destroy();
695
-
696
- expect(document.body.contains(radios.element)).toBe(false);
697
- expect(radios.radios.length).toBe(0);
698
- });
699
- });