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
@@ -1,225 +0,0 @@
1
- // src/core/compose/component.js
2
- /**
3
- * @module core/compose/component
4
- * @description Core utilities for component composition and creation with built-in mobile support
5
- */
6
-
7
- import { createElement } from '../dom/create'
8
- import {
9
- normalizeEvent,
10
- hasTouchSupport,
11
- TOUCH_CONFIG,
12
- PASSIVE_EVENTS
13
- } from '../utils/mobile'
14
-
15
- /**
16
- * Creates helper functions for managing CSS class names with a prefix
17
- * @param {string} prefix - Prefix to apply to class names
18
- * @returns {Object} Class name utilities
19
- * @property {Function} getClass - Gets a class name with prefix
20
- * @property {Function} getModifierClass - Gets a modifier class with prefix
21
- * @property {Function} getElementClass - Gets an element class with prefix
22
- * @example
23
- * const { getClass } = withPrefix('mtrl');
24
- * getClass('button'); // Returns 'mtrl-button'
25
- */
26
- const withPrefix = prefix => ({
27
- /**
28
- * Gets a prefixed class name
29
- * @param {string} name - Base class name
30
- * @returns {string} Prefixed class name
31
- */
32
- getClass: (name) => `${prefix}-${name}`,
33
- /**
34
- * Gets a prefixed modifier class name
35
- * @param {string} base - Base class name
36
- * @param {string} modifier - Modifier name
37
- * @returns {string} Prefixed modifier class
38
- */
39
- getModifierClass: (base, modifier) => `${base}--${modifier}`,
40
- /**
41
- * Gets a prefixed element class name
42
- * @param {string} base - Base class name
43
- * @param {string} element - Element name
44
- * @returns {string} Prefixed element class
45
- */
46
- getElementClass: (base, element) => `${base}-${element}`
47
- })
48
-
49
- /**
50
- * Creates a base component with configuration and prefix utilities.
51
- * This forms the foundation for all components in the system.
52
- *
53
- * @param {Object} config - Component configuration
54
- * @param {string} [config.prefix='mtrl'] - CSS class prefix
55
- * @param {string} [config.componentName] - Component name for class generation
56
- * @returns {Object} Base component with prefix utilities
57
- */
58
- export const createBase = (config = {}) => ({
59
- config,
60
- componentName: config.componentName,
61
- ...withPrefix(config.prefix || 'mtrl'),
62
-
63
- /**
64
- * Manages the touch interaction state for the component.
65
- * This helps track touch gestures and interactions.
66
- */
67
- touchState: {
68
- startTime: 0,
69
- startPosition: { x: 0, y: 0 },
70
- isTouching: false,
71
- activeTarget: null
72
- },
73
-
74
- /**
75
- * Updates the component's touch state based on user interactions.
76
- * Tracks touch position and timing for gesture recognition.
77
- */
78
- updateTouchState (event, status) {
79
- const normalized = normalizeEvent(event)
80
-
81
- if (status === 'start') {
82
- this.touchState = {
83
- startTime: Date.now(),
84
- startPosition: {
85
- x: normalized.clientX,
86
- y: normalized.clientY
87
- },
88
- isTouching: true,
89
- activeTarget: normalized.target
90
- }
91
- } else if (status === 'end') {
92
- this.touchState.isTouching = false
93
- this.touchState.activeTarget = null
94
- }
95
- }
96
- })
97
-
98
- /**
99
- * Higher-order function that adds a DOM element to a component
100
- * @param {Object} options - Element creation options
101
- * @param {string} [options.tag='div'] - HTML tag name
102
- * @param {string} [options.componentName] - Component name for class generation
103
- * @param {Object} [options.attrs] - HTML attributes
104
- * @param {string|string[]} [options.className] - Additional CSS classes
105
- * @param {Object} [options.forwardEvents] - Native events to forward to component events
106
- * @returns {Function} Component enhancer
107
- * @example
108
- * pipe(
109
- * createBase,
110
- * withElement({
111
- * tag: 'button',
112
- * componentName: 'button',
113
- * attrs: { type: 'button' },
114
- * forwardEvents: {
115
- * click: component => !component.element.disabled
116
- * }
117
- * })
118
- * )({ prefix: 'app' })
119
- */
120
- export const withElement = (options = {}) => (base) => {
121
- /**
122
- * Handles the start of a touch interaction.
123
- * Initializes touch tracking and provides visual feedback.
124
- */
125
- const handleTouchStart = (event) => {
126
- base.updateTouchState(event, 'start')
127
- element.classList.add(`${base.getClass('touch-active')}`)
128
-
129
- if (options.forwardEvents?.touchstart) {
130
- base.emit?.('touchstart', normalizeEvent(event))
131
- }
132
- }
133
-
134
- /**
135
- * Handles the end of a touch interaction.
136
- * Detects taps and cleans up touch state.
137
- */
138
- const handleTouchEnd = (event) => {
139
- if (!base.touchState.isTouching) return
140
-
141
- const touchDuration = Date.now() - base.touchState.startTime
142
- element.classList.remove(`${base.getClass('touch-active')}`)
143
- base.updateTouchState(event, 'end')
144
-
145
- // Emit tap event for short touches
146
- if (touchDuration < TOUCH_CONFIG.TAP_THRESHOLD) {
147
- base.emit?.('tap', normalizeEvent(event))
148
- }
149
-
150
- if (options.forwardEvents?.touchend) {
151
- base.emit?.('touchend', normalizeEvent(event))
152
- }
153
- }
154
-
155
- /**
156
- * Handles touch movement.
157
- * Detects swipes and other gesture-based interactions.
158
- */
159
- const handleTouchMove = (event) => {
160
- if (!base.touchState.isTouching) return
161
-
162
- const normalized = normalizeEvent(event)
163
- const deltaX = normalized.clientX - base.touchState.startPosition.x
164
- const deltaY = normalized.clientY - base.touchState.startPosition.y
165
-
166
- // Detect and emit swipe gestures
167
- if (Math.abs(deltaX) > TOUCH_CONFIG.SWIPE_THRESHOLD) {
168
- base.emit?.('swipe', {
169
- direction: deltaX > 0 ? 'right' : 'left',
170
- deltaX,
171
- deltaY
172
- })
173
- }
174
-
175
- if (options.forwardEvents?.touchmove) {
176
- base.emit?.('touchmove', { ...normalized, deltaX, deltaY })
177
- }
178
- }
179
-
180
- // Create the element with appropriate classes
181
- const element = createElement({
182
- ...options,
183
- className: [
184
- base.getClass(options.componentName || base.componentName || 'component'),
185
- hasTouchSupport() && options.interactive ? base.getClass('interactive') : null,
186
- options.className
187
- ].filter(Boolean),
188
- context: base
189
- })
190
-
191
- // Add event listeners only if touch is supported and the component is interactive
192
- if (hasTouchSupport() && options.interactive) {
193
- element.addEventListener('touchstart', handleTouchStart, PASSIVE_EVENTS)
194
- element.addEventListener('touchend', handleTouchEnd)
195
- element.addEventListener('touchmove', handleTouchMove, PASSIVE_EVENTS)
196
- }
197
-
198
- return {
199
- ...base,
200
- element,
201
-
202
- /**
203
- * Adds CSS classes to the element
204
- * @param {...string} classes - CSS classes to add
205
- * @returns {Object} Component instance for chaining
206
- */
207
- addClass (...classes) {
208
- element.classList.add(...classes.filter(Boolean))
209
- return this
210
- },
211
-
212
- /**
213
- * Removes the element and cleans up event listeners.
214
- * Ensures proper resource cleanup when the component is destroyed.
215
- */
216
- destroy () {
217
- if (hasTouchSupport() && options.interactive) {
218
- element.removeEventListener('touchstart', handleTouchStart)
219
- element.removeEventListener('touchend', handleTouchEnd)
220
- element.removeEventListener('touchmove', handleTouchMove)
221
- }
222
- element.remove()
223
- }
224
- }
225
- }
@@ -1,114 +0,0 @@
1
- // src/core/compose/features/checkable.js
2
-
3
- /**
4
- * Adds checked state management to a component with an input
5
- * Manages visual state and event emission for checked changes
6
- *
7
- * @param {Object} config - Checkable configuration
8
- * @param {boolean} [config.checked] - Initial checked state
9
- *
10
- * @returns {Function} Component transformer that adds checkable functionality
11
- *
12
- * @example
13
- * const component = pipe(
14
- * createBase,
15
- * withEvents(),
16
- * withInput(config),
17
- * withCheckable({ checked: true })
18
- * )(config);
19
- *
20
- * // Use the checkable API
21
- * component.checkable.toggle();
22
- * component.checkable.check();
23
- * component.checkable.uncheck();
24
- *
25
- * // Listen for changes
26
- * component.on('change', ({ checked }) => {
27
- * console.log('State changed:', checked);
28
- * });
29
- */
30
- export const withCheckable = (config = {}) => (component) => {
31
- if (!component.input) return component
32
-
33
- /**
34
- * Updates component classes to reflect checked state
35
- * @private
36
- */
37
- const updateStateClasses = () => {
38
- component.element.classList.toggle(
39
- `${component.getClass('switch')}--checked`,
40
- component.input.checked
41
- )
42
- }
43
-
44
- // Set initial state
45
- if (config.checked) {
46
- component.input.checked = true
47
- updateStateClasses()
48
- }
49
-
50
- // Update classes whenever checked state changes
51
- component.on('change', updateStateClasses)
52
-
53
- return {
54
- ...component,
55
- checkable: {
56
- /**
57
- * Sets the checked state to true
58
- * Emits change event if state changes
59
- * @returns {Object} Checkable interface
60
- */
61
- check () {
62
- if (!component.input.checked) {
63
- component.input.checked = true
64
- updateStateClasses()
65
- component.emit('change', {
66
- checked: true,
67
- value: component.input.value
68
- })
69
- }
70
- return this
71
- },
72
-
73
- /**
74
- * Sets the checked state to false
75
- * Emits change event if state changes
76
- * @returns {Object} Checkable interface
77
- */
78
- uncheck () {
79
- if (component.input.checked) {
80
- component.input.checked = false
81
- updateStateClasses()
82
- component.emit('change', {
83
- checked: false,
84
- value: component.input.value
85
- })
86
- }
87
- return this
88
- },
89
-
90
- /**
91
- * Toggles the current checked state
92
- * Always emits change event
93
- * @returns {Object} Checkable interface
94
- */
95
- toggle () {
96
- component.input.checked = !component.input.checked
97
- updateStateClasses()
98
- component.emit('change', {
99
- checked: component.input.checked,
100
- value: component.input.value
101
- })
102
- return this
103
- },
104
-
105
- /**
106
- * Gets the current checked state
107
- * @returns {boolean} Whether component is checked
108
- */
109
- isChecked () {
110
- return component.input.checked
111
- }
112
- }
113
- }
114
- }
@@ -1,64 +0,0 @@
1
- // src/core/compose/features/disabled.js
2
-
3
- /**
4
- * Adds disabled state management to a component
5
- * @param {Object} config - Disabled configuration
6
- * @returns {Function} Component enhancer
7
- */
8
- export const withDisabled = (config = {}) => (component) => {
9
- // Get the disabled class based on component name
10
- const disabledClass = `${component.getClass(component.componentName)}--disabled`
11
-
12
- // Directly implement disabled functionality
13
- const disabled = {
14
- enable () {
15
- component.element.classList.remove(disabledClass)
16
- if (component.input) {
17
- component.input.disabled = false
18
- component.input.removeAttribute('disabled')
19
- } else {
20
- component.element.disabled = false
21
- component.element.removeAttribute('disabled')
22
- }
23
- return this
24
- },
25
-
26
- disable () {
27
- component.element.classList.add(disabledClass)
28
- if (component.input) {
29
- component.input.disabled = true
30
- component.input.setAttribute('disabled', 'true')
31
- } else {
32
- component.element.disabled = true
33
- component.element.setAttribute('disabled', 'true')
34
- }
35
- return this
36
- },
37
-
38
- toggle () {
39
- if (this.isDisabled()) {
40
- this.enable()
41
- } else {
42
- this.disable()
43
- }
44
- return this
45
- },
46
-
47
- isDisabled () {
48
- return component.input ? component.input.disabled : component.element.disabled
49
- }
50
- }
51
-
52
- // Initialize disabled state if configured
53
- if (config.disabled) {
54
- // Use requestAnimationFrame to ensure DOM is ready
55
- requestAnimationFrame(() => {
56
- disabled.disable()
57
- })
58
- }
59
-
60
- return {
61
- ...component,
62
- disabled
63
- }
64
- }
@@ -1,48 +0,0 @@
1
- // src/core/compose/features/withEvents.js
2
- /**
3
- * @module core/compose/features
4
- */
5
-
6
- import { createEmitter } from '../../state/emitter'
7
-
8
- /**
9
- * Adds event handling capabilities to a component
10
- * @memberof module:core/compose/features
11
- * @function withEvents
12
- * @param {HTMLElement} [target] - Event target element
13
- * @returns {Function} Component transformer
14
- * @example
15
- * const button = pipe(
16
- * createBase({ componentName: 'button' }),
17
- * withElement(),
18
- * withEvents()
19
- * )({})
20
- *
21
- * button.on('click', () => console.log('clicked'))
22
- */
23
-
24
- /**
25
- * Adds event handling capabilities to a component
26
- * Returns event system ready to use immediately
27
- */
28
- export const withEvents = () => (component) => {
29
- const emitter = createEmitter()
30
-
31
- return {
32
- ...component,
33
- on (event, handler) {
34
- emitter.on(event, handler)
35
- return this
36
- },
37
-
38
- off (event, handler) {
39
- emitter.off(event, handler)
40
- return this
41
- },
42
-
43
- emit (event, data) {
44
- emitter.emit(event, data)
45
- return this
46
- }
47
- }
48
- }
@@ -1,33 +0,0 @@
1
- // src/core/compose/features/icon.js
2
- import { createIcon } from '../../../core/build/icon'
3
-
4
- const updateCircularStyle = (component, config) => {
5
- const hasText = config.text
6
- const hasIcon = config.icon
7
-
8
- const circularClass = `${component.getClass('button')}--circular`
9
- if (!hasText && hasIcon) {
10
- component.element.classList.add(circularClass)
11
- } else {
12
- component.element.classList.remove(circularClass)
13
- }
14
- }
15
-
16
- export const withIcon = (config = {}) => (component) => {
17
- const icon = createIcon(component.element, {
18
- prefix: config.prefix,
19
- type: 'button',
20
- position: config.iconPosition
21
- })
22
-
23
- if (config.icon) {
24
- icon.setIcon(config.icon)
25
- }
26
-
27
- updateCircularStyle(component, config)
28
-
29
- return {
30
- ...component,
31
- icon
32
- }
33
- }
@@ -1,20 +0,0 @@
1
- // src/core/compose/features/index.js
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 { withInput } from './input'
11
- export { withTrack } from './track'
12
- export { withTextInput } from './textinput'
13
- export { withTextLabel } from './textlabel'
14
- export { withRipple } from './ripple'
15
-
16
- // State management features
17
- export { withDisabled } from './disabled'
18
- export { withCheckable } from './checkable'
19
-
20
- export { withLifecycle } from './lifecycle'
@@ -1,100 +0,0 @@
1
- // src/core/compose/features/input.js
2
-
3
- /**
4
- * Creates an input element and adds it to a component
5
- * Handles both input creation and event emission for state changes
6
- *
7
- * @param {Object} config - Input configuration
8
- * @param {string} [config.name] - Input name attribute
9
- * @param {boolean} [config.checked] - Initial checked state
10
- * @param {boolean} [config.required] - Whether input is required
11
- * @param {boolean} [config.disabled] - Whether input is disabled
12
- * @param {string} [config.value='on'] - Input value attribute
13
- * @param {string} [config.label] - Accessibility label text
14
- * @param {string} [config.ariaLabel] - Alternative accessibility label
15
- *
16
- * @returns {Function} Component transformer that adds input functionality
17
- */
18
- export const withInput = (config = {}) => (component) => {
19
- const input = document.createElement('input')
20
- const name = component.componentName
21
- input.type = 'checkbox'
22
- input.className = `${component.getClass(name)}-input`
23
-
24
- // Ensure input can receive focus
25
- input.style.position = 'absolute'
26
- input.style.opacity = '0'
27
- input.style.cursor = 'pointer'
28
- // Don't use display: none or visibility: hidden as they prevent focus
29
-
30
- // The input itself should be focusable, not the wrapper
31
- component.element.setAttribute('role', 'presentation')
32
- input.setAttribute('role', name)
33
-
34
- const attributes = {
35
- name: config.name,
36
- checked: config.checked,
37
- required: config.required,
38
- disabled: config.disabled,
39
- value: config.value || 'on',
40
- 'aria-label': config.label || config.ariaLabel
41
- }
42
-
43
- Object.entries(attributes).forEach(([key, value]) => {
44
- if (value !== null && value !== undefined) {
45
- if (key === 'disabled' && value === true) {
46
- input.disabled = true
47
- input.setAttribute('disabled', 'true')
48
- // Note: We don't add the class here because that's handled by withDisabled
49
- } else if (value === true) {
50
- input.setAttribute(key, key)
51
- } else {
52
- input.setAttribute(key, value)
53
- }
54
- }
55
- })
56
-
57
- // Bridge native checkbox events to our event system
58
- input.addEventListener('change', (event) => {
59
- component.emit('change', {
60
- checked: input.checked,
61
- value: input.value,
62
- nativeEvent: event
63
- })
64
- })
65
-
66
- // Add keyboard handling
67
- input.addEventListener('keydown', (event) => {
68
- if (event.key === ' ' || event.key === 'Enter') {
69
- event.preventDefault()
70
- if (!input.disabled) {
71
- input.checked = !input.checked
72
- input.dispatchEvent(new Event('change', { bubbles: true }))
73
- }
74
- }
75
- })
76
-
77
- component.element.appendChild(input)
78
-
79
- return {
80
- ...component,
81
- input,
82
-
83
- /**
84
- * Gets the current input value
85
- * @returns {string} Current value
86
- */
87
- getValue: () => input.value,
88
-
89
- /**
90
- * Sets the input value and emits a value event
91
- * @param {string} value - New value to set
92
- * @returns {Object} Component instance
93
- */
94
- setValue (value) {
95
- input.value = value
96
- component.emit('value', { value })
97
- return this
98
- }
99
- }
100
- }
@@ -1,69 +0,0 @@
1
- // src/core/compose/features/withLifecycle.js
2
- import { createEmitter } from '../../state/emitter'
3
-
4
- export const withLifecycle = () => (component) => {
5
- if (!component.element) return component
6
-
7
- let mounted = false
8
- const emitter = createEmitter()
9
-
10
- return {
11
- ...component,
12
- lifecycle: {
13
- // Mount/Unmount state management
14
- onMount: (handler) => emitter.on('mount', handler),
15
- onUnmount: (handler) => emitter.on('unmount', handler),
16
-
17
- mount: () => {
18
- if (!mounted) {
19
- mounted = true
20
- emitter.emit('mount')
21
- }
22
- },
23
-
24
- unmount: () => {
25
- if (mounted) {
26
- mounted = false
27
- emitter.emit('unmount')
28
- emitter.clear()
29
- }
30
- },
31
-
32
- isMounted: () => mounted,
33
-
34
- // Cleanup and destruction
35
- destroy () {
36
- // First trigger unmount
37
- if (mounted) {
38
- this.unmount()
39
- }
40
-
41
- // Clean up all event listeners
42
- if (component.events) {
43
- component.events.destroy()
44
- }
45
-
46
- // Clean up text element
47
- if (component.text) {
48
- const textElement = component.text.getElement()
49
- if (textElement) {
50
- textElement.remove()
51
- }
52
- }
53
-
54
- // Clean up icon element
55
- if (component.icon) {
56
- const iconElement = component.icon.getElement()
57
- if (iconElement) {
58
- iconElement.remove()
59
- }
60
- }
61
-
62
- // Remove the main element
63
- if (component.element) {
64
- component.element.remove()
65
- }
66
- }
67
- }
68
- }
69
- }