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.
Files changed (99) hide show
  1. package/CLAUDE.md +33 -0
  2. package/package.json +3 -1
  3. package/src/components/button/button.ts +34 -5
  4. package/src/components/navigation/index.ts +4 -1
  5. package/src/components/navigation/system/core.ts +302 -0
  6. package/src/components/navigation/system/events.ts +240 -0
  7. package/src/components/navigation/system/index.ts +184 -0
  8. package/src/components/navigation/system/mobile.ts +278 -0
  9. package/src/components/navigation/system/state.ts +77 -0
  10. package/src/components/navigation/system/types.ts +364 -0
  11. package/src/components/navigation/types.ts +33 -0
  12. package/src/components/slider/config.ts +2 -2
  13. package/src/components/slider/features/controller.ts +1 -25
  14. package/src/components/slider/features/handlers.ts +0 -1
  15. package/src/components/slider/features/range.ts +7 -7
  16. package/src/components/slider/{structure.ts → schema.ts} +2 -13
  17. package/src/components/slider/slider.ts +3 -2
  18. package/src/components/snackbar/index.ts +7 -1
  19. package/src/components/snackbar/types.ts +25 -0
  20. package/src/components/switch/api.ts +16 -0
  21. package/src/components/switch/config.ts +1 -18
  22. package/src/components/switch/features.ts +198 -0
  23. package/src/components/switch/index.ts +6 -1
  24. package/src/components/switch/switch.ts +3 -3
  25. package/src/components/switch/types.ts +27 -2
  26. package/src/components/textfield/index.ts +7 -1
  27. package/src/components/textfield/types.ts +36 -0
  28. package/src/core/composition/features/dom.ts +26 -14
  29. package/src/core/composition/features/icon.ts +18 -18
  30. package/src/core/composition/features/index.ts +3 -2
  31. package/src/core/composition/features/label.ts +16 -17
  32. package/src/core/composition/features/layout.ts +47 -0
  33. package/src/core/composition/index.ts +4 -4
  34. package/src/core/layout/README.md +350 -0
  35. package/src/core/layout/array.ts +181 -0
  36. package/src/core/layout/create.ts +55 -0
  37. package/src/core/layout/index.ts +26 -0
  38. package/src/core/layout/object.ts +124 -0
  39. package/src/core/layout/processor.ts +58 -0
  40. package/src/core/layout/result.ts +85 -0
  41. package/src/core/layout/types.ts +125 -0
  42. package/src/core/layout/utils.ts +136 -0
  43. package/src/styles/abstract/_variables.scss +28 -0
  44. package/src/styles/components/_switch.scss +133 -69
  45. package/src/styles/components/_textfield.scss +9 -16
  46. package/test/components/badge.test.ts +545 -0
  47. package/test/components/bottom-app-bar.test.ts +303 -0
  48. package/test/components/button.test.ts +233 -0
  49. package/test/components/card.test.ts +560 -0
  50. package/test/components/carousel.test.ts +951 -0
  51. package/test/components/checkbox.test.ts +462 -0
  52. package/test/components/chip.test.ts +692 -0
  53. package/test/components/datepicker.test.ts +1124 -0
  54. package/test/components/dialog.test.ts +990 -0
  55. package/test/components/divider.test.ts +412 -0
  56. package/test/components/extended-fab.test.ts +672 -0
  57. package/test/components/fab.test.ts +561 -0
  58. package/test/components/list.test.ts +365 -0
  59. package/test/components/menu.test.ts +718 -0
  60. package/test/components/navigation.test.ts +186 -0
  61. package/test/components/progress.test.ts +567 -0
  62. package/test/components/radios.test.ts +699 -0
  63. package/test/components/search.test.ts +1135 -0
  64. package/test/components/segmented-button.test.ts +732 -0
  65. package/test/components/sheet.test.ts +641 -0
  66. package/test/components/slider.test.ts +1220 -0
  67. package/test/components/snackbar.test.ts +461 -0
  68. package/test/components/switch.test.ts +452 -0
  69. package/test/components/tabs.test.ts +1369 -0
  70. package/test/components/textfield.test.ts +400 -0
  71. package/test/components/timepicker.test.ts +592 -0
  72. package/test/components/tooltip.test.ts +630 -0
  73. package/test/components/top-app-bar.test.ts +566 -0
  74. package/test/core/dom.attributes.test.ts +148 -0
  75. package/test/core/dom.classes.test.ts +152 -0
  76. package/test/core/dom.events.test.ts +243 -0
  77. package/test/core/emitter.test.ts +141 -0
  78. package/test/core/ripple.test.ts +99 -0
  79. package/test/core/state.store.test.ts +189 -0
  80. package/test/core/utils.normalize.test.ts +61 -0
  81. package/test/core/utils.object.test.ts +120 -0
  82. package/test/setup.ts +451 -0
  83. package/tsconfig.json +2 -2
  84. package/src/components/navigation/system-types.ts +0 -124
  85. package/src/components/navigation/system.ts +0 -776
  86. package/src/components/snackbar/constants.ts +0 -26
  87. package/src/core/composition/features/structure.ts +0 -22
  88. package/src/core/layout/index.js +0 -95
  89. package/src/core/structure.ts +0 -288
  90. package/test/components/button.test.js +0 -170
  91. package/test/components/checkbox.test.js +0 -238
  92. package/test/components/list.test.js +0 -105
  93. package/test/components/menu.test.js +0 -385
  94. package/test/components/navigation.test.js +0 -227
  95. package/test/components/snackbar.test.js +0 -234
  96. package/test/components/switch.test.js +0 -186
  97. package/test/components/textfield.test.js +0 -314
  98. package/test/core/emitter.test.js +0 -141
  99. 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
+ });