mtrl 0.1.2 → 0.2.0

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 (220) hide show
  1. package/README.md +70 -22
  2. package/index.ts +33 -0
  3. package/package.json +14 -5
  4. package/src/components/button/{styles.scss → _styles.scss} +2 -2
  5. package/src/components/button/api.ts +89 -0
  6. package/src/components/button/button.ts +50 -0
  7. package/src/components/button/config.ts +75 -0
  8. package/src/components/button/constants.ts +17 -0
  9. package/src/components/button/index.ts +4 -0
  10. package/src/components/button/types.ts +118 -0
  11. package/src/components/card/_styles.scss +359 -0
  12. package/src/components/card/actions.ts +48 -0
  13. package/src/components/card/api.ts +102 -0
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/constants.ts +69 -0
  17. package/src/components/card/content.ts +48 -0
  18. package/src/components/card/features.ts +228 -0
  19. package/src/components/card/header.ts +88 -0
  20. package/src/components/card/index.ts +19 -0
  21. package/src/components/card/media.ts +52 -0
  22. package/src/components/card/types.ts +174 -0
  23. package/src/components/checkbox/api.ts +82 -0
  24. package/src/components/checkbox/checkbox.ts +75 -0
  25. package/src/components/checkbox/config.ts +90 -0
  26. package/src/components/checkbox/index.ts +4 -0
  27. package/src/components/checkbox/types.ts +146 -0
  28. package/src/components/chip/_styles.scss +372 -0
  29. package/src/components/chip/api.ts +115 -0
  30. package/src/components/chip/chip-set.ts +225 -0
  31. package/src/components/chip/chip.ts +82 -0
  32. package/src/components/chip/config.ts +92 -0
  33. package/src/components/chip/constants.ts +38 -0
  34. package/src/components/chip/index.ts +4 -0
  35. package/src/components/chip/types.ts +172 -0
  36. package/src/components/list/api.ts +72 -0
  37. package/src/components/list/config.ts +43 -0
  38. package/src/components/list/{constants.js → constants.ts} +34 -7
  39. package/src/components/list/features.ts +224 -0
  40. package/src/components/list/index.ts +14 -0
  41. package/src/components/list/list-item.ts +120 -0
  42. package/src/components/list/list.ts +37 -0
  43. package/src/components/list/types.ts +179 -0
  44. package/src/components/list/utils.ts +47 -0
  45. package/src/components/menu/api.ts +119 -0
  46. package/src/components/menu/config.ts +54 -0
  47. package/src/components/menu/constants.ts +154 -0
  48. package/src/components/menu/features/items-manager.ts +457 -0
  49. package/src/components/menu/features/keyboard-navigation.ts +133 -0
  50. package/src/components/menu/features/positioning.ts +127 -0
  51. package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
  52. package/src/components/menu/index.ts +14 -0
  53. package/src/components/menu/menu-item.ts +43 -0
  54. package/src/components/menu/menu.ts +53 -0
  55. package/src/components/menu/types.ts +178 -0
  56. package/src/components/navigation/api.ts +79 -0
  57. package/src/components/navigation/config.ts +61 -0
  58. package/src/components/navigation/{constants.js → constants.ts} +10 -10
  59. package/src/components/navigation/index.ts +14 -0
  60. package/src/components/navigation/nav-item.ts +148 -0
  61. package/src/components/navigation/navigation.ts +50 -0
  62. package/src/components/navigation/types.ts +212 -0
  63. package/src/components/progress/_styles.scss +204 -0
  64. package/src/components/progress/api.ts +179 -0
  65. package/src/components/progress/config.ts +124 -0
  66. package/src/components/progress/constants.ts +43 -0
  67. package/src/components/progress/index.ts +5 -0
  68. package/src/components/progress/progress.ts +163 -0
  69. package/src/components/progress/types.ts +102 -0
  70. package/src/components/snackbar/api.ts +162 -0
  71. package/src/components/snackbar/config.ts +62 -0
  72. package/src/components/snackbar/{constants.js → constants.ts} +21 -4
  73. package/src/components/snackbar/features.ts +76 -0
  74. package/src/components/snackbar/index.ts +4 -0
  75. package/src/components/snackbar/position.ts +71 -0
  76. package/src/components/snackbar/queue.ts +76 -0
  77. package/src/components/snackbar/snackbar.ts +60 -0
  78. package/src/components/snackbar/types.ts +58 -0
  79. package/src/components/switch/api.ts +77 -0
  80. package/src/components/switch/config.ts +74 -0
  81. package/src/components/switch/index.ts +4 -0
  82. package/src/components/switch/switch.ts +52 -0
  83. package/src/components/switch/types.ts +142 -0
  84. package/src/components/textfield/api.ts +72 -0
  85. package/src/components/textfield/config.ts +54 -0
  86. package/src/components/textfield/{constants.js → constants.ts} +38 -5
  87. package/src/components/textfield/index.ts +4 -0
  88. package/src/components/textfield/textfield.ts +50 -0
  89. package/src/components/textfield/types.ts +139 -0
  90. package/src/core/compose/base.ts +43 -0
  91. package/src/core/compose/component.ts +247 -0
  92. package/src/core/compose/features/checkable.ts +155 -0
  93. package/src/core/compose/features/disabled.ts +116 -0
  94. package/src/core/compose/features/events.ts +65 -0
  95. package/src/core/compose/features/icon.ts +67 -0
  96. package/src/core/compose/features/index.ts +35 -0
  97. package/src/core/compose/features/input.ts +174 -0
  98. package/src/core/compose/features/lifecycle.ts +139 -0
  99. package/src/core/compose/features/position.ts +94 -0
  100. package/src/core/compose/features/ripple.ts +55 -0
  101. package/src/core/compose/features/size.ts +29 -0
  102. package/src/core/compose/features/style.ts +31 -0
  103. package/src/core/compose/features/text.ts +44 -0
  104. package/src/core/compose/features/textinput.ts +225 -0
  105. package/src/core/compose/features/textlabel.ts +92 -0
  106. package/src/core/compose/features/track.ts +84 -0
  107. package/src/core/compose/features/variant.ts +29 -0
  108. package/src/core/compose/features/withEvents.ts +137 -0
  109. package/src/core/compose/index.ts +54 -0
  110. package/src/core/compose/{pipe.js → pipe.ts} +16 -11
  111. package/src/core/config/component-config.ts +136 -0
  112. package/src/core/config.ts +211 -0
  113. package/src/core/dom/{attributes.js → attributes.ts} +11 -11
  114. package/src/core/dom/classes.ts +60 -0
  115. package/src/core/dom/create.ts +188 -0
  116. package/src/core/dom/events.ts +209 -0
  117. package/src/core/dom/index.ts +10 -0
  118. package/src/core/dom/utils.ts +97 -0
  119. package/src/core/index.ts +111 -0
  120. package/src/core/state/disabled.ts +81 -0
  121. package/src/core/state/emitter.ts +94 -0
  122. package/src/core/state/events.ts +88 -0
  123. package/src/core/state/index.ts +16 -0
  124. package/src/core/state/lifecycle.ts +131 -0
  125. package/src/core/state/store.ts +197 -0
  126. package/src/core/utils/index.ts +45 -0
  127. package/src/core/utils/{mobile.js → mobile.ts} +48 -24
  128. package/src/core/utils/object.ts +41 -0
  129. package/src/core/utils/validate.ts +234 -0
  130. package/src/{index.js → index.ts} +4 -2
  131. package/index.js +0 -11
  132. package/src/components/button/api.js +0 -54
  133. package/src/components/button/button.js +0 -81
  134. package/src/components/button/config.js +0 -10
  135. package/src/components/button/constants.js +0 -63
  136. package/src/components/button/index.js +0 -2
  137. package/src/components/checkbox/api.js +0 -45
  138. package/src/components/checkbox/checkbox.js +0 -96
  139. package/src/components/checkbox/index.js +0 -2
  140. package/src/components/container/api.js +0 -42
  141. package/src/components/container/container.js +0 -45
  142. package/src/components/container/index.js +0 -2
  143. package/src/components/container/styles.scss +0 -66
  144. package/src/components/list/index.js +0 -2
  145. package/src/components/list/list-item.js +0 -147
  146. package/src/components/list/list.js +0 -267
  147. package/src/components/menu/api.js +0 -117
  148. package/src/components/menu/constants.js +0 -42
  149. package/src/components/menu/features/items-manager.js +0 -375
  150. package/src/components/menu/features/keyboard-navigation.js +0 -129
  151. package/src/components/menu/features/positioning.js +0 -125
  152. package/src/components/menu/index.js +0 -2
  153. package/src/components/menu/menu-item.js +0 -41
  154. package/src/components/menu/menu.js +0 -54
  155. package/src/components/navigation/api.js +0 -43
  156. package/src/components/navigation/index.js +0 -2
  157. package/src/components/navigation/nav-item.js +0 -137
  158. package/src/components/navigation/navigation.js +0 -55
  159. package/src/components/snackbar/api.js +0 -125
  160. package/src/components/snackbar/features.js +0 -69
  161. package/src/components/snackbar/index.js +0 -2
  162. package/src/components/snackbar/position.js +0 -63
  163. package/src/components/snackbar/queue.js +0 -74
  164. package/src/components/snackbar/snackbar.js +0 -70
  165. package/src/components/switch/api.js +0 -44
  166. package/src/components/switch/index.js +0 -2
  167. package/src/components/switch/switch.js +0 -71
  168. package/src/components/textfield/api.js +0 -49
  169. package/src/components/textfield/index.js +0 -2
  170. package/src/components/textfield/textfield.js +0 -68
  171. package/src/core/build/_ripple.scss +0 -79
  172. package/src/core/build/constants.js +0 -51
  173. package/src/core/build/icon.js +0 -78
  174. package/src/core/build/ripple.js +0 -159
  175. package/src/core/build/text.js +0 -54
  176. package/src/core/compose/base.js +0 -8
  177. package/src/core/compose/component.js +0 -225
  178. package/src/core/compose/features/checkable.js +0 -114
  179. package/src/core/compose/features/disabled.js +0 -64
  180. package/src/core/compose/features/events.js +0 -48
  181. package/src/core/compose/features/icon.js +0 -33
  182. package/src/core/compose/features/index.js +0 -20
  183. package/src/core/compose/features/input.js +0 -100
  184. package/src/core/compose/features/lifecycle.js +0 -69
  185. package/src/core/compose/features/position.js +0 -60
  186. package/src/core/compose/features/ripple.js +0 -32
  187. package/src/core/compose/features/size.js +0 -9
  188. package/src/core/compose/features/style.js +0 -12
  189. package/src/core/compose/features/text.js +0 -17
  190. package/src/core/compose/features/textinput.js +0 -114
  191. package/src/core/compose/features/textlabel.js +0 -28
  192. package/src/core/compose/features/track.js +0 -49
  193. package/src/core/compose/features/variant.js +0 -9
  194. package/src/core/compose/features/withEvents.js +0 -67
  195. package/src/core/compose/index.js +0 -16
  196. package/src/core/config.js +0 -140
  197. package/src/core/dom/classes.js +0 -70
  198. package/src/core/dom/create.js +0 -132
  199. package/src/core/dom/events.js +0 -175
  200. package/src/core/dom/index.js +0 -5
  201. package/src/core/dom/utils.js +0 -22
  202. package/src/core/index.js +0 -23
  203. package/src/core/state/disabled.js +0 -51
  204. package/src/core/state/emitter.js +0 -63
  205. package/src/core/state/events.js +0 -29
  206. package/src/core/state/index.js +0 -6
  207. package/src/core/state/lifecycle.js +0 -64
  208. package/src/core/state/store.js +0 -112
  209. package/src/core/utils/index.js +0 -39
  210. package/src/core/utils/object.js +0 -22
  211. package/src/core/utils/validate.js +0 -37
  212. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  213. /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
  214. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  215. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  216. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  217. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  218. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  219. /package/src/components/switch/{constants.js → constants.ts} +0 -0
  220. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -0,0 +1,209 @@
1
+ // src/core/dom/events.ts
2
+ /**
3
+ * @module core/dom
4
+ * @description DOM manipulation utilities
5
+ */
6
+
7
+ /**
8
+ * Event manager interface for handling DOM events
9
+ */
10
+ export interface EventManager {
11
+ /**
12
+ * Add an event listener with options
13
+ * @param event - Event name
14
+ * @param handler - Event handler
15
+ * @param options - addEventListener options
16
+ * @returns EventManager instance for chaining
17
+ */
18
+ on: <T extends Event>(event: string, handler: (e: T) => void, options?: AddEventListenerOptions) => EventManager;
19
+
20
+ /**
21
+ * Remove an event listener
22
+ * @param event - Event name
23
+ * @param handler - Event handler
24
+ * @returns EventManager instance for chaining
25
+ */
26
+ off: <T extends Event>(event: string, handler: (e: T) => void) => EventManager;
27
+
28
+ /**
29
+ * Temporarily disable all event listeners
30
+ * @returns EventManager instance for chaining
31
+ */
32
+ pause: () => EventManager;
33
+
34
+ /**
35
+ * Re-enable all event listeners
36
+ * @returns EventManager instance for chaining
37
+ */
38
+ resume: () => EventManager;
39
+
40
+ /**
41
+ * Remove all event listeners and clean up
42
+ */
43
+ destroy: () => void;
44
+
45
+ /**
46
+ * Get all active handlers
47
+ * @returns Map of active handlers
48
+ */
49
+ getHandlers: () => Map<string, HandlerInfo>;
50
+
51
+ /**
52
+ * Check if a specific handler exists
53
+ * @param event - Event name
54
+ * @param handler - Event handler
55
+ * @returns Whether handler exists
56
+ */
57
+ hasHandler: <T extends Event>(event: string, handler: (e: T) => void) => boolean;
58
+ }
59
+
60
+ /**
61
+ * Handler information
62
+ */
63
+ interface HandlerInfo {
64
+ original: EventListener;
65
+ enhanced: EventListener;
66
+ event: string;
67
+ options: AddEventListenerOptions;
68
+ }
69
+
70
+ /**
71
+ * Creates an event manager to handle DOM events with enhanced functionality.
72
+ * Provides a robust interface for managing event listeners with error handling,
73
+ * cleanup, and lifecycle management.
74
+ *
75
+ * @param element - DOM element to attach events to
76
+ * @returns Event manager interface
77
+ */
78
+ export const createEventManager = (element: HTMLElement): EventManager => {
79
+ // Store handlers with their metadata
80
+ const handlers = new Map<string, HandlerInfo>();
81
+
82
+ /**
83
+ * Creates a unique handler identifier
84
+ * @param event - Event name
85
+ * @param handler - EventListener
86
+ * @returns Unique identifier
87
+ */
88
+ const createHandlerId = (event: string, handler: EventListener): string =>
89
+ `${event}_${handler.toString()}`;
90
+
91
+ /**
92
+ * Wraps an event handler with error boundary and logging
93
+ * @param handler - Original event handler
94
+ * @param event - Event name for error context
95
+ * @returns Enhanced handler with error boundary
96
+ */
97
+ const enhanceHandler = (handler: EventListener, event: string): EventListener => (e: Event) => {
98
+ try {
99
+ handler(e);
100
+ } catch (error) {
101
+ console.error(`Error in ${event} handler:`, error);
102
+ }
103
+ };
104
+
105
+ /**
106
+ * Safely removes event listener
107
+ * @param event - Event name
108
+ * @param handler - Event handler
109
+ */
110
+ const safeRemoveListener = (event: string, handler: EventListener): void => {
111
+ try {
112
+ element.removeEventListener(event, handler);
113
+ } catch (error) {
114
+ console.warn(`Failed to remove ${event} listener:`, error);
115
+ }
116
+ };
117
+
118
+ return {
119
+ /**
120
+ * Adds an event listener with options
121
+ * @param event - Event name
122
+ * @param handler - Event handler
123
+ * @param options - addEventListener options
124
+ * @returns EventManager instance for chaining
125
+ */
126
+ on<T extends Event>(event: string, handler: (e: T) => void, options: AddEventListenerOptions = {}): EventManager {
127
+ const enhanced = enhanceHandler(handler as EventListener, event);
128
+ const id = createHandlerId(event, handler as EventListener);
129
+
130
+ handlers.set(id, {
131
+ original: handler as EventListener,
132
+ enhanced,
133
+ event,
134
+ options
135
+ });
136
+
137
+ element.addEventListener(event, enhanced, options);
138
+ return this;
139
+ },
140
+
141
+ /**
142
+ * Removes an event listener
143
+ * @param event - Event name
144
+ * @param handler - Event handler
145
+ * @returns EventManager instance for chaining
146
+ */
147
+ off<T extends Event>(event: string, handler: (e: T) => void): EventManager {
148
+ const id = createHandlerId(event, handler as EventListener);
149
+ const stored = handlers.get(id);
150
+
151
+ if (stored) {
152
+ safeRemoveListener(event, stored.enhanced);
153
+ handlers.delete(id);
154
+ }
155
+ return this;
156
+ },
157
+
158
+ /**
159
+ * Temporarily disables all event listeners
160
+ * @returns EventManager instance for chaining
161
+ */
162
+ pause(): EventManager {
163
+ handlers.forEach(({ enhanced, event }) => {
164
+ safeRemoveListener(event, enhanced);
165
+ });
166
+ return this;
167
+ },
168
+
169
+ /**
170
+ * Re-enables all event listeners
171
+ * @returns EventManager instance for chaining
172
+ */
173
+ resume(): EventManager {
174
+ handlers.forEach(({ enhanced, event, options }) => {
175
+ element.addEventListener(event, enhanced, options);
176
+ });
177
+ return this;
178
+ },
179
+
180
+ /**
181
+ * Removes all event listeners and cleans up
182
+ */
183
+ destroy(): void {
184
+ handlers.forEach(({ enhanced, event }) => {
185
+ safeRemoveListener(event, enhanced);
186
+ });
187
+ handlers.clear();
188
+ },
189
+
190
+ /**
191
+ * Gets all active handlers
192
+ * @returns Map of active handlers
193
+ */
194
+ getHandlers(): Map<string, HandlerInfo> {
195
+ return new Map(handlers);
196
+ },
197
+
198
+ /**
199
+ * Checks if a specific handler exists
200
+ * @param event - Event name
201
+ * @param handler - Event handler
202
+ * @returns Whether handler exists
203
+ */
204
+ hasHandler<T extends Event>(event: string, handler: (e: T) => void): boolean {
205
+ const id = createHandlerId(event, handler as EventListener);
206
+ return handlers.has(id);
207
+ }
208
+ };
209
+ };
@@ -0,0 +1,10 @@
1
+ // src/core/dom/index.ts
2
+
3
+ export { createElement, withAttributes, withClasses, withContent } from './create';
4
+ export type { CreateElementOptions } from './create';
5
+
6
+ export { setAttributes, removeAttributes } from './attributes';
7
+ export { addClass, removeClass, toggleClass, hasClass } from './classes';
8
+
9
+ export { createEventManager } from './events';
10
+ export type { EventManager } from './events';
@@ -0,0 +1,97 @@
1
+ // src/core/dom/utils.ts
2
+
3
+ /**
4
+ * Normalizes class names input by handling various formats:
5
+ * - String with space-separated classes
6
+ * - Array of strings
7
+ * - Mixed array of strings and space-separated classes
8
+ *
9
+ * @param classes - Classes to normalize
10
+ * @returns Array of unique, non-empty class names
11
+ */
12
+ export const normalizeClasses = (...classes: (string | string[])[]): string[] => {
13
+ return [...new Set(
14
+ classes
15
+ .flat()
16
+ .reduce((acc: string[], cls) => {
17
+ if (typeof cls === 'string') {
18
+ // Split space-separated classes and add them individually
19
+ acc.push(...cls.split(/\s+/));
20
+ }
21
+ return acc;
22
+ }, [])
23
+ .filter(Boolean) // Remove empty strings
24
+ )];
25
+ };
26
+
27
+ /**
28
+ * Creates a DOM element with attributes
29
+ *
30
+ * @param tag - Element tag name
31
+ * @param attributes - Element attributes
32
+ * @returns Created element
33
+ */
34
+ export const createElement = <T extends HTMLElement>(tag: string, attributes: Record<string, any> = {}): T => {
35
+ const element = document.createElement(tag) as T;
36
+
37
+ Object.entries(attributes).forEach(([key, value]) => {
38
+ if (key === 'className') {
39
+ element.className = value;
40
+ } else if (key === 'style' && typeof value === 'object') {
41
+ Object.assign(element.style, value);
42
+ } else if (key === 'data' && typeof value === 'object') {
43
+ Object.entries(value).forEach(([dataKey, dataValue]) => {
44
+ element.dataset[dataKey] = String(dataValue);
45
+ });
46
+ } else if (key === 'children' && Array.isArray(value)) {
47
+ value.forEach(child => {
48
+ if (child instanceof Node) {
49
+ element.appendChild(child);
50
+ } else if (child != null) {
51
+ element.appendChild(document.createTextNode(String(child)));
52
+ }
53
+ });
54
+ } else if (key.startsWith('on') && typeof value === 'function') {
55
+ const eventName = key.slice(2).toLowerCase();
56
+ element.addEventListener(eventName, value);
57
+ } else if (value !== null && value !== undefined) {
58
+ element.setAttribute(key, String(value));
59
+ }
60
+ });
61
+
62
+ return element;
63
+ };
64
+
65
+ /**
66
+ * Sets inline styles on an element
67
+ *
68
+ * @param element - Target element
69
+ * @param styles - Styles to set
70
+ * @returns Modified element
71
+ */
72
+ export const setStyles = <T extends HTMLElement>(element: T, styles: Partial<CSSStyleDeclaration>): T => {
73
+ Object.assign(element.style, styles);
74
+ return element;
75
+ };
76
+
77
+ /**
78
+ * Checks if an element matches a selector
79
+ *
80
+ * @param element - Element to check
81
+ * @param selector - CSS selector
82
+ * @returns Whether element matches selector
83
+ */
84
+ export const matches = (element: Element, selector: string): boolean => {
85
+ return element.matches(selector);
86
+ };
87
+
88
+ /**
89
+ * Finds the closest ancestor matching a selector
90
+ *
91
+ * @param element - Starting element
92
+ * @param selector - CSS selector
93
+ * @returns Matching ancestor or null
94
+ */
95
+ export const closest = <T extends HTMLElement>(element: Element, selector: string): T | null => {
96
+ return element.closest(selector) as T | null;
97
+ };
@@ -0,0 +1,111 @@
1
+ // src/core/index.ts
2
+ /**
3
+ * @module core
4
+ * @description Core utilities and building blocks for the component system
5
+ */
6
+
7
+ // Config
8
+ export { PREFIX, COMPONENTS, STATES, classNames } from './config';
9
+ export type {
10
+ ThemeConfig,
11
+ ComponentConfig,
12
+ ThemedComponentConfig,
13
+ VariantComponentConfig,
14
+ StateComponentConfig
15
+ } from './config';
16
+
17
+ // Build
18
+ export { createText } from './build/text';
19
+ export { createIcon } from './build/icon';
20
+ export { createRipple } from './build/ripple';
21
+ export { RIPPLE_TIMING } from './build/constants';
22
+
23
+ // DOM manipulation
24
+ export { createElement, withAttributes, withClasses, withContent } from './dom/create';
25
+ export { setAttributes, removeAttributes } from './dom/attributes';
26
+ export { addClass, removeClass, toggleClass, hasClass } from './dom/classes';
27
+
28
+ // State Management
29
+ export { createDisabled } from './state/disabled';
30
+ export { createEventManager } from './state/events';
31
+ export { createLifecycle } from './state/lifecycle';
32
+ export { createEmitter } from './state/emitter';
33
+ export { createStore } from './state/store';
34
+
35
+ // Composition Utilities
36
+ export { pipe, compose, transform } from './compose/pipe';
37
+ export { createBase, withElement } from './compose/component';
38
+ export {
39
+ withEvents,
40
+ withText,
41
+ withIcon,
42
+ withVariant,
43
+ withSize,
44
+ withPosition,
45
+ withDisabled,
46
+ withLifecycle,
47
+ withRipple
48
+ } from './compose/features';
49
+
50
+ // Utilities
51
+ export {
52
+ normalizeClasses,
53
+ when,
54
+ classNames as joinClasses,
55
+ isObject,
56
+ byString,
57
+ hasTouchSupport,
58
+ isMobileDevice,
59
+ normalizeEvent
60
+ } from './utils';
61
+
62
+ // Component feature interfaces for better developer experience
63
+ export type {
64
+ BaseComponent,
65
+ ElementComponent,
66
+ TouchState
67
+ } from './compose/component';
68
+
69
+ export type {
70
+ EventComponent,
71
+ TextComponent,
72
+ IconComponent,
73
+ LifecycleComponent,
74
+ Lifecycle,
75
+ DisabledComponent,
76
+ DisabledManager,
77
+ RippleComponent
78
+ } from './compose/features';
79
+
80
+ // Other interfaces
81
+ export type {
82
+ CreateElementOptions
83
+ } from './dom/create';
84
+
85
+ export type {
86
+ TextManager,
87
+ TextConfig
88
+ } from './build/text';
89
+
90
+ export type {
91
+ IconManager,
92
+ IconConfig
93
+ } from './build/icon';
94
+
95
+ export type {
96
+ RippleController,
97
+ RippleConfig
98
+ } from './build/ripple';
99
+
100
+ export type {
101
+ Emitter,
102
+ EventCallback
103
+ } from './state/emitter';
104
+
105
+ export type {
106
+ DisabledState
107
+ } from './state/disabled';
108
+
109
+ export type {
110
+ NormalizedEvent
111
+ } from './utils/mobile';
@@ -0,0 +1,81 @@
1
+ // src/core/state/disabled.ts
2
+
3
+ /**
4
+ * Disabled state manager interface
5
+ */
6
+ export interface DisabledState {
7
+ /**
8
+ * Enables the element
9
+ * @returns DisabledState instance for chaining
10
+ */
11
+ enable(): DisabledState;
12
+
13
+ /**
14
+ * Disables the element
15
+ * @returns DisabledState instance for chaining
16
+ */
17
+ disable(): DisabledState;
18
+
19
+ /**
20
+ * Toggles the disabled state
21
+ * @returns DisabledState instance for chaining
22
+ */
23
+ toggle(): DisabledState;
24
+
25
+ /**
26
+ * Checks if the element is disabled
27
+ * @returns true if disabled
28
+ */
29
+ isDisabled(): boolean;
30
+ }
31
+
32
+ /**
33
+ * Creates a controller for managing the disabled state of an element
34
+ *
35
+ * @param element - The element to control
36
+ * @returns Disabled state controller
37
+ */
38
+ export const createDisabled = (element: HTMLElement): DisabledState => {
39
+ return {
40
+ /**
41
+ * Enables the element
42
+ * @returns DisabledState instance for chaining
43
+ */
44
+ enable() {
45
+ (element as HTMLButtonElement | HTMLInputElement).disabled = false;
46
+ element.removeAttribute('disabled');
47
+ return this;
48
+ },
49
+
50
+ /**
51
+ * Disables the element
52
+ * @returns DisabledState instance for chaining
53
+ */
54
+ disable() {
55
+ (element as HTMLButtonElement | HTMLInputElement).disabled = true;
56
+ element.setAttribute('disabled', 'true');
57
+ return this;
58
+ },
59
+
60
+ /**
61
+ * Toggles the disabled state
62
+ * @returns DisabledState instance for chaining
63
+ */
64
+ toggle() {
65
+ if ((element as HTMLButtonElement | HTMLInputElement).disabled) {
66
+ this.enable();
67
+ } else {
68
+ this.disable();
69
+ }
70
+ return this;
71
+ },
72
+
73
+ /**
74
+ * Checks if the element is disabled
75
+ * @returns true if disabled
76
+ */
77
+ isDisabled() {
78
+ return (element as HTMLButtonElement | HTMLInputElement).disabled === true;
79
+ }
80
+ };
81
+ };
@@ -0,0 +1,94 @@
1
+ // src/core/state/emitter.ts
2
+ /**
3
+ * @module core/state
4
+ */
5
+
6
+ /**
7
+ * Type definition for event callback functions
8
+ */
9
+ export type EventCallback = (...args: any[]) => void;
10
+
11
+ /**
12
+ * Interface for the event emitter
13
+ */
14
+ export interface Emitter {
15
+ /**
16
+ * Subscribe to an event
17
+ * @param event - Event name
18
+ * @param callback - Event handler
19
+ * @returns Unsubscribe function
20
+ */
21
+ on(event: string, callback: EventCallback): () => void;
22
+
23
+ /**
24
+ * Unsubscribe from an event
25
+ * @param event - Event name
26
+ * @param callback - Event handler to remove
27
+ */
28
+ off(event: string, callback: EventCallback): void;
29
+
30
+ /**
31
+ * Emit an event
32
+ * @param event - Event name
33
+ * @param args - Event arguments
34
+ */
35
+ emit(event: string, ...args: any[]): void;
36
+
37
+ /**
38
+ * Clear all event listeners
39
+ */
40
+ clear(): void;
41
+ }
42
+
43
+ /**
44
+ * Creates an event emitter with subscription management
45
+ * @returns Event emitter interface
46
+ */
47
+ export const createEmitter = (): Emitter => {
48
+ const events = new Map<string, EventCallback[]>();
49
+
50
+ return {
51
+ /**
52
+ * Subscribe to an event
53
+ * @param event - Event name
54
+ * @param callback - Event handler
55
+ * @returns Unsubscribe function
56
+ */
57
+ on: (event: string, callback: EventCallback): (() => void) => {
58
+ const callbacks = events.get(event) || [];
59
+ events.set(event, [...callbacks, callback]);
60
+
61
+ return () => {
62
+ const callbacks = events.get(event) || [];
63
+ events.set(event, callbacks.filter(cb => cb !== callback));
64
+ };
65
+ },
66
+
67
+ /**
68
+ * Unsubscribe from an event
69
+ * @param event - Event name
70
+ * @param callback - Event handler to remove
71
+ */
72
+ off(event: string, callback: EventCallback): void {
73
+ const callbacks = events.get(event) || [];
74
+ events.set(event, callbacks.filter(cb => cb !== callback));
75
+ },
76
+
77
+ /**
78
+ * Emit an event
79
+ * @param event - Event name
80
+ * @param args - Event arguments
81
+ */
82
+ emit: (event: string, ...args: any[]): void => {
83
+ const callbacks = events.get(event) || [];
84
+ callbacks.forEach(cb => cb(...args));
85
+ },
86
+
87
+ /**
88
+ * Clear all event listeners
89
+ */
90
+ clear: (): void => {
91
+ events.clear();
92
+ }
93
+ };
94
+ };
@@ -0,0 +1,88 @@
1
+ // src/core/state/events.ts
2
+
3
+ /**
4
+ * Event manager interface for handling component events
5
+ */
6
+ export interface EventManagerState {
7
+ /**
8
+ * Adds an event listener
9
+ * @param event - Event name
10
+ * @param handler - Event handler
11
+ * @returns EventManagerState instance for chaining
12
+ */
13
+ on: (event: string, handler: (...args: any[]) => void) => EventManagerState;
14
+
15
+ /**
16
+ * Removes an event listener
17
+ * @param event - Event name
18
+ * @param handler - Event handler
19
+ * @returns EventManagerState instance for chaining
20
+ */
21
+ off: (event: string, handler: (...args: any[]) => void) => EventManagerState;
22
+
23
+ /**
24
+ * Removes all event listeners and cleans up
25
+ */
26
+ destroy: () => void;
27
+
28
+ /**
29
+ * Gets all active handlers
30
+ * @returns Map of event names to handlers
31
+ */
32
+ getHandlers: () => Map<(...args: any[]) => void, string>;
33
+ }
34
+
35
+ /**
36
+ * Creates an event manager for a component
37
+ * Simple event handling mechanism for components
38
+ *
39
+ * @param element - Component's DOM element
40
+ * @returns Event manager interface
41
+ */
42
+ export const createEventManager = (element: HTMLElement): EventManagerState => {
43
+ const handlers = new Map<(...args: any[]) => void, string>();
44
+
45
+ return {
46
+ /**
47
+ * Adds an event listener
48
+ * @param event - Event name
49
+ * @param handler - Event handler
50
+ * @returns EventManagerState instance for chaining
51
+ */
52
+ on(event: string, handler: (...args: any[]) => void): EventManagerState {
53
+ element.addEventListener(event, handler as EventListener);
54
+ handlers.set(handler, event);
55
+ return this;
56
+ },
57
+
58
+ /**
59
+ * Removes an event listener
60
+ * @param event - Event name
61
+ * @param handler - Event handler
62
+ * @returns EventManagerState instance for chaining
63
+ */
64
+ off(event: string, handler: (...args: any[]) => void): EventManagerState {
65
+ element.removeEventListener(event, handler as EventListener);
66
+ handlers.delete(handler);
67
+ return this;
68
+ },
69
+
70
+ /**
71
+ * Removes all event listeners and cleans up
72
+ */
73
+ destroy(): void {
74
+ handlers.forEach((event, handler) => {
75
+ element.removeEventListener(event, handler as EventListener);
76
+ });
77
+ handlers.clear();
78
+ },
79
+
80
+ /**
81
+ * Gets all active handlers
82
+ * @returns Map of handlers to event names
83
+ */
84
+ getHandlers(): Map<(...args: any[]) => void, string> {
85
+ return new Map(handlers);
86
+ }
87
+ };
88
+ };
@@ -0,0 +1,16 @@
1
+ // src/core/state/index.ts
2
+
3
+ export { createEmitter } from './emitter';
4
+ export type { Emitter, EventCallback } from './emitter';
5
+
6
+ export { createStore, loggingMiddleware, deriveFiltered } from './store';
7
+ export type { Store, StoreOptions, Selector, Computation, Updater } from './store';
8
+
9
+ export { createLifecycle } from './lifecycle';
10
+ export type { LifecycleManager, LifecycleManagers } from './lifecycle';
11
+
12
+ export { createDisabled } from './disabled';
13
+ export type { DisabledState } from './disabled';
14
+
15
+ export { createEventManager } from './events';
16
+ export type { EventManagerState } from './events';