mtrl 0.2.9 → 0.3.1
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/CLAUDE.md +33 -0
- package/package.json +3 -1
- package/src/components/button/button.ts +34 -5
- package/src/components/navigation/index.ts +4 -1
- package/src/components/navigation/system/core.ts +302 -0
- package/src/components/navigation/system/events.ts +240 -0
- package/src/components/navigation/system/index.ts +184 -0
- package/src/components/navigation/system/mobile.ts +278 -0
- package/src/components/navigation/system/state.ts +77 -0
- package/src/components/navigation/system/types.ts +364 -0
- package/src/components/navigation/types.ts +33 -0
- package/src/components/slider/config.ts +2 -2
- package/src/components/slider/features/controller.ts +1 -25
- package/src/components/slider/features/handlers.ts +0 -1
- package/src/components/slider/features/range.ts +7 -7
- package/src/components/slider/{structure.ts → schema.ts} +2 -13
- package/src/components/slider/slider.ts +3 -2
- package/src/components/snackbar/index.ts +7 -1
- package/src/components/snackbar/types.ts +25 -0
- package/src/components/switch/api.ts +16 -0
- package/src/components/switch/config.ts +1 -18
- package/src/components/switch/features.ts +198 -0
- package/src/components/switch/index.ts +6 -1
- package/src/components/switch/switch.ts +3 -3
- package/src/components/switch/types.ts +27 -2
- package/src/components/textfield/index.ts +7 -1
- package/src/components/textfield/types.ts +36 -0
- package/src/core/composition/features/dom.ts +26 -14
- package/src/core/composition/features/icon.ts +18 -18
- package/src/core/composition/features/index.ts +3 -2
- package/src/core/composition/features/label.ts +16 -17
- package/src/core/composition/features/layout.ts +47 -0
- package/src/core/composition/index.ts +4 -4
- package/src/core/layout/README.md +350 -0
- package/src/core/layout/array.ts +181 -0
- package/src/core/layout/create.ts +55 -0
- package/src/core/layout/index.ts +26 -0
- package/src/core/layout/object.ts +124 -0
- package/src/core/layout/processor.ts +58 -0
- package/src/core/layout/result.ts +85 -0
- package/src/core/layout/types.ts +125 -0
- package/src/core/layout/utils.ts +136 -0
- package/src/styles/abstract/_variables.scss +28 -0
- package/src/styles/components/_switch.scss +133 -69
- package/src/styles/components/_textfield.scss +9 -16
- package/test/components/badge.test.ts +545 -0
- package/test/components/bottom-app-bar.test.ts +303 -0
- package/test/components/button.test.ts +233 -0
- package/test/components/card.test.ts +560 -0
- package/test/components/carousel.test.ts +951 -0
- package/test/components/checkbox.test.ts +462 -0
- package/test/components/chip.test.ts +692 -0
- package/test/components/datepicker.test.ts +1124 -0
- package/test/components/dialog.test.ts +990 -0
- package/test/components/divider.test.ts +412 -0
- package/test/components/extended-fab.test.ts +672 -0
- package/test/components/fab.test.ts +561 -0
- package/test/components/list.test.ts +365 -0
- package/test/components/menu.test.ts +718 -0
- package/test/components/navigation.test.ts +186 -0
- package/test/components/progress.test.ts +567 -0
- package/test/components/radios.test.ts +699 -0
- package/test/components/search.test.ts +1135 -0
- package/test/components/segmented-button.test.ts +732 -0
- package/test/components/sheet.test.ts +641 -0
- package/test/components/slider.test.ts +1220 -0
- package/test/components/snackbar.test.ts +461 -0
- package/test/components/switch.test.ts +452 -0
- package/test/components/tabs.test.ts +1369 -0
- package/test/components/textfield.test.ts +400 -0
- package/test/components/timepicker.test.ts +592 -0
- package/test/components/tooltip.test.ts +630 -0
- package/test/components/top-app-bar.test.ts +566 -0
- package/test/core/dom.attributes.test.ts +148 -0
- package/test/core/dom.classes.test.ts +152 -0
- package/test/core/dom.events.test.ts +243 -0
- package/test/core/emitter.test.ts +141 -0
- package/test/core/ripple.test.ts +99 -0
- package/test/core/state.store.test.ts +189 -0
- package/test/core/utils.normalize.test.ts +61 -0
- package/test/core/utils.object.test.ts +120 -0
- package/test/setup.ts +451 -0
- package/tsconfig.json +2 -2
- package/src/components/navigation/system-types.ts +0 -124
- package/src/components/navigation/system.ts +0 -776
- package/src/components/snackbar/constants.ts +0 -26
- package/src/core/composition/features/structure.ts +0 -22
- package/src/core/layout/index.js +0 -95
- package/src/core/structure.ts +0 -288
- package/test/components/button.test.js +0 -170
- package/test/components/checkbox.test.js +0 -238
- package/test/components/list.test.js +0 -105
- package/test/components/menu.test.js +0 -385
- package/test/components/navigation.test.js +0 -227
- package/test/components/snackbar.test.js +0 -234
- package/test/components/switch.test.js +0 -186
- package/test/components/textfield.test.js +0 -314
- package/test/core/emitter.test.js +0 -141
- package/test/core/ripple.test.js +0 -66
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// test/components/navigation.test.ts
|
|
2
|
+
import { describe, test, expect } 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
|
+
|
|
12
|
+
// Import navigation types directly
|
|
13
|
+
import type { NavigationComponent, NavItemConfig, NavItemData, NavVariant, NavPosition } from '../../src/components/navigation/types';
|
|
14
|
+
|
|
15
|
+
// Define constants here to avoid circular dependencies
|
|
16
|
+
const NAV_VARIANTS: Record<string, NavVariant> = {
|
|
17
|
+
RAIL: 'rail',
|
|
18
|
+
DRAWER: 'drawer',
|
|
19
|
+
BAR: 'bar',
|
|
20
|
+
MODAL: 'modal',
|
|
21
|
+
STANDARD: 'standard'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const NAV_POSITIONS: Record<string, NavPosition> = {
|
|
25
|
+
LEFT: 'left',
|
|
26
|
+
RIGHT: 'right',
|
|
27
|
+
TOP: 'top',
|
|
28
|
+
BOTTOM: 'bottom'
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Sample items for testing
|
|
32
|
+
const testItems: NavItemConfig[] = [
|
|
33
|
+
{
|
|
34
|
+
id: 'home',
|
|
35
|
+
icon: '<svg viewBox="0 0 24 24"><path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/></svg>',
|
|
36
|
+
label: 'Home'
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'favorites',
|
|
40
|
+
icon: '<svg viewBox="0 0 24 24"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>',
|
|
41
|
+
label: 'Favorites'
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'settings',
|
|
45
|
+
icon: '<svg viewBox="0 0 24 24"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/></svg>',
|
|
46
|
+
label: 'Settings'
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
// Create a simple mock navigation
|
|
51
|
+
const createMockNavigation = (config = {}): NavigationComponent => {
|
|
52
|
+
const element = document.createElement('nav');
|
|
53
|
+
element.className = `mtrl-nav mtrl-nav--${config.variant || 'rail'}`;
|
|
54
|
+
|
|
55
|
+
if (config.class) {
|
|
56
|
+
element.className += ` ${config.class}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Create basic items map
|
|
60
|
+
const items = new Map();
|
|
61
|
+
|
|
62
|
+
if (config.items) {
|
|
63
|
+
(config.items as NavItemConfig[]).forEach(itemConfig => {
|
|
64
|
+
const itemElement = document.createElement('button');
|
|
65
|
+
itemElement.className = 'mtrl-nav-item';
|
|
66
|
+
itemElement.dataset.id = itemConfig.id;
|
|
67
|
+
|
|
68
|
+
items.set(itemConfig.id, {
|
|
69
|
+
element: itemElement,
|
|
70
|
+
config: itemConfig
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
element,
|
|
77
|
+
items,
|
|
78
|
+
config: {
|
|
79
|
+
variant: config.variant || 'rail',
|
|
80
|
+
position: config.position || 'left',
|
|
81
|
+
disabled: config.disabled || false,
|
|
82
|
+
...config
|
|
83
|
+
},
|
|
84
|
+
addItem: () => ({ element, items, config } as any),
|
|
85
|
+
removeItem: () => ({ element, items, config } as any),
|
|
86
|
+
getItem: (id) => items.get(id),
|
|
87
|
+
getAllItems: () => Array.from(items.values()),
|
|
88
|
+
getActive: () => null,
|
|
89
|
+
getItemPath: () => [],
|
|
90
|
+
setActive: () => ({ element, items, config } as any),
|
|
91
|
+
enable: () => ({ element, items, config } as any),
|
|
92
|
+
disable: () => ({ element, items, config } as any),
|
|
93
|
+
expand: () => ({ element, items, config } as any),
|
|
94
|
+
collapse: () => ({ element, items, config } as any),
|
|
95
|
+
isExpanded: () => false,
|
|
96
|
+
toggle: () => ({ element, items, config } as any),
|
|
97
|
+
on: () => ({ element, items, config } as any),
|
|
98
|
+
off: () => ({ element, items, config } as any),
|
|
99
|
+
destroy: () => {
|
|
100
|
+
if (element.parentNode) {
|
|
101
|
+
element.parentNode.removeChild(element);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
} as NavigationComponent;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
describe('Navigation Component', () => {
|
|
108
|
+
test('should create a navigation element', () => {
|
|
109
|
+
const nav = createMockNavigation();
|
|
110
|
+
expect(nav.element).toBeDefined();
|
|
111
|
+
expect(nav.element.tagName).toBe('NAV');
|
|
112
|
+
expect(nav.element.className).toContain('mtrl-nav');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('should apply variant class', () => {
|
|
116
|
+
const variant = NAV_VARIANTS.RAIL;
|
|
117
|
+
const nav = createMockNavigation({
|
|
118
|
+
variant
|
|
119
|
+
});
|
|
120
|
+
expect(nav.config.variant).toBe(variant);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should apply position class', () => {
|
|
124
|
+
const position = NAV_POSITIONS.LEFT;
|
|
125
|
+
const nav = createMockNavigation({
|
|
126
|
+
position
|
|
127
|
+
});
|
|
128
|
+
expect(nav.config.position).toBe(position);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('should add initial items', () => {
|
|
132
|
+
const nav = createMockNavigation({
|
|
133
|
+
items: testItems
|
|
134
|
+
});
|
|
135
|
+
expect(nav.items).toBeDefined();
|
|
136
|
+
expect(nav.items.size).toBe(testItems.length);
|
|
137
|
+
|
|
138
|
+
// Check first item details
|
|
139
|
+
const homeItem = nav.getItem('home');
|
|
140
|
+
expect(homeItem).toBeDefined();
|
|
141
|
+
expect(homeItem?.config.label).toBe('Home');
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test('should add item dynamically', () => {
|
|
145
|
+
const nav = createMockNavigation();
|
|
146
|
+
const newItem: NavItemConfig = {
|
|
147
|
+
id: 'profile',
|
|
148
|
+
icon: '<svg viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>',
|
|
149
|
+
label: 'Profile'
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
expect(typeof nav.addItem).toBe('function');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('should support disabled state', () => {
|
|
156
|
+
const nav = createMockNavigation();
|
|
157
|
+
expect(typeof nav.disable).toBe('function');
|
|
158
|
+
expect(typeof nav.enable).toBe('function');
|
|
159
|
+
|
|
160
|
+
const disabledNav = createMockNavigation({ disabled: true });
|
|
161
|
+
expect(disabledNav.config.disabled).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test('should register event handlers', () => {
|
|
165
|
+
const nav = createMockNavigation();
|
|
166
|
+
expect(typeof nav.on).toBe('function');
|
|
167
|
+
expect(typeof nav.off).toBe('function');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test('should apply custom class', () => {
|
|
171
|
+
const customClass = 'custom-nav';
|
|
172
|
+
const nav = createMockNavigation({
|
|
173
|
+
class: customClass
|
|
174
|
+
});
|
|
175
|
+
expect(nav.element.className).toContain(customClass);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('should properly clean up resources on destroy', () => {
|
|
179
|
+
const nav = createMockNavigation();
|
|
180
|
+
const parentElement = document.createElement('div');
|
|
181
|
+
parentElement.appendChild(nav.element);
|
|
182
|
+
|
|
183
|
+
nav.destroy();
|
|
184
|
+
expect(parentElement.children.length).toBe(0);
|
|
185
|
+
});
|
|
186
|
+
});
|