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