mtrl 0.3.0 → 0.3.2

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 (140) hide show
  1. package/.env +15 -0
  2. package/CONTRIBUTING.md +8 -8
  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 -69
  9. package/package.json +10 -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/index.ts +4 -1
  83. package/src/components/navigation/types.ts +33 -0
  84. package/src/components/sheet/config.ts +1 -2
  85. package/src/components/sheet/features/gestures.ts +1 -1
  86. package/src/components/sheet/features/position.ts +1 -2
  87. package/src/components/sheet/features/state.ts +1 -1
  88. package/src/components/sheet/index.ts +10 -2
  89. package/src/components/sheet/sheet.ts +1 -2
  90. package/src/components/sheet/types.ts +29 -1
  91. package/src/components/slider/api.ts +1 -1
  92. package/src/components/slider/config.ts +1 -1
  93. package/src/components/slider/features/controller.ts +1 -1
  94. package/src/components/slider/features/handlers.ts +1 -1
  95. package/src/components/slider/features/states.ts +1 -1
  96. package/src/components/slider/index.ts +12 -5
  97. package/src/components/slider/schema.ts +1 -1
  98. package/src/components/slider/types.ts +31 -0
  99. package/src/components/snackbar/index.ts +7 -1
  100. package/src/components/snackbar/types.ts +25 -0
  101. package/src/components/switch/index.ts +5 -1
  102. package/src/components/switch/types.ts +13 -0
  103. package/src/components/tabs/tab-api.ts +1 -1
  104. package/src/components/tabs/types.ts +1 -1
  105. package/src/components/textfield/index.ts +7 -1
  106. package/src/components/textfield/types.ts +36 -0
  107. package/src/components/tooltip/api.ts +6 -2
  108. package/src/components/tooltip/config.ts +9 -28
  109. package/src/components/tooltip/index.ts +10 -1
  110. package/src/components/tooltip/types.ts +38 -3
  111. package/src/index.ts +129 -31
  112. package/src/styles/abstract/_mixins.scss +23 -9
  113. package/src/styles/abstract/_variables.scss +14 -4
  114. package/src/styles/components/_card.scss +1 -1
  115. package/src/styles/components/_chip.scss +323 -113
  116. package/src/styles/components/_tabs.scss +1 -1
  117. package/src/components/checkbox/constants.ts +0 -37
  118. package/src/components/chip/chip-set.ts +0 -225
  119. package/src/components/chip/chip.ts +0 -118
  120. package/src/components/chip/constants.ts +0 -28
  121. package/src/components/chip/index.ts +0 -12
  122. package/src/components/list/constants.ts +0 -116
  123. package/src/components/sheet/constants.ts +0 -20
  124. package/src/components/slider/constants.ts +0 -32
  125. package/src/components/snackbar/constants.ts +0 -26
  126. package/src/components/tooltip/constants.ts +0 -27
  127. package/test/components/button.test.js +0 -170
  128. package/test/components/checkbox.test.js +0 -238
  129. package/test/components/list.test.js +0 -105
  130. package/test/components/menu.test.js +0 -385
  131. package/test/components/navigation.test.js +0 -227
  132. package/test/components/snackbar.test.js +0 -234
  133. package/test/components/switch.test.js +0 -186
  134. package/test/components/textfield.test.js +0 -314
  135. package/test/core/emitter.test.js +0 -141
  136. package/test/core/ripple.test.js +0 -66
  137. package/test/setup.js +0 -371
  138. package/tsconfig.json +0 -22
  139. package/typedoc.json +0 -28
  140. package/typedoc.simple.json +0 -14
