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,592 +0,0 @@
1
- // test/components/timepicker.test.ts
2
- import { describe, test, expect, mock, beforeAll, afterAll } from 'bun:test';
3
- import { JSDOM } from 'jsdom';
4
-
5
- // Setup jsdom environment
6
- let dom: JSDOM;
7
- let window: Window;
8
- let document: Document;
9
- let originalGlobalDocument: any;
10
- let originalGlobalWindow: any;
11
-
12
- beforeAll(() => {
13
- // Create a new JSDOM instance
14
- dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
15
- url: 'http://localhost/',
16
- pretendToBeVisual: true
17
- });
18
-
19
- // Get window and document from jsdom
20
- window = dom.window;
21
- document = window.document;
22
-
23
- // Store original globals
24
- originalGlobalDocument = global.document;
25
- originalGlobalWindow = global.window;
26
-
27
- // Set globals to use jsdom
28
- global.document = document;
29
- global.window = window;
30
- global.Element = window.Element;
31
- global.HTMLElement = window.HTMLElement;
32
- global.HTMLButtonElement = window.HTMLButtonElement;
33
- global.Event = window.Event;
34
- });
35
-
36
- afterAll(() => {
37
- // Restore original globals
38
- global.document = originalGlobalDocument;
39
- global.window = originalGlobalWindow;
40
-
41
- // Clean up jsdom
42
- window.close();
43
- });
44
-
45
- // Import only the types we need from the component
46
- import {
47
- TimePickerComponent,
48
- TimePickerConfig,
49
- TimeValue,
50
- TIME_PICKER_TYPE,
51
- TIME_PICKER_ORIENTATION,
52
- TIME_FORMAT,
53
- TIME_PERIOD
54
- } from '../../src/components/timepicker/types';
55
-
56
- // Create a mock implementation of the timepicker component
57
- const createMockTimePicker = (config: TimePickerConfig = {}): TimePickerComponent => {
58
- // Create the main container element
59
- const element = document.createElement('div');
60
- element.className = `mtrl-time-picker ${config.class || ''}`;
61
-
62
- // Create modal element
63
- const modalElement = document.createElement('div');
64
- modalElement.className = 'mtrl-time-picker-modal';
65
- modalElement.style.display = 'none';
66
-
67
- // Create dialog element
68
- const dialogElement = document.createElement('div');
69
- dialogElement.className = [
70
- 'mtrl-time-picker-dialog',
71
- `mtrl-time-picker-dialog--${config.type || TIME_PICKER_TYPE.DIAL}`,
72
- `mtrl-time-picker-dialog--${config.orientation || TIME_PICKER_ORIENTATION.VERTICAL}`,
73
- `mtrl-time-picker-dialog--${config.format || TIME_FORMAT.AMPM}`
74
- ].join(' ');
75
-
76
- // Append dialog to modal
77
- modalElement.appendChild(dialogElement);
78
-
79
- // Append modal to document body
80
- document.body.appendChild(modalElement);
81
-
82
- // Parse initial time value or use current time
83
- let timeValue: TimeValue;
84
- if (config.value) {
85
- const parts = config.value.split(':');
86
- const hours = parseInt(parts[0], 10);
87
- const minutes = parseInt(parts[1], 10);
88
- const seconds = parts[2] ? parseInt(parts[2], 10) : 0;
89
-
90
- timeValue = {
91
- hours,
92
- minutes,
93
- seconds,
94
- period: hours >= 12 ? TIME_PERIOD.PM : TIME_PERIOD.AM
95
- };
96
- } else {
97
- // Default to current time
98
- const now = new Date();
99
- timeValue = {
100
- hours: now.getHours(),
101
- minutes: now.getMinutes(),
102
- seconds: config.showSeconds ? now.getSeconds() : 0,
103
- period: now.getHours() >= 12 ? TIME_PERIOD.PM : TIME_PERIOD.AM
104
- };
105
- }
106
-
107
- // Track state
108
- let isOpen = !!config.isOpen;
109
- let currentType = config.type || TIME_PICKER_TYPE.DIAL;
110
- let currentFormat = config.format || TIME_FORMAT.AMPM;
111
- let currentOrientation = config.orientation || TIME_PICKER_ORIENTATION.VERTICAL;
112
- let currentTitle = config.title || '';
113
-
114
- // Event handlers
115
- const eventHandlers: Record<string, Function[]> = {};
116
-
117
- // Update modal visibility based on isOpen state
118
- const updateVisibility = () => {
119
- modalElement.style.display = isOpen ? 'block' : 'none';
120
- if (isOpen) {
121
- modalElement.classList.add('active');
122
- dialogElement.classList.add('active');
123
- element.classList.add('mtrl-time-picker--open');
124
- } else {
125
- modalElement.classList.remove('active');
126
- dialogElement.classList.remove('active');
127
- element.classList.remove('mtrl-time-picker--open');
128
- }
129
- };
130
-
131
- // Set initial visibility
132
- updateVisibility();
133
-
134
- // Format the time value as a string
135
- const formatTimeValue = (): string => {
136
- const { hours, minutes, seconds } = timeValue;
137
- const use24HourFormat = currentFormat === TIME_FORMAT.MILITARY;
138
-
139
- // Helper function to pad numbers with leading zeros
140
- const padZero = (num: number): string => {
141
- return num.toString().padStart(2, '0');
142
- };
143
-
144
- if (use24HourFormat) {
145
- if (config.showSeconds) {
146
- return `${padZero(hours)}:${padZero(minutes)}:${padZero(seconds || 0)}`;
147
- }
148
- return `${padZero(hours)}:${padZero(minutes)}`;
149
- } else {
150
- // Convert to 12-hour format for display
151
- let displayHours = hours % 12;
152
- if (displayHours === 0) {
153
- displayHours = 12;
154
- }
155
-
156
- if (config.showSeconds) {
157
- return `${padZero(displayHours)}:${padZero(minutes)}:${padZero(seconds || 0)} ${timeValue.period}`;
158
- }
159
- return `${padZero(displayHours)}:${padZero(minutes)} ${timeValue.period}`;
160
- }
161
- };
162
-
163
- // Emit event helper
164
- const emitEvent = (eventName: string, data?: any) => {
165
- if (eventHandlers[eventName]) {
166
- eventHandlers[eventName].forEach(handler => {
167
- handler(data);
168
- });
169
- }
170
-
171
- // Call appropriate callback if provided
172
- switch (eventName) {
173
- case 'change':
174
- if (config.onChange) config.onChange(formatTimeValue());
175
- break;
176
- case 'open':
177
- if (config.onOpen) config.onOpen();
178
- break;
179
- case 'close':
180
- if (config.onClose) config.onClose();
181
- break;
182
- case 'confirm':
183
- if (config.onConfirm) config.onConfirm(formatTimeValue());
184
- break;
185
- case 'cancel':
186
- if (config.onCancel) config.onCancel();
187
- break;
188
- }
189
- };
190
-
191
- const timePickerObj = {
192
- element,
193
- modalElement,
194
- dialogElement,
195
- isOpen,
196
-
197
- open() {
198
- if (isOpen) return this;
199
-
200
- isOpen = true;
201
- this.isOpen = true; // Update the public property too
202
- updateVisibility();
203
- emitEvent('open');
204
-
205
- return this;
206
- },
207
-
208
- close() {
209
- if (!isOpen) return this;
210
-
211
- isOpen = false;
212
- this.isOpen = false; // Update the public property too
213
- updateVisibility();
214
- emitEvent('close');
215
-
216
- return this;
217
- },
218
-
219
- toggle() {
220
- return isOpen ? this.close() : this.open();
221
- },
222
-
223
- getValue() {
224
- return formatTimeValue();
225
- },
226
-
227
- getTimeObject() {
228
- return { ...timeValue };
229
- },
230
-
231
- setValue(time: string) {
232
- try {
233
- const parts = time.split(':');
234
- const hours = parseInt(parts[0], 10);
235
- const minutes = parseInt(parts[1], 10);
236
- const seconds = parts[2] ? parseInt(parts[2], 10) : 0;
237
-
238
- if (
239
- isNaN(hours) || hours < 0 || hours > 23 ||
240
- isNaN(minutes) || minutes < 0 || minutes > 59 ||
241
- isNaN(seconds) || seconds < 0 || seconds > 59
242
- ) {
243
- throw new Error('Invalid time format');
244
- }
245
-
246
- timeValue = {
247
- hours,
248
- minutes,
249
- seconds,
250
- period: hours >= 12 ? TIME_PERIOD.PM : TIME_PERIOD.AM
251
- };
252
-
253
- emitEvent('change', formatTimeValue());
254
- } catch (error) {
255
- console.error('Error setting time value:', error);
256
- }
257
-
258
- return this;
259
- },
260
-
261
- setType(type: TIME_PICKER_TYPE) {
262
- if (currentType === type) return this;
263
-
264
- // Update class
265
- dialogElement.classList.remove(`mtrl-time-picker-dialog--${currentType}`);
266
- dialogElement.classList.add(`mtrl-time-picker-dialog--${type}`);
267
-
268
- currentType = type;
269
- return this;
270
- },
271
-
272
- getType() {
273
- return currentType;
274
- },
275
-
276
- setFormat(format: TIME_FORMAT) {
277
- if (currentFormat === format) return this;
278
-
279
- // Update class
280
- dialogElement.classList.remove(`mtrl-time-picker-dialog--${currentFormat}`);
281
- dialogElement.classList.add(`mtrl-time-picker-dialog--${format}`);
282
-
283
- currentFormat = format;
284
- emitEvent('change', formatTimeValue());
285
-
286
- return this;
287
- },
288
-
289
- getFormat() {
290
- return currentFormat;
291
- },
292
-
293
- setOrientation(orientation: TIME_PICKER_ORIENTATION) {
294
- if (currentOrientation === orientation) return this;
295
-
296
- // Update class
297
- dialogElement.classList.remove(`mtrl-time-picker-dialog--${currentOrientation}`);
298
- dialogElement.classList.add(`mtrl-time-picker-dialog--${orientation}`);
299
-
300
- currentOrientation = orientation;
301
- return this;
302
- },
303
-
304
- getOrientation() {
305
- return currentOrientation;
306
- },
307
-
308
- setTitle(title: string) {
309
- currentTitle = title;
310
-
311
- // If there's a title element, update it
312
- const titleElement = dialogElement.querySelector('.mtrl-time-picker-title');
313
- if (titleElement) {
314
- titleElement.textContent = title;
315
- }
316
-
317
- return this;
318
- },
319
-
320
- getTitle() {
321
- return currentTitle;
322
- },
323
-
324
- destroy() {
325
- // Close if open
326
- if (isOpen) {
327
- this.close();
328
- }
329
-
330
- // Remove from DOM
331
- if (modalElement.parentNode) {
332
- modalElement.parentNode.removeChild(modalElement);
333
- }
334
-
335
- // Clean up event handlers
336
- Object.keys(eventHandlers).forEach(event => {
337
- eventHandlers[event] = [];
338
- });
339
- },
340
-
341
- on(event: string, handler: Function) {
342
- if (!eventHandlers[event]) {
343
- eventHandlers[event] = [];
344
- }
345
- eventHandlers[event].push(handler);
346
- return this;
347
- },
348
-
349
- off(event: string, handler: Function) {
350
- if (eventHandlers[event]) {
351
- eventHandlers[event] = eventHandlers[event].filter(h => h !== handler);
352
- }
353
- return this;
354
- }
355
- };
356
-
357
- return timePickerObj;
358
- };
359
-
360
- describe('TimePicker Component', () => {
361
- test('should create a time picker component', () => {
362
- const timePicker = createMockTimePicker();
363
-
364
- expect(timePicker.element).toBeDefined();
365
- expect(timePicker.modalElement).toBeDefined();
366
- expect(timePicker.dialogElement).toBeDefined();
367
- expect(timePicker.isOpen).toBe(false);
368
- });
369
-
370
- test('should initialize with custom time value', () => {
371
- const timePicker = createMockTimePicker({
372
- value: '14:30'
373
- });
374
-
375
- expect(timePicker.getValue()).toBe('02:30 PM');
376
-
377
- const timeObject = timePicker.getTimeObject();
378
- expect(timeObject.hours).toBe(14);
379
- expect(timeObject.minutes).toBe(30);
380
- expect(timeObject.period).toBe(TIME_PERIOD.PM);
381
- });
382
-
383
- test('should initialize in 24-hour format', () => {
384
- const timePicker = createMockTimePicker({
385
- value: '14:30',
386
- format: TIME_FORMAT.MILITARY
387
- });
388
-
389
- expect(timePicker.getValue()).toBe('14:30');
390
-
391
- const timeObject = timePicker.getTimeObject();
392
- expect(timeObject.hours).toBe(14);
393
- expect(timeObject.minutes).toBe(30);
394
- });
395
-
396
- test('should toggle open/close state', () => {
397
- const timePicker = createMockTimePicker();
398
-
399
- // Initial state is closed
400
- expect(timePicker.isOpen).toBe(false);
401
- expect(timePicker.modalElement.style.display).toBe('none');
402
-
403
- // Open the time picker
404
- timePicker.open();
405
- expect(timePicker.isOpen).toBe(true);
406
- expect(timePicker.modalElement.style.display).toBe('block');
407
- expect(timePicker.modalElement.classList.contains('active')).toBe(true);
408
-
409
- // Close the time picker
410
- timePicker.close();
411
- expect(timePicker.isOpen).toBe(false);
412
- expect(timePicker.modalElement.classList.contains('active')).toBe(false);
413
-
414
- // Toggle should open it again
415
- timePicker.toggle();
416
- expect(timePicker.isOpen).toBe(true);
417
-
418
- // Toggle again should close it
419
- timePicker.toggle();
420
- expect(timePicker.isOpen).toBe(false);
421
- });
422
-
423
- test('should set and get time values', () => {
424
- const timePicker = createMockTimePicker();
425
-
426
- // Set a new time
427
- timePicker.setValue('09:45');
428
- expect(timePicker.getValue()).toBe('09:45 AM');
429
-
430
- const timeObject = timePicker.getTimeObject();
431
- expect(timeObject.hours).toBe(9);
432
- expect(timeObject.minutes).toBe(45);
433
- expect(timeObject.period).toBe(TIME_PERIOD.AM);
434
-
435
- // Set an afternoon time
436
- timePicker.setValue('16:20');
437
- expect(timePicker.getValue()).toBe('04:20 PM');
438
-
439
- const pmTimeObject = timePicker.getTimeObject();
440
- expect(pmTimeObject.hours).toBe(16);
441
- expect(pmTimeObject.minutes).toBe(20);
442
- expect(pmTimeObject.period).toBe(TIME_PERIOD.PM);
443
- });
444
-
445
- test('should change time picker type', () => {
446
- const timePicker = createMockTimePicker({
447
- type: TIME_PICKER_TYPE.DIAL
448
- });
449
-
450
- expect(timePicker.getType()).toBe(TIME_PICKER_TYPE.DIAL);
451
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--dial')).toBe(true);
452
-
453
- // Change to INPUT type
454
- timePicker.setType(TIME_PICKER_TYPE.INPUT);
455
- expect(timePicker.getType()).toBe(TIME_PICKER_TYPE.INPUT);
456
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--input')).toBe(true);
457
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--dial')).toBe(false);
458
- });
459
-
460
- test('should change time format', () => {
461
- const timePicker = createMockTimePicker({
462
- value: '14:30',
463
- format: TIME_FORMAT.AMPM
464
- });
465
-
466
- expect(timePicker.getFormat()).toBe(TIME_FORMAT.AMPM);
467
- expect(timePicker.getValue()).toBe('02:30 PM');
468
-
469
- // Change to 24-hour format
470
- timePicker.setFormat(TIME_FORMAT.MILITARY);
471
- expect(timePicker.getFormat()).toBe(TIME_FORMAT.MILITARY);
472
- expect(timePicker.getValue()).toBe('14:30');
473
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--24h')).toBe(true);
474
- });
475
-
476
- test('should change orientation', () => {
477
- const timePicker = createMockTimePicker({
478
- orientation: TIME_PICKER_ORIENTATION.VERTICAL
479
- });
480
-
481
- expect(timePicker.getOrientation()).toBe(TIME_PICKER_ORIENTATION.VERTICAL);
482
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--vertical')).toBe(true);
483
-
484
- // Change to horizontal orientation
485
- timePicker.setOrientation(TIME_PICKER_ORIENTATION.HORIZONTAL);
486
- expect(timePicker.getOrientation()).toBe(TIME_PICKER_ORIENTATION.HORIZONTAL);
487
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--horizontal')).toBe(true);
488
- expect(timePicker.dialogElement.classList.contains('mtrl-time-picker-dialog--vertical')).toBe(false);
489
- });
490
-
491
- test('should set and get title', () => {
492
- const initialTitle = 'Select Time';
493
- const timePicker = createMockTimePicker({
494
- title: initialTitle
495
- });
496
-
497
- expect(timePicker.getTitle()).toBe(initialTitle);
498
-
499
- // Update the title
500
- const newTitle = 'Choose Departure Time';
501
- timePicker.setTitle(newTitle);
502
- expect(timePicker.getTitle()).toBe(newTitle);
503
- });
504
-
505
- test('should handle event callbacks', () => {
506
- const changeHandler = mock(() => {});
507
- const openHandler = mock(() => {});
508
- const closeHandler = mock(() => {});
509
-
510
- const timePicker = createMockTimePicker();
511
-
512
- // Register event handlers
513
- timePicker.on('change', changeHandler);
514
- timePicker.on('open', openHandler);
515
- timePicker.on('close', closeHandler);
516
-
517
- // Trigger events
518
- timePicker.open();
519
- expect(openHandler).toHaveBeenCalled();
520
-
521
- timePicker.setValue('10:15');
522
- expect(changeHandler).toHaveBeenCalled();
523
-
524
- timePicker.close();
525
- expect(closeHandler).toHaveBeenCalled();
526
-
527
- // Remove an event handler
528
- timePicker.off('change', changeHandler);
529
- changeHandler.mockClear();
530
-
531
- // The handler should no longer be called
532
- timePicker.setValue('11:30');
533
- expect(changeHandler).not.toHaveBeenCalled();
534
- });
535
-
536
- test('should trigger config callbacks', () => {
537
- const onChangeMock = mock(() => {});
538
- const onOpenMock = mock(() => {});
539
- const onCloseMock = mock(() => {});
540
-
541
- const timePicker = createMockTimePicker({
542
- onChange: onChangeMock,
543
- onOpen: onOpenMock,
544
- onClose: onCloseMock
545
- });
546
-
547
- // Trigger events
548
- timePicker.open();
549
- expect(onOpenMock).toHaveBeenCalled();
550
-
551
- timePicker.setValue('09:30');
552
- expect(onChangeMock).toHaveBeenCalledWith('09:30 AM');
553
-
554
- timePicker.close();
555
- expect(onCloseMock).toHaveBeenCalled();
556
- });
557
-
558
- test('should handle time with seconds when showSeconds is true', () => {
559
- const timePicker = createMockTimePicker({
560
- value: '14:30:45',
561
- showSeconds: true
562
- });
563
-
564
- expect(timePicker.getValue()).toBe('02:30:45 PM');
565
-
566
- const timeObject = timePicker.getTimeObject();
567
- expect(timeObject.hours).toBe(14);
568
- expect(timeObject.minutes).toBe(30);
569
- expect(timeObject.seconds).toBe(45);
570
-
571
- // Update time with seconds
572
- timePicker.setValue('08:15:30');
573
- expect(timePicker.getValue()).toBe('08:15:30 AM');
574
- });
575
-
576
- test('should cleanup properly when destroyed', () => {
577
- const timePicker = createMockTimePicker();
578
- const modalElement = timePicker.modalElement;
579
-
580
- // Add to document
581
- document.body.appendChild(timePicker.element);
582
-
583
- // Verify modal is in the document
584
- expect(document.body.contains(modalElement)).toBe(true);
585
-
586
- // Destroy the component
587
- timePicker.destroy();
588
-
589
- // Verify modal was removed
590
- expect(document.body.contains(modalElement)).toBe(false);
591
- });
592
- });