mtrl 0.1.3 → 0.2.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 (225) 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 → _styles.scss} +79 -7
  12. package/src/components/card/{actions.js → actions.ts} +15 -18
  13. package/src/components/card/{api.js → api.ts} +33 -33
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/{constants.js → constants.ts} +11 -10
  17. package/src/components/card/{content.js → content.ts} +15 -18
  18. package/src/components/card/{features.js → features.ts} +104 -94
  19. package/src/components/card/{header.js → header.ts} +21 -25
  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/constants.ts +37 -0
  27. package/src/components/checkbox/index.ts +4 -0
  28. package/src/components/checkbox/types.ts +146 -0
  29. package/src/components/chip/_styles.scss +372 -0
  30. package/src/components/chip/api.ts +115 -0
  31. package/src/components/chip/chip-set.ts +225 -0
  32. package/src/components/chip/chip.ts +82 -0
  33. package/src/components/chip/config.ts +92 -0
  34. package/src/components/chip/constants.ts +38 -0
  35. package/src/components/chip/index.ts +4 -0
  36. package/src/components/chip/types.ts +172 -0
  37. package/src/components/list/api.ts +72 -0
  38. package/src/components/list/config.ts +43 -0
  39. package/src/components/list/{constants.js → constants.ts} +34 -7
  40. package/src/components/list/features.ts +224 -0
  41. package/src/components/list/index.ts +14 -0
  42. package/src/components/list/list-item.ts +120 -0
  43. package/src/components/list/list.ts +37 -0
  44. package/src/components/list/types.ts +179 -0
  45. package/src/components/list/utils.ts +47 -0
  46. package/src/components/menu/api.ts +119 -0
  47. package/src/components/menu/config.ts +54 -0
  48. package/src/components/menu/constants.ts +154 -0
  49. package/src/components/menu/features/items-manager.ts +457 -0
  50. package/src/components/menu/features/keyboard-navigation.ts +133 -0
  51. package/src/components/menu/features/positioning.ts +127 -0
  52. package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
  53. package/src/components/menu/index.ts +14 -0
  54. package/src/components/menu/menu-item.ts +43 -0
  55. package/src/components/menu/menu.ts +53 -0
  56. package/src/components/menu/types.ts +178 -0
  57. package/src/components/navigation/api.ts +79 -0
  58. package/src/components/navigation/config.ts +61 -0
  59. package/src/components/navigation/{constants.js → constants.ts} +10 -10
  60. package/src/components/navigation/index.ts +14 -0
  61. package/src/components/navigation/nav-item.ts +148 -0
  62. package/src/components/navigation/navigation.ts +50 -0
  63. package/src/components/navigation/types.ts +212 -0
  64. package/src/components/progress/_styles.scss +204 -0
  65. package/src/components/progress/api.ts +179 -0
  66. package/src/components/progress/config.ts +124 -0
  67. package/src/components/progress/constants.ts +43 -0
  68. package/src/components/progress/index.ts +5 -0
  69. package/src/components/progress/progress.ts +163 -0
  70. package/src/components/progress/types.ts +102 -0
  71. package/src/components/snackbar/api.ts +162 -0
  72. package/src/components/snackbar/config.ts +62 -0
  73. package/src/components/snackbar/{constants.js → constants.ts} +21 -4
  74. package/src/components/snackbar/features.ts +76 -0
  75. package/src/components/snackbar/index.ts +4 -0
  76. package/src/components/snackbar/position.ts +71 -0
  77. package/src/components/snackbar/queue.ts +76 -0
  78. package/src/components/snackbar/snackbar.ts +60 -0
  79. package/src/components/snackbar/types.ts +58 -0
  80. package/src/components/switch/api.ts +77 -0
  81. package/src/components/switch/config.ts +74 -0
  82. package/src/components/switch/{constants.js → constants.ts} +5 -5
  83. package/src/components/switch/index.ts +4 -0
  84. package/src/components/switch/switch.ts +52 -0
  85. package/src/components/switch/types.ts +142 -0
  86. package/src/components/textfield/api.ts +72 -0
  87. package/src/components/textfield/config.ts +54 -0
  88. package/src/components/textfield/{constants.js → constants.ts} +38 -5
  89. package/src/components/textfield/index.ts +4 -0
  90. package/src/components/textfield/textfield.ts +50 -0
  91. package/src/components/textfield/types.ts +139 -0
  92. package/src/core/compose/base.ts +43 -0
  93. package/src/core/compose/component.ts +255 -0
  94. package/src/core/compose/features/checkable.ts +155 -0
  95. package/src/core/compose/features/disabled.ts +116 -0
  96. package/src/core/compose/features/events.ts +65 -0
  97. package/src/core/compose/features/icon.ts +67 -0
  98. package/src/core/compose/features/index.ts +35 -0
  99. package/src/core/compose/features/input.ts +174 -0
  100. package/src/core/compose/features/lifecycle.ts +139 -0
  101. package/src/core/compose/features/position.ts +94 -0
  102. package/src/core/compose/features/ripple.ts +55 -0
  103. package/src/core/compose/features/size.ts +29 -0
  104. package/src/core/compose/features/style.ts +31 -0
  105. package/src/core/compose/features/text.ts +44 -0
  106. package/src/core/compose/features/textinput.ts +225 -0
  107. package/src/core/compose/features/textlabel.ts +92 -0
  108. package/src/core/compose/features/track.ts +84 -0
  109. package/src/core/compose/features/variant.ts +29 -0
  110. package/src/core/compose/features/withEvents.ts +137 -0
  111. package/src/core/compose/index.ts +54 -0
  112. package/src/core/compose/{pipe.js → pipe.ts} +16 -11
  113. package/src/core/config/component-config.ts +136 -0
  114. package/src/core/config.ts +211 -0
  115. package/src/core/dom/{attributes.js → attributes.ts} +11 -11
  116. package/src/core/dom/classes.ts +60 -0
  117. package/src/core/dom/create.ts +251 -0
  118. package/src/core/dom/events.ts +209 -0
  119. package/src/core/dom/index.ts +10 -0
  120. package/src/core/dom/utils.ts +97 -0
  121. package/src/core/index.ts +111 -0
  122. package/src/core/state/disabled.ts +81 -0
  123. package/src/core/state/emitter.ts +94 -0
  124. package/src/core/state/events.ts +88 -0
  125. package/src/core/state/index.ts +16 -0
  126. package/src/core/state/lifecycle.ts +131 -0
  127. package/src/core/state/store.ts +197 -0
  128. package/src/core/utils/index.ts +45 -0
  129. package/src/core/utils/{mobile.js → mobile.ts} +48 -24
  130. package/src/core/utils/object.ts +41 -0
  131. package/src/core/utils/validate.ts +234 -0
  132. package/src/{index.js → index.ts} +3 -2
  133. package/index.js +0 -11
  134. package/src/components/button/api.js +0 -54
  135. package/src/components/button/button.js +0 -81
  136. package/src/components/button/config.js +0 -10
  137. package/src/components/button/constants.js +0 -63
  138. package/src/components/button/index.js +0 -2
  139. package/src/components/card/card.js +0 -102
  140. package/src/components/card/config.js +0 -16
  141. package/src/components/card/index.js +0 -7
  142. package/src/components/card/media.js +0 -56
  143. package/src/components/checkbox/api.js +0 -45
  144. package/src/components/checkbox/checkbox.js +0 -96
  145. package/src/components/checkbox/constants.js +0 -88
  146. package/src/components/checkbox/index.js +0 -2
  147. package/src/components/container/api.js +0 -42
  148. package/src/components/container/container.js +0 -45
  149. package/src/components/container/index.js +0 -2
  150. package/src/components/container/styles.scss +0 -66
  151. package/src/components/list/index.js +0 -2
  152. package/src/components/list/list-item.js +0 -147
  153. package/src/components/list/list.js +0 -267
  154. package/src/components/menu/api.js +0 -117
  155. package/src/components/menu/constants.js +0 -42
  156. package/src/components/menu/features/items-manager.js +0 -375
  157. package/src/components/menu/features/keyboard-navigation.js +0 -129
  158. package/src/components/menu/features/positioning.js +0 -125
  159. package/src/components/menu/index.js +0 -2
  160. package/src/components/menu/menu-item.js +0 -41
  161. package/src/components/menu/menu.js +0 -54
  162. package/src/components/navigation/api.js +0 -43
  163. package/src/components/navigation/index.js +0 -2
  164. package/src/components/navigation/nav-item.js +0 -137
  165. package/src/components/navigation/navigation.js +0 -55
  166. package/src/components/snackbar/api.js +0 -125
  167. package/src/components/snackbar/features.js +0 -69
  168. package/src/components/snackbar/index.js +0 -2
  169. package/src/components/snackbar/position.js +0 -63
  170. package/src/components/snackbar/queue.js +0 -74
  171. package/src/components/snackbar/snackbar.js +0 -70
  172. package/src/components/switch/api.js +0 -44
  173. package/src/components/switch/index.js +0 -2
  174. package/src/components/switch/switch.js +0 -71
  175. package/src/components/textfield/api.js +0 -49
  176. package/src/components/textfield/index.js +0 -2
  177. package/src/components/textfield/textfield.js +0 -68
  178. package/src/core/build/_ripple.scss +0 -79
  179. package/src/core/build/constants.js +0 -51
  180. package/src/core/build/icon.js +0 -78
  181. package/src/core/build/ripple.js +0 -159
  182. package/src/core/build/text.js +0 -54
  183. package/src/core/compose/base.js +0 -8
  184. package/src/core/compose/component.js +0 -225
  185. package/src/core/compose/features/checkable.js +0 -114
  186. package/src/core/compose/features/disabled.js +0 -64
  187. package/src/core/compose/features/events.js +0 -48
  188. package/src/core/compose/features/icon.js +0 -33
  189. package/src/core/compose/features/index.js +0 -20
  190. package/src/core/compose/features/input.js +0 -100
  191. package/src/core/compose/features/lifecycle.js +0 -69
  192. package/src/core/compose/features/position.js +0 -60
  193. package/src/core/compose/features/ripple.js +0 -32
  194. package/src/core/compose/features/size.js +0 -9
  195. package/src/core/compose/features/style.js +0 -12
  196. package/src/core/compose/features/text.js +0 -17
  197. package/src/core/compose/features/textinput.js +0 -114
  198. package/src/core/compose/features/textlabel.js +0 -28
  199. package/src/core/compose/features/track.js +0 -49
  200. package/src/core/compose/features/variant.js +0 -9
  201. package/src/core/compose/features/withEvents.js +0 -67
  202. package/src/core/compose/index.js +0 -16
  203. package/src/core/config.js +0 -140
  204. package/src/core/dom/classes.js +0 -70
  205. package/src/core/dom/create.js +0 -132
  206. package/src/core/dom/events.js +0 -175
  207. package/src/core/dom/index.js +0 -5
  208. package/src/core/dom/utils.js +0 -22
  209. package/src/core/index.js +0 -23
  210. package/src/core/state/disabled.js +0 -51
  211. package/src/core/state/emitter.js +0 -63
  212. package/src/core/state/events.js +0 -29
  213. package/src/core/state/index.js +0 -6
  214. package/src/core/state/lifecycle.js +0 -64
  215. package/src/core/state/store.js +0 -112
  216. package/src/core/utils/index.js +0 -39
  217. package/src/core/utils/object.js +0 -22
  218. package/src/core/utils/validate.js +0 -37
  219. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  220. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  221. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  222. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  223. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  224. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  225. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -0,0 +1,35 @@