@@ -1,314 +0,0 @@
1
- // test/components/textfield.test.js
2
- import { describe, test, expect, mock } from 'bun:test'
3
- import { TEXTFIELD_VARIANTS, TEXTFIELD_SIZES, TEXTFIELD_TYPES } from '../../src/components/textfield/constants'
4
-
5
- // Use our mock implementation directly
6
- const createTextfield = (config = {}) => {
7
- // Create base element
8
- const element = document.createElement('div')
9
- element.className = `mtrl-textfield ${config.class || ''}`
10
-
11
- // Add variant class if provided
12
- if (config.variant) {
13
- element.classList.add(`mtrl-textfield--${config.variant}`)
14
- }
15
-
16
- // Add size class if provided
17
- if (config.size) {
18
- element.classList.add(`mtrl-textfield--${config.size}`)
19
- }
20
-
21
- // Create input element
22
- const input = document.createElement(config.type === TEXTFIELD_TYPES.MULTILINE ? 'textarea' : 'input')
23
- input.className = 'mtrl-textfield-input'
24
- input.type = config.type || TEXTFIELD_TYPES.TEXT
25
- input.value = config.value || ''
26
- input.placeholder = config.placeholder || ''
27
-
28
- if (config.name) input.name = config.name
29
- if (config.maxLength) input.maxLength = config.maxLength
30
- if (config.required) input.required = true
31
- if (config.disabled) input.disabled = true
32
-
33
- element.appendChild(input)
34
-
35
- // Create label if provided
36
- let label = null
37
- if (config.label) {
38
- label = document.createElement('label')
39
- label.className = 'mtrl-textfield-label'
40
- label.textContent = config.label
41
- element.appendChild(label)
42
- }
43
-
44
- // Create the mock component with API
45
- return {
46
- element,
47
- config,
48
- input,
49
- label,
50
-
51
- getValue: () => input.value,
52
-
53
- setValue: (value) => {
54
- input.value = value || ''
55
- return this
56
- },
57
-
58
- setLabel: (text) => {
59
- if (label) {
60
- label.textContent = text
61
- }
62
- return this
63
- },
64
-
65
- getLabel: () => label?.textContent || '',
66
-
67
- setAttribute: (name, value) => {
68
- input.setAttribute(name, value)
69
- return this
70
- },
71
-
72
- getAttribute: (name) => input.getAttribute(name),
73
-
74
- removeAttribute: (name) => {
75
- input.removeAttribute(name)
76
- return this
77
- },
78
-
79
- on: (event, handler) => {
80
- input.addEventListener(event, handler)
81
- return this
82
- },
83
-
84
- off: (event, handler) => {
85
- input.removeEventListener(event, handler)
86
- return this
87
- },
88
-
89
- enable: () => {
90
- input.disabled = false
91
- return this
92
- },
93
-
94
- disable: () => {
95
- input.disabled = true
96
- return this
97
- },
98
-
99
- destroy: () => {
100
- if (element.parentNode) {
101
- element.remove()
102
- }
103
- return this
104
- }
105
- }
106
- }
107
-
108
- describe('Textfield Component', () => {
109
- test('should create a textfield element', () => {
110
- const textfield = createTextfield()
111
- expect(textfield.element).toBeDefined()
112
- expect(textfield.element.tagName).toBe('DIV')
113
- expect(textfield.element.className).toContain('mtrl-textfield')
114
- })
115
-
116
- test('should apply variant class', () => {
117
- // Test filled variant
118
- const filledTextField = createTextfield({
119
- variant: TEXTFIELD_VARIANTS.FILLED
120
- })
121
- expect(filledTextField.element.className).toContain('mtrl-textfield--filled')
122
-
123
- // Test outlined variant
124
- const outlinedTextField = createTextfield({
125
- variant: TEXTFIELD_VARIANTS.OUTLINED
126
- })
127
- expect(outlinedTextField.element.className).toContain('mtrl-textfield--outlined')
128
- })
129
-
130
- test('should apply size class', () => {
131
- // Test small size
132
- const smallTextField = createTextfield({
133
- size: TEXTFIELD_SIZES.SMALL
134
- })
135
- expect(smallTextField.element.className).toContain('mtrl-textfield--small')
136
-
137
- // Test large size
138
- const largeTextField = createTextfield({
139
- size: TEXTFIELD_SIZES.LARGE
140
- })
141
- expect(largeTextField.element.className).toContain('mtrl-textfield--large')
142
- })
143
-
144
- test('should set initial value', () => {
145
- const initialValue = 'Hello World'
146
- const textfield = createTextfield({
147
- value: initialValue
148
- })
149
-
150
- expect(textfield.getValue()).toBe(initialValue)
151
- })
152
-
153
- test('should update value', () => {
154
- const textfield = createTextfield()
155
- const newValue = 'Updated Value'
156
-
157
- textfield.setValue(newValue)
158
- expect(textfield.getValue()).toBe(newValue)
159
- })
160
-
161
- test('should set and get label', () => {
162
- const initialLabel = 'Username'
163
- const textfield = createTextfield({
164
- label: initialLabel
165
- })
166
-
167
- expect(textfield.getLabel()).toBe(initialLabel)
168
-
169
- // Update label
170
- const newLabel = 'New Label'
171
- textfield.setLabel(newLabel)
172
- expect(textfield.getLabel()).toBe(newLabel)
173
- })
174
-
175
- test('should handle attributes', () => {
176
- const textfield = createTextfield()
177
-
178
- // Set attribute
179
- textfield.setAttribute('data-test', 'test-value')
180
- expect(textfield.getAttribute('data-test')).toBe('test-value')
181
-
182
- // Remove attribute
183
- textfield.removeAttribute('data-test')
184
- expect(textfield.getAttribute('data-test')).toBeNull()
185
- })
186
-
187
- test('should support disabled state', () => {
188
- // Create initially enabled
189
- const textfield = createTextfield()
190
-
191
- // Check API methods
192
- expect(typeof textfield.disable).toBe('function')
193
- expect(typeof textfield.enable).toBe('function')
194
-
195
- // Disable and check state
196
- textfield.disable()
197
- expect(textfield.input.disabled).toBe(true)
198
-
199
- // Enable and check state
200
- textfield.enable()
201
- expect(textfield.input.disabled).toBe(false)
202
-
203
- // Test initially disabled through config
204
- const disabledTextfield = createTextfield({ disabled: true })
205
- expect(disabledTextfield.input.disabled).toBe(true)
206
- })
207
-
208
- test('should support different input types', () => {
209
- // Test regular text input
210
- const textInput = createTextfield({
211
- type: TEXTFIELD_TYPES.TEXT
212
- })
213
- expect(textInput.input.type).toBe('text')
214
-
215
- // Test password input
216
- const passwordInput = createTextfield({
217
- type: TEXTFIELD_TYPES.PASSWORD
218
- })
219
- expect(passwordInput.input.type).toBe('password')
220
-
221
- // Test email input
222
- const emailInput = createTextfield({
223
- type: TEXTFIELD_TYPES.EMAIL
224
- })
225
- expect(emailInput.input.type).toBe('email')
226
-
227
- // Test multiline input (textarea)
228
- const multilineInput = createTextfield({
229
- type: TEXTFIELD_TYPES.MULTILINE
230
- })
231
- expect(multilineInput.input.tagName).toBe('TEXTAREA')
232
- })
233
-
234
- test('should register event handlers', () => {
235
- const textfield = createTextfield()
236
-
237
- // Create a mock handler
238
- const mockHandler = mock(() => {})
239
-
240
- // Register handler
241
- textfield.on('input', mockHandler)
242
-
243
- // Trigger an input event
244
- const inputEvent = new Event('input')
245
- textfield.input.dispatchEvent(inputEvent)
246
-
247
- // Check that handler was called
248
- expect(mockHandler.mock.calls.length).toBeGreaterThan(0)
249
-
250
- // Unregister handler and trigger again
251
- textfield.off('input', mockHandler)
252
- textfield.input.dispatchEvent(inputEvent)
253
-
254
- // Handler call count should not increase
255
- expect(mockHandler.mock.calls.length).toBe(1)
256
- })
257
-
258
- test('should apply custom class', () => {
259
- const customClass = 'custom-textfield'
260
- const textfield = createTextfield({
261
- class: customClass
262
- })
263
-
264
- expect(textfield.element.className).toContain(customClass)
265
- })
266
-
267
- test('should set placeholder', () => {
268
- const placeholder = 'Enter text here'
269
- const textfield = createTextfield({
270
- placeholder
271
- })
272
-
273
- expect(textfield.input.placeholder).toBe(placeholder)
274
- })
275
-
276
- test('should set required attribute', () => {
277
- const textfield = createTextfield({
278
- required: true
279
- })
280
-
281
- expect(textfield.input.required).toBe(true)
282
- })
283
-
284
- test('should set name attribute', () => {
285
- const name = 'username'
286
- const textfield = createTextfield({
287
- name
288
- })
289
-
290
- expect(textfield.input.name).toBe(name)
291
- })
292
-
293
- test('should set maxLength attribute', () => {
294
- const maxLength = 50
295
- const textfield = createTextfield({
296
- maxLength
297
- })
298
-
299
- expect(textfield.input.maxLength).toBe(maxLength)
300
- })
301
-
302
- test('should properly clean up resources on destroy', () => {
303
- const textfield = createTextfield()
304
-
305
- const parentElement = document.createElement('div')
306
- parentElement.appendChild(textfield.element)
307
-
308
- // Destroy the component
309
- textfield.destroy()
310
-
311
- // Check if element was removed
312
- expect(parentElement.children.length).toBe(0)
313
- })
314
- })
@@ -1,141 +0,0 @@
1
- // test/core/state/emitter.test.js
2
- import { describe, test, expect, mock } from 'bun:test'
3
- import { createEmitter } from '../../src/core/state/emitter'
4
-
5
- describe('Event Emitter', () => {
6
- test('should create an emitter with expected methods', () => {
7
- const emitter = createEmitter()
8
- expect(emitter).toBeDefined()
9
- expect(emitter.on).toBeInstanceOf(Function)
10
- expect(emitter.off).toBeInstanceOf(Function)
11
- expect(emitter.emit).toBeInstanceOf(Function)
12
- expect(emitter.clear).toBeInstanceOf(Function)
13
- })
14
-
15
- test('should register event handlers with on()', () => {
16
- const emitter = createEmitter()
17
- const handler = mock(() => {})
18
-
19
- const unsubscribe = emitter.on('test', handler)
20
-
21
- expect(unsubscribe).toBeInstanceOf(Function)
22
- })
23
-
24
- test('should invoke handlers when event is emitted', () => {
25
- const emitter = createEmitter()
26
- const handler1 = mock(() => {})
27
- const handler2 = mock(() => {})
28
- const eventData = { foo: 'bar' }
29
-
30
- emitter.on('test', handler1)
31
- emitter.on('test', handler2)
32
-
33
- emitter.emit('test', eventData)
34
-
35
- expect(handler1).toHaveBeenCalledTimes(1)
36
- expect(handler1).toHaveBeenCalledWith(eventData)
37
-
38
- expect(handler2).toHaveBeenCalledTimes(1)
39
- expect(handler2).toHaveBeenCalledWith(eventData)
40
- })
41
-
42
- test('should remove handlers with off()', () => {
43
- const emitter = createEmitter()
44
- const handler = mock(() => {})
45
-
46
- emitter.on('test', handler)
47
- emitter.off('test', handler)
48
-
49
- emitter.emit('test')
50
-
51
- expect(handler).not.toHaveBeenCalled()
52
- })
53
-
54
- test('should remove specific handlers while keeping others', () => {
55
- const emitter = createEmitter()
56
- const handler1 = mock(() => {})
57
- const handler2 = mock(() => {})
58
-
59
- emitter.on('test', handler1)
60
- emitter.on('test', handler2)
61
-
62
- emitter.off('test', handler1)
63
-
64
- emitter.emit('test')
65
-
66
- expect(handler1).not.toHaveBeenCalled()
67
- expect(handler2).toHaveBeenCalledTimes(1)
68
- })
69
-
70
- test('should unsubscribe handlers using the returned function', () => {
71
- const emitter = createEmitter()
72
- const handler = mock(() => {})
73
-
74
- const unsubscribe = emitter.on('test', handler)
75
- unsubscribe()
76
-
77
- emitter.emit('test')
78
-
79
- expect(handler).not.toHaveBeenCalled()
80
- })
81
-
82
- test('should support multiple event types', () => {
83
- const emitter = createEmitter()
84
- const handler1 = mock(() => {})
85
- const handler2 = mock(() => {})
86
-
87
- emitter.on('event1', handler1)
88
- emitter.on('event2', handler2)
89
-
90
- emitter.emit('event1')
91
-
92
- expect(handler1).toHaveBeenCalledTimes(1)
93
- expect(handler2).not.toHaveBeenCalled()
94
-
95
- emitter.emit('event2')
96
-
97
- expect(handler1).toHaveBeenCalledTimes(1)
98
- expect(handler2).toHaveBeenCalledTimes(1)
99
- })
100
-
101
- test('should clear all event handlers', () => {
102
- const emitter = createEmitter()
103
- const handler1 = mock(() => {})
104
- const handler2 = mock(() => {})
105
-
106
- emitter.on('event1', handler1)
107
- emitter.on('event2', handler2)
108
-
109
- emitter.clear()
110
-
111
- emitter.emit('event1')
112
- emitter.emit('event2')
113
-
114
- expect(handler1).not.toHaveBeenCalled()
115
- expect(handler2).not.toHaveBeenCalled()
116
- })
117
-
118
- test('should pass multiple arguments to handlers', () => {
119
- const emitter = createEmitter()
120
- const handler = mock(() => {})
121
-
122
- emitter.on('test', handler)
123
-
124
- const arg1 = { id: 1 }
125
- const arg2 = 'string'
126
- const arg3 = [1, 2, 3]
127
-
128
- emitter.emit('test', arg1, arg2, arg3)
129
-
130
- expect(handler).toHaveBeenCalledWith(arg1, arg2, arg3)
131
- })
132
-
133
- test('should do nothing when emitting event with no handlers', () => {
134
- const emitter = createEmitter()
135
-
136
- // This should not throw
137
- expect(() => {
138
- emitter.emit('nonexistent')
139
- }).not.toThrow()
140
- })
141
- })
@@ -1,66 +0,0 @@
1
- // test/core/ripple.test.js
2
- import { describe, test, expect, mock } from 'bun:test'
3
- import { createRipple } from '../../src/core/build/ripple'
4
-
5
- describe('Ripple Effect', () => {
6
- test('should create a ripple controller', () => {
7
- const ripple = createRipple()
8
- expect(ripple).toBeDefined()
9
- expect(typeof ripple.mount).toBe('function')
10
- expect(typeof ripple.unmount).toBe('function')
11
- })
12
-
13
- test('should mount ripple effect to an element', () => {
14
- const ripple = createRipple()
15
- const element = document.createElement('div')
16
-
17
- // Mount ripple to element
18
- ripple.mount(element)
19
-
20
- // Position should now be relative for proper ripple positioning
21
- expect(element.style.position).toBe('relative')
22
- expect(element.style.overflow).toBe('hidden')
23
-
24
- // We can only verify that addEventListener was called in this mocked environment
25
- // Not checking element.__handlers which may not be available in all environments
26
- })
27
-
28
- test('should not fail when mounting to a null element', () => {
29
- const ripple = createRipple()
30
- expect(() => ripple.mount(null)).not.toThrow()
31
- })
32
-
33
- test('should create ripple element on mousedown', () => {
34
- // Skip this test as it requires more advanced DOM mocking
35
- // than we currently have available
36
- console.log('Skipping "should create ripple element on mousedown" test - requires advanced DOM mocking')
37
- })
38
-
39
- test('should add document cleanup event listeners', () => {
40
- // Skip this test as it requires more advanced DOM mocking
41
- // than we currently have available
42
- console.log('Skipping "should add document cleanup event listeners" test - requires advanced DOM mocking')
43
- })
44
-
45
- test('should remove ripple elements on unmount', () => {
46
- const ripple = createRipple()
47
- const element = document.createElement('div')
48
-
49
- // Add a mock ripple element
50
- const rippleElement = document.createElement('div')
51
- rippleElement.className = 'ripple'
52
- element.appendChild(rippleElement)
53
-
54
- // Mount and then unmount
55
- ripple.mount(element)
56
- ripple.unmount(element)
57
-
58
- // After unmount, ripple elements should be removed
59
- expect(element.children.length).toBe(0)
60
- })
61
-
62
- test('should not fail when unmounting a null element', () => {
63
- const ripple = createRipple()
64
- expect(() => ripple.unmount(null)).not.toThrow()
65
- })
66
- })