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,400 +0,0 @@
1
- // test/components/textfield.test.ts
2
- import { describe, test, expect, mock } from 'bun:test';
3
- import { JSDOM } from 'jsdom';
4
-
5
- // Set up JSDOM
6
- const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`);
7
- global.document = dom.window.document;
8
- global.window = dom.window;
9
- global.Element = dom.window.Element;
10
- global.HTMLElement = dom.window.HTMLElement;
11
- global.HTMLInputElement = dom.window.HTMLInputElement;
12
- global.HTMLTextAreaElement = dom.window.HTMLTextAreaElement;
13
- global.Event = dom.window.Event;
14
- global.CustomEvent = dom.window.CustomEvent;
15
-
16
- // Import types directly to avoid circular dependencies
17
- import type {
18
- TextfieldComponent,
19
- TextfieldConfig,
20
- TextfieldVariant,
21
- TextfieldTypes,
22
- TextfieldSize
23
- } from '../../src/components/textfield/types';
24
-
25
- // Define constants here to avoid circular dependencies
26
- const TEXTFIELD_VARIANTS = {
27
- FILLED: 'filled',
28
- OUTLINED: 'outlined'
29
- } as const;
30
-
31
- const TEXTFIELD_SIZES = {
32
- SMALL: 'small',
33
- MEDIUM: 'medium',
34
- LARGE: 'large'
35
- } as const;
36
-
37
- const TEXTFIELD_TYPES = {
38
- TEXT: 'text',
39
- PASSWORD: 'password',
40
- EMAIL: 'email',
41
- NUMBER: 'number',
42
- TEL: 'tel',
43
- URL: 'url',
44
- SEARCH: 'search',
45
- MULTILINE: 'multiline'
46
- } as const;
47
-
48
- // Create a mock textfield implementation
49
- const createTextfield = (config: TextfieldConfig = {}): TextfieldComponent => {
50
- // Create base element
51
- const element = document.createElement('div');
52
- element.className = `mtrl-textfield ${config.class || ''}`;
53
-
54
- // Add variant class if provided
55
- if (config.variant) {
56
- element.classList.add(`mtrl-textfield--${config.variant}`);
57
- }
58
-
59
- // Add size class if provided
60
- if (config.size) {
61
- element.classList.add(`mtrl-textfield--${config.size}`);
62
- }
63
-
64
- // Create input element
65
- const input = document.createElement(config.type === TEXTFIELD_TYPES.MULTILINE ? 'textarea' : 'input') as HTMLInputElement | HTMLTextAreaElement;
66
- input.className = 'mtrl-textfield-input';
67
-
68
- if (input instanceof HTMLInputElement) {
69
- input.type = config.type || TEXTFIELD_TYPES.TEXT;
70
- }
71
-
72
- input.value = config.value || '';
73
- input.placeholder = config.placeholder || '';
74
-
75
- if (config.name) input.name = config.name;
76
- if (config.maxLength) input.maxLength = config.maxLength;
77
- if (config.required) input.required = true;
78
- if (config.disabled) input.disabled = true;
79
-
80
- element.appendChild(input);
81
-
82
- // Create label if provided
83
- let label: HTMLLabelElement | null = null;
84
- if (config.label) {
85
- label = document.createElement('label');
86
- label.className = 'mtrl-textfield-label';
87
- label.textContent = config.label;
88
- element.appendChild(label);
89
- }
90
-
91
- // Event handlers
92
- const eventHandlers: Record<string, EventListener[]> = {};
93
-
94
- // Create the textfield component instance
95
- const textfield: TextfieldComponent = {
96
- element,
97
- input,
98
- config,
99
-
100
- getValue: () => input.value,
101
-
102
- setValue: (value: string) => {
103
- input.value = value || '';
104
- return textfield;
105
- },
106
-
107
- setLabel: (text: string) => {
108
- if (label) {
109
- label.textContent = text;
110
- }
111
- return textfield;
112
- },
113
-
114
- getLabel: () => label?.textContent || '',
115
-
116
- setAttribute: (name: string, value: string) => {
117
- input.setAttribute(name, value);
118
- return textfield;
119
- },
120
-
121
- getAttribute: (name: string) => input.getAttribute(name),
122
-
123
- removeAttribute: (name: string) => {
124
- input.removeAttribute(name);
125
- return textfield;
126
- },
127
-
128
- on: (event: string, handler: Function) => {
129
- const listener = handler as EventListener;
130
- if (!eventHandlers[event]) {
131
- eventHandlers[event] = [];
132
- }
133
-
134
- eventHandlers[event].push(listener);
135
- input.addEventListener(event, listener);
136
- return textfield;
137
- },
138
-
139
- off: (event: string, handler: Function) => {
140
- const listener = handler as EventListener;
141
- input.removeEventListener(event, listener);
142
-
143
- if (eventHandlers[event]) {
144
- eventHandlers[event] = eventHandlers[event].filter(h => h !== listener);
145
- }
146
-
147
- return textfield;
148
- },
149
-
150
- enable: () => {
151
- input.disabled = false;
152
- element.classList.remove('mtrl-textfield--disabled');
153
- return textfield;
154
- },
155
-
156
- disable: () => {
157
- input.disabled = true;
158
- element.classList.add('mtrl-textfield--disabled');
159
- return textfield;
160
- },
161
-
162
- destroy: () => {
163
- // Clean up event listeners
164
- Object.entries(eventHandlers).forEach(([event, handlers]) => {
165
- handlers.forEach(handler => {
166
- input.removeEventListener(event, handler);
167
- });
168
- });
169
-
170
- // Clear handlers
171
- Object.keys(eventHandlers).forEach(key => {
172
- eventHandlers[key] = [];
173
- });
174
-
175
- // Remove from DOM if attached
176
- if (element.parentNode) {
177
- element.parentNode.removeChild(element);
178
- }
179
- }
180
- };
181
-
182
- return textfield;
183
- };
184
-
185
- describe('Textfield Component', () => {
186
- test('should create a textfield element', () => {
187
- const textfield = createTextfield();
188
- expect(textfield.element).toBeDefined();
189
- expect(textfield.element.tagName).toBe('DIV');
190
- expect(textfield.element.className).toContain('mtrl-textfield');
191
- });
192
-
193
- test('should apply variant class', () => {
194
- // Test filled variant
195
- const filledTextField = createTextfield({
196
- variant: TEXTFIELD_VARIANTS.FILLED
197
- });
198
- expect(filledTextField.element.className).toContain('mtrl-textfield--filled');
199
-
200
- // Test outlined variant
201
- const outlinedTextField = createTextfield({
202
- variant: TEXTFIELD_VARIANTS.OUTLINED
203
- });
204
- expect(outlinedTextField.element.className).toContain('mtrl-textfield--outlined');
205
- });
206
-
207
- test('should apply size class', () => {
208
- // Test small size
209
- const smallTextField = createTextfield({
210
- size: TEXTFIELD_SIZES.SMALL
211
- });
212
- expect(smallTextField.element.className).toContain('mtrl-textfield--small');
213
-
214
- // Test large size
215
- const largeTextField = createTextfield({
216
- size: TEXTFIELD_SIZES.LARGE
217
- });
218
- expect(largeTextField.element.className).toContain('mtrl-textfield--large');
219
- });
220
-
221
- test('should set initial value', () => {
222
- const initialValue = 'Hello World';
223
- const textfield = createTextfield({
224
- value: initialValue
225
- });
226
-
227
- expect(textfield.getValue()).toBe(initialValue);
228
- });
229
-
230
- test('should update value', () => {
231
- const textfield = createTextfield();
232
- const newValue = 'Updated Value';
233
-
234
- textfield.setValue(newValue);
235
- expect(textfield.getValue()).toBe(newValue);
236
- });
237
-
238
- test('should set and get label', () => {
239
- const initialLabel = 'Username';
240
- const textfield = createTextfield({
241
- label: initialLabel
242
- });
243
-
244
- expect(textfield.getLabel()).toBe(initialLabel);
245
-
246
- // Update label
247
- const newLabel = 'New Label';
248
- textfield.setLabel(newLabel);
249
- expect(textfield.getLabel()).toBe(newLabel);
250
- });
251
-
252
- test('should handle attributes', () => {
253
- const textfield = createTextfield();
254
-
255
- // Set attribute
256
- textfield.setAttribute('data-test', 'test-value');
257
- expect(textfield.getAttribute('data-test')).toBe('test-value');
258
-
259
- // Remove attribute
260
- textfield.removeAttribute('data-test');
261
- expect(textfield.getAttribute('data-test')).toBeNull();
262
- });
263
-
264
- test('should support disabled state', () => {
265
- // Create initially enabled
266
- const textfield = createTextfield();
267
-
268
- // Check API methods
269
- expect(typeof textfield.disable).toBe('function');
270
- expect(typeof textfield.enable).toBe('function');
271
-
272
- // Disable and check state
273
- textfield.disable();
274
- expect(textfield.input.disabled).toBe(true);
275
-
276
- // Enable and check state
277
- textfield.enable();
278
- expect(textfield.input.disabled).toBe(false);
279
-
280
- // Test initially disabled through config
281
- const disabledTextfield = createTextfield({ disabled: true });
282
- expect(disabledTextfield.input.disabled).toBe(true);
283
- });
284
-
285
- test('should support different input types', () => {
286
- // Test regular text input
287
- const textInput = createTextfield({
288
- type: TEXTFIELD_TYPES.TEXT
289
- });
290
-
291
- if (textInput.input instanceof HTMLInputElement) {
292
- expect(textInput.input.type).toBe('text');
293
- }
294
-
295
- // Test password input
296
- const passwordInput = createTextfield({
297
- type: TEXTFIELD_TYPES.PASSWORD
298
- });
299
-
300
- if (passwordInput.input instanceof HTMLInputElement) {
301
- expect(passwordInput.input.type).toBe('password');
302
- }
303
-
304
- // Test email input
305
- const emailInput = createTextfield({
306
- type: TEXTFIELD_TYPES.EMAIL
307
- });
308
-
309
- if (emailInput.input instanceof HTMLInputElement) {
310
- expect(emailInput.input.type).toBe('email');
311
- }
312
-
313
- // Test multiline input (textarea)
314
- const multilineInput = createTextfield({
315
- type: TEXTFIELD_TYPES.MULTILINE
316
- });
317
- expect(multilineInput.input.tagName).toBe('TEXTAREA');
318
- });
319
-
320
- test('should register event handlers', () => {
321
- const textfield = createTextfield();
322
-
323
- // Create a mock handler
324
- const mockHandler = mock(() => {});
325
-
326
- // Register handler
327
- textfield.on('input', mockHandler);
328
-
329
- // Trigger an input event
330
- const inputEvent = new Event('input');
331
- textfield.input.dispatchEvent(inputEvent);
332
-
333
- // Check that handler was called
334
- expect(mockHandler.mock.calls.length).toBeGreaterThan(0);
335
-
336
- // Unregister handler and trigger again
337
- textfield.off('input', mockHandler);
338
- textfield.input.dispatchEvent(inputEvent);
339
-
340
- // Handler call count should not increase
341
- expect(mockHandler.mock.calls.length).toBe(1);
342
- });
343
-
344
- test('should apply custom class', () => {
345
- const customClass = 'custom-textfield';
346
- const textfield = createTextfield({
347
- class: customClass
348
- });
349
-
350
- expect(textfield.element.className).toContain(customClass);
351
- });
352
-
353
- test('should set placeholder', () => {
354
- const placeholder = 'Enter text here';
355
- const textfield = createTextfield({
356
- placeholder
357
- });
358
-
359
- expect(textfield.input.placeholder).toBe(placeholder);
360
- });
361
-
362
- test('should set required attribute', () => {
363
- const textfield = createTextfield({
364
- required: true
365
- });
366
-
367
- expect(textfield.input.required).toBe(true);
368
- });
369
-
370
- test('should set name attribute', () => {
371
- const name = 'username';
372
- const textfield = createTextfield({
373
- name
374
- });
375
-
376
- expect(textfield.input.name).toBe(name);
377
- });
378
-
379
- test('should set maxLength attribute', () => {
380
- const maxLength = 50;
381
- const textfield = createTextfield({
382
- maxLength
383
- });
384
-
385
- expect(textfield.input.maxLength).toBe(maxLength);
386
- });
387
-
388
- test('should properly clean up resources on destroy', () => {
389
- const textfield = createTextfield();
390
-
391
- const parentElement = document.createElement('div');
392
- parentElement.appendChild(textfield.element);
393
-
394
- // Destroy the component
395
- textfield.destroy();
396
-
397
- // Check if element was removed
398
- expect(parentElement.children.length).toBe(0);
399
- });
400
- });