1
+ // src/core/compose/features/index.ts
2
+
3
+ // Core features
4
+ export { withEvents } from './events';
5
+ export { withText } from './text';
6
+ export { withIcon } from './icon';
7
+ export { withVariant } from './variant';
8
+ export { withSize } from './size';
9
+ export { withPosition } from './position';
10
+ export { withRipple } from './ripple';
11
+ export { withInput } from './input';
12
+ export { withCheckable } from './checkable';
13
+ export { withStyle } from './style';
14
+ export { withTextInput } from './textinput';
15
+ export { withTextLabel } from './textlabel';
16
+ export { withTrack } from './track';
17
+ export { withEvents as withEnhancedEvents } from './withEvents';
18
+
19
+ // State management features
20
+ export { withDisabled } from './disabled';
21
+ export { withLifecycle } from './lifecycle';
22
+
23
+ // Re-export interfaces for better developer experience
24
+ export type { EventComponent } from './events';
25
+ export type { TextComponent } from './text';
26
+ export type { IconComponent } from './icon';
27
+ export type { LifecycleComponent, Lifecycle } from './lifecycle';
28
+ export type { DisabledComponent, DisabledManager } from './disabled';
29
+ export type { RippleComponent } from './ripple';
30
+ export type { InputComponent } from './input';
31
+ export type { CheckableComponent, CheckableManager } from './checkable';
32
+ export type { TextInputComponent } from './textinput';
33
+ export type { LabelComponent, LabelManager } from './textlabel';
34
+ export type { TrackComponent } from './track';
35
+ export type { EnhancedEventComponent } from './withEvents';
@@ -0,0 +1,174 @@
1
+ // src/core/compose/features/input.ts
2
+
3
+ import { BaseComponent, ElementComponent } from '../component';
4
+
5
+ /**
6
+ * Input configuration options
7
+ */
8
+ export interface InputConfig {
9
+ /**
10
+ * Input name attribute
11
+ */
12
+ name?: string;
13
+
14
+ /**
15
+ * Initial checked state
16
+ */
17
+ checked?: boolean;
18
+
19
+ /**
20
+ * Whether input is required
21
+ */
22
+ required?: boolean;
23
+
24
+ /**
25
+ * Whether input is disabled
26
+ */
27
+ disabled?: boolean;
28
+
29
+ /**
30
+ * Input value attribute
31
+ */
32
+ value?: string;
33
+
34
+ /**
35
+ * Accessibility label text
36
+ */
37
+ label?: string;
38
+
39
+ /**
40
+ * Alternative accessibility label
41
+ */
42
+ ariaLabel?: string;
43
+
44
+ /**
45
+ * Component name for classes
46
+ */
47
+ componentName?: string;
48
+
49
+ [key: string]: any;
50
+ }
51
+
52
+ /**
53
+ * Component with input element and related methods
54
+ */
55
+ export interface InputComponent extends ElementComponent {
56
+ /**
57
+ * Input element
58
+ */
59
+ input: HTMLInputElement;
60
+
61
+ /**
62
+ * Gets the current input value
63
+ * @returns Current value
64
+ */
65
+ getValue: () => string;
66
+
67
+ /**
68
+ * Sets the input value and emits a value event
69
+ * @param value - New value to set
70
+ * @returns Component instance for chaining
71
+ */
72
+ setValue: (value: string) => InputComponent;
73
+
74
+ /**
75
+ * Event emission method if available
76
+ */
77
+ emit?: (event: string, data: any) => InputComponent;
78
+ }
79
+
80
+ /**
81
+ * Creates an input element and adds it to a component
82
+ * Handles both input creation and event emission for state changes
83
+ *
84
+ * @param config - Input configuration
85
+ * @returns Function that enhances a component with input functionality
86
+ */
87
+ export const withInput = <T extends InputConfig>(config: T = {} as T) =>
88
+ <C extends ElementComponent>(component: C): C & InputComponent => {
89
+ const input = document.createElement('input');
90
+ const name = component.componentName || 'component';
91
+ input.type = 'checkbox';
92
+ input.className = `${component.getClass(name)}-input`;
93
+
94
+ // Ensure input can receive focus
95
+ input.style.position = 'absolute';
96
+ input.style.opacity = '0';
97
+ input.style.cursor = 'pointer';
98
+ // Don't use display: none or visibility: hidden as they prevent focus
99
+
100
+ // The input itself should be focusable, not the wrapper
101
+ component.element.setAttribute('role', 'presentation');
102
+ input.setAttribute('role', name);
103
+
104
+ const attributes: Record<string, string | boolean | undefined> = {
105
+ name: config.name,
106
+ checked: config.checked,
107
+ required: config.required,
108
+ disabled: config.disabled,
109
+ value: config.value || 'on',
110
+ 'aria-label': config.label || config.ariaLabel
111
+ };
112
+
113
+ Object.entries(attributes).forEach(([key, value]) => {
114
+ if (value !== null && value !== undefined) {
115
+ if (key === 'disabled' && value === true) {
116
+ input.disabled = true;
117
+ input.setAttribute('disabled', 'true');
118
+ // Note: We don't add the class here because that's handled by withDisabled
119
+ } else if (value === true) {
120
+ input.setAttribute(key, key);
121
+ } else {
122
+ input.setAttribute(key, String(value));
123
+ }
124
+ }
125
+ });
126
+
127
+ // Bridge native checkbox events to our event system
128
+ input.addEventListener('change', (event) => {
129
+ if (component.emit) {
130
+ component.emit('change', {
131
+ checked: input.checked,
132
+ value: input.value,
133
+ nativeEvent: event
134
+ });
135
+ }
136
+ });
137
+
138
+ // Add keyboard handling
139
+ input.addEventListener('keydown', (event) => {
140
+ if (event.key === ' ' || event.key === 'Enter') {
141
+ event.preventDefault();
142
+ if (!input.disabled) {
143
+ input.checked = !input.checked;
144
+ input.dispatchEvent(new Event('change', { bubbles: true }));
145
+ }
146
+ }
147
+ });
148
+
149
+ component.element.appendChild(input);
150
+
151
+ return {
152
+ ...component,
153
+ input,
154
+
155
+ /**
156
+ * Gets the current input value
157
+ * @returns Current value
158
+ */
159
+ getValue: () => input.value,
160
+
161
+ /**
162
+ * Sets the input value and emits a value event
163
+ * @param value - New value to set
164
+ * @returns Component instance for chaining
165
+ */
166
+ setValue(value: string) {
167
+ input.value = value;
168
+ if (component.emit) {
169
+ component.emit('value', { value });
170
+ }
171
+ return this;
172
+ }
173
+ };
174
+ };
@@ -0,0 +1,139 @@
1
+ // src/core/compose/features/lifecycle.ts
2
+
3
+ import { createEmitter, Emitter } from '../../state/emitter';
4
+ import { BaseComponent, ElementComponent } from '../component';
5
+
6
+ /**
7
+ * Component managers that can be passed to lifecycle
8
+ */
9
+ export interface ComponentManagers {
10
+ events?: {
11
+ destroy: () => void;
12
+ };
13
+ text?: {
14
+ getElement: () => HTMLElement | null;
15
+ };
16
+ icon?: {
17
+ getElement: () => HTMLElement | null;
18
+ };
19
+ [key: string]: any;
20
+ }
21
+
22
+ /**
23
+ * Lifecycle methods interface
24
+ */
25
+ export interface Lifecycle {
26
+ /**
27
+ * Registers a handler for mount event
28
+ * @param handler - Function to call when component is mounted
29
+ * @returns Unsubscribe function
30
+ */
31
+ onMount: (handler: () => void) => () => void;
32
+
33
+ /**
34
+ * Registers a handler for unmount event
35
+ * @param handler - Function to call when component is unmounted
36
+ * @returns Unsubscribe function
37
+ */
38
+ onUnmount: (handler: () => void) => () => void;
39
+
40
+ /**
41
+ * Mounts the component
42
+ */
43
+ mount: () => void;
44
+
45
+ /**
46
+ * Unmounts the component
47
+ */
48
+ unmount: () => void;
49
+
50
+ /**
51
+ * Checks if component is mounted
52
+ */
53
+ isMounted: () => boolean;
54
+
55
+ /**
56
+ * Destroys the component
57
+ */
58
+ destroy: () => void;
59
+ }
60
+
61
+ /**
62
+ * Component with lifecycle capabilities
63
+ */
64
+ export interface LifecycleComponent extends BaseComponent {
65
+ lifecycle: Lifecycle;
66
+ }
67
+
68
+ /**
69
+ * Adds lifecycle management to a component
70
+ *
71
+ * @returns Function that enhances a component with lifecycle management
72
+ */
73
+ export const withLifecycle = () =>
74
+ <T extends ElementComponent>(component: T): T & LifecycleComponent => {
75
+ let mounted = false;
76
+ const emitter: Emitter = createEmitter();
77
+
78
+ const lifecycle: Lifecycle = {
79
+ // Mount/Unmount state management
80
+ onMount: (handler: () => void) => emitter.on('mount', handler),
81
+ onUnmount: (handler: () => void) => emitter.on('unmount', handler),
82
+
83
+ mount: () => {
84
+ if (!mounted) {
85
+ mounted = true;
86
+ emitter.emit('mount');
87
+ }
88
+ },
89
+
90
+ unmount: () => {
91
+ if (mounted) {
92
+ mounted = false;
93
+ emitter.emit('unmount');
94
+ emitter.clear();
95
+ }
96
+ },
97
+
98
+ isMounted: () => mounted,
99
+
100
+ // Cleanup and destruction
101
+ destroy() {
102
+ // First trigger unmount
103
+ if (mounted) {
104
+ this.unmount();
105
+ }
106
+
107
+ // Clean up all event listeners
108
+ if ('events' in component && component.events?.destroy) {
109
+ component.events.destroy();
110
+ }
111
+
112
+ // Clean up text element
113
+ if ('text' in component && component.text?.getElement) {
114
+ const textElement = component.text.getElement();
115
+ if (textElement) {
116
+ textElement.remove();
117
+ }
118
+ }
119
+
120
+ // Clean up icon element
121
+ if ('icon' in component && component.icon?.getElement) {
122
+ const iconElement = component.icon.getElement();
123
+ if (iconElement) {
124
+ iconElement.remove();
125
+ }
126
+ }
127
+
128
+ // Remove the main element
129
+ if (component.element) {
130
+ component.element.remove();
131
+ }
132
+ }
133
+ };
134
+
135
+ return {
136
+ ...component,
137
+ lifecycle
138
+ };
139
+ };
@@ -0,0 +1,94 @@
1
+ // src/core/compose/features/position.ts
2
+
3
+ import { BaseComponent, ElementComponent } from '../component';
4
+
5
+ /**
6
+ * Available position values
7
+ */
8
+ export enum POSITIONS {
9
+ LEFT = 'left',
10
+ RIGHT = 'right',
11
+ TOP = 'top',
12
+ BOTTOM = 'bottom',
13
+ START = 'start',
14
+ END = 'end',
15
+ CENTER = 'center'
16
+ }
17
+
18
+ /**
19
+ * Configuration for position feature
20
+ */
21
+ export interface PositionConfig {
22
+ position?: string;
23
+ prefix?: string;
24
+ componentName?: string;
25
+ [key: string]: any;
26
+ }
27
+
28
+ /**
29
+ * Position manager interface
30
+ */
31
+ export interface PositionManager {
32
+ /**
33
+ * Sets the component's position
34
+ * @param newPosition - New position value
35
+ * @returns Position manager for chaining
36
+ */
37
+ setPosition: (newPosition: string) => PositionManager;
38
+
39
+ /**
40
+ * Gets the current position
41
+ * @returns Current position
42
+ */
43
+ getPosition: () => string;
44
+ }
45
+
46
+ /**
47
+ * Component with position capabilities
48
+ */
49
+ export interface PositionComponent extends BaseComponent {
50
+ position: PositionManager;
51
+ }
52
+
53
+ /**
54
+ * Adds positioning functionality to a component
55
+ *
56
+ * @param config - Configuration object containing position information
57
+ * @returns Function that enhances a component with position capabilities
58
+ */
59
+ export const withPosition = <T extends PositionConfig>(config: T) =>
60
+ <C extends ElementComponent>(component: C): C & PositionComponent => {
61
+ if (!config.position || !component.element) {
62
+ return component as C & PositionComponent;
63
+ }
64
+
65
+ // Get the position value, normalizing from enum if provided as uppercase
66
+ const position =
67
+ POSITIONS[config.position.toUpperCase() as keyof typeof POSITIONS] ||
68
+ config.position;
69
+
70
+ const className = `${config.prefix}-${config.componentName}--${position}`;
71
+ component.element.classList.add(className);
72
+
73
+ const positionManager: PositionManager = {
74
+ setPosition(newPosition: string) {
75
+ const oldPosition = position;
76
+ const oldClassName = `${config.prefix}-${config.componentName}--${oldPosition}`;
77
+ const newClassName = `${config.prefix}-${config.componentName}--${newPosition}`;
78
+
79
+ component.element.classList.remove(oldClassName);
80
+ component.element.classList.add(newClassName);
81
+
82
+ return this;
83
+ },
84
+
85
+ getPosition() {
86
+ return position;
87
+ }
88
+ };
89
+
90
+ return {
91
+ ...component,
92
+ position: positionManager
93
+ };
94
+ };
@@ -0,0 +1,55 @@
1
+ // src/core/compose/features/ripple.ts
2
+
3
+ import { createRipple, RippleController, RippleConfig } from '../../build/ripple';
4
+ import { BaseComponent, ElementComponent } from '../component';
5
+ import { LifecycleComponent } from './lifecycle';
6
+
7
+ /**
8
+ * Configuration for ripple feature
9
+ */
10
+ export interface RippleFeatureConfig {
11
+ ripple?: boolean;
12
+ rippleConfig?: RippleConfig;
13
+ [key: string]: any;
14
+ }
15
+
16
+ /**
17
+ * Component with ripple capabilities
18
+ */
19
+ export interface RippleComponent extends BaseComponent {
20
+ ripple: RippleController;
21
+ }
22
+
23
+ /**
24
+ * Adds ripple effect functionality to a component
25
+ *
26
+ * @param config - Configuration object
27
+ * @returns Function that enhances a component with ripple effect
28
+ */
29
+ export const withRipple = <T extends RippleFeatureConfig>(config: T) =>
30
+ <C extends ElementComponent & Partial<LifecycleComponent>>(component: C): C & RippleComponent => {
31
+ if (!config.ripple) return component as C & RippleComponent;
32
+
33
+ const rippleInstance = createRipple(config.rippleConfig);
34
+
35
+ // If component has lifecycle methods, integrate ripple with them
36
+ if (component.lifecycle) {
37
+ const originalMount = component.lifecycle.mount;
38
+ const originalDestroy = component.lifecycle.destroy;
39
+
40
+ component.lifecycle.mount = () => {
41
+ originalMount.call(component.lifecycle);
42
+ rippleInstance.mount(component.element);
43
+ };
44
+
45
+ component.lifecycle.destroy = () => {
46
+ rippleInstance.unmount(component.element);
47
+ originalDestroy.call(component.lifecycle);
48
+ };
49
+ }
50
+
51
+ return {
52
+ ...component,
53
+ ripple: rippleInstance
54
+ };
55
+ };
@@ -0,0 +1,29 @@
1
+ // src/core/compose/features/size.ts
2
+
3
+ import { BaseComponent, ElementComponent } from '../component';
4
+
5
+ /**
6
+ * Configuration for size feature
7
+ */
8
+ export interface SizeConfig {
9
+ size?: string;
10
+ prefix?: string;
11
+ componentName?: string;
12
+ [key: string]: any;
13
+ }
14
+
15
+ /**
16
+ * Adds a size class to a component
17
+ *
18
+ * @param config - Configuration object containing size information
19
+ * @returns Function that enhances a component with the size class
20
+ */
21
+ export const withSize = <T extends SizeConfig>(config: T) =>
22
+ <C extends ElementComponent>(component: C): C => {
23
+ if (config.size && component.element) {
24
+ // Use config.componentName since we know it's there
25
+ const className = `${config.prefix}-${config.componentName}--${config.size}`;
26
+ component.element.classList.add(className);
27
+ }
28
+ return component;
29
+ };
@@ -0,0 +1,31 @@
1
+ // src/core/compose/features/style.ts
2
+
3
+ import { ElementComponent } from '../component';
4
+
5
+ /**
6
+ * Configuration for style feature
7
+ */
8
+ export interface StyleConfig {
9
+ variant?: string;
10
+ size?: string;
11
+ [key: string]: any;
12
+ }
13
+
14
+ /**
15
+ * Adds style classes to a component based on configuration
16
+ *
17
+ * @param config - Configuration object containing style information
18
+ * @returns Function that enhances a component with style classes
19
+ */
20
+ export const withStyle = <T extends StyleConfig>(config: T = {} as T) =>
21
+ <C extends ElementComponent>(component: C): C => {
22
+ if (config.variant) {
23
+ component.element.classList.add(`${component.getClass('button')}--${config.variant}`);
24
+ }
25
+
26
+ if (config.size) {
27
+ component.element.classList.add(`${component.getClass('button')}--${config.size}`);
28
+ }
29
+
30
+ return component;
31
+ };
@@ -0,0 +1,44 @@
1
+ // src/core/compose/features/text.ts
2
+
3
+ import { createText, TextManager } from '../../build/text';
4
+ import { BaseComponent, ElementComponent } from '../component';
5
+
6
+ /**
7
+ * Configuration for text feature
8
+ */
9
+ export interface TextConfig {
10
+ text?: string;
11
+ prefix?: string;
12
+ componentName?: string;
13
+ [key: string]: any;
14
+ }
15
+
16
+ /**
17
+ * Component with text capabilities
18
+ */
19
+ export interface TextComponent extends BaseComponent {
20
+ text: TextManager;
21
+ }
22
+
23
+ /**
24
+ * Adds text management to a component
25
+ *
26
+ * @param config - Configuration object containing text information
27
+ * @returns Function that enhances a component with text capabilities
28
+ */
29
+ export const withText = <T extends TextConfig>(config: T) =>
30
+ <C extends ElementComponent>(component: C): C & TextComponent => {
31
+ const text = createText(component.element, {
32
+ prefix: config.prefix,
33
+ type: config.componentName || 'component'
34
+ });
35
+
36
+ if (config.text) {
37
+ text.setText(config.text);
38
+ }
39
+
40
+ return {
41
+ ...component,
42
+ text
43
+ };
44
+ };