mtrl 0.1.3 → 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 (224) 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/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} +3 -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/card/card.js +0 -102
  138. package/src/components/card/config.js +0 -16
  139. package/src/components/card/index.js +0 -7
  140. package/src/components/card/media.js +0 -56
  141. package/src/components/checkbox/api.js +0 -45
  142. package/src/components/checkbox/checkbox.js +0 -96
  143. package/src/components/checkbox/index.js +0 -2
  144. package/src/components/container/api.js +0 -42
  145. package/src/components/container/container.js +0 -45
  146. package/src/components/container/index.js +0 -2
  147. package/src/components/container/styles.scss +0 -66
  148. package/src/components/list/index.js +0 -2
  149. package/src/components/list/list-item.js +0 -147
  150. package/src/components/list/list.js +0 -267
  151. package/src/components/menu/api.js +0 -117
  152. package/src/components/menu/constants.js +0 -42
  153. package/src/components/menu/features/items-manager.js +0 -375
  154. package/src/components/menu/features/keyboard-navigation.js +0 -129
  155. package/src/components/menu/features/positioning.js +0 -125
  156. package/src/components/menu/index.js +0 -2
  157. package/src/components/menu/menu-item.js +0 -41
  158. package/src/components/menu/menu.js +0 -54
  159. package/src/components/navigation/api.js +0 -43
  160. package/src/components/navigation/index.js +0 -2
  161. package/src/components/navigation/nav-item.js +0 -137
  162. package/src/components/navigation/navigation.js +0 -55
  163. package/src/components/snackbar/api.js +0 -125
  164. package/src/components/snackbar/features.js +0 -69
  165. package/src/components/snackbar/index.js +0 -2
  166. package/src/components/snackbar/position.js +0 -63
  167. package/src/components/snackbar/queue.js +0 -74
  168. package/src/components/snackbar/snackbar.js +0 -70
  169. package/src/components/switch/api.js +0 -44
  170. package/src/components/switch/index.js +0 -2
  171. package/src/components/switch/switch.js +0 -71
  172. package/src/components/textfield/api.js +0 -49
  173. package/src/components/textfield/index.js +0 -2
  174. package/src/components/textfield/textfield.js +0 -68
  175. package/src/core/build/_ripple.scss +0 -79
  176. package/src/core/build/constants.js +0 -51
  177. package/src/core/build/icon.js +0 -78
  178. package/src/core/build/ripple.js +0 -159
  179. package/src/core/build/text.js +0 -54
  180. package/src/core/compose/base.js +0 -8
  181. package/src/core/compose/component.js +0 -225
  182. package/src/core/compose/features/checkable.js +0 -114
  183. package/src/core/compose/features/disabled.js +0 -64
  184. package/src/core/compose/features/events.js +0 -48
  185. package/src/core/compose/features/icon.js +0 -33
  186. package/src/core/compose/features/index.js +0 -20
  187. package/src/core/compose/features/input.js +0 -100
  188. package/src/core/compose/features/lifecycle.js +0 -69
  189. package/src/core/compose/features/position.js +0 -60
  190. package/src/core/compose/features/ripple.js +0 -32
  191. package/src/core/compose/features/size.js +0 -9
  192. package/src/core/compose/features/style.js +0 -12
  193. package/src/core/compose/features/text.js +0 -17
  194. package/src/core/compose/features/textinput.js +0 -114
  195. package/src/core/compose/features/textlabel.js +0 -28
  196. package/src/core/compose/features/track.js +0 -49
  197. package/src/core/compose/features/variant.js +0 -9
  198. package/src/core/compose/features/withEvents.js +0 -67
  199. package/src/core/compose/index.js +0 -16
  200. package/src/core/config.js +0 -140
  201. package/src/core/dom/classes.js +0 -70
  202. package/src/core/dom/create.js +0 -132
  203. package/src/core/dom/events.js +0 -175
  204. package/src/core/dom/index.js +0 -5
  205. package/src/core/dom/utils.js +0 -22
  206. package/src/core/index.js +0 -23
  207. package/src/core/state/disabled.js +0 -51
  208. package/src/core/state/emitter.js +0 -63
  209. package/src/core/state/events.js +0 -29
  210. package/src/core/state/index.js +0 -6
  211. package/src/core/state/lifecycle.js +0 -64
  212. package/src/core/state/store.js +0 -112
  213. package/src/core/utils/index.js +0 -39
  214. package/src/core/utils/object.js +0 -22
  215. package/src/core/utils/validate.js +0 -37
  216. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  217. /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
  218. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  219. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  220. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  221. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  222. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  223. /package/src/components/switch/{constants.js → constants.ts} +0 -0
  224. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -1,24 +1,35 @@
1
- // src/components/card/features.js
2
- import { PREFIX } from '../../core/config'
3
- import { createElement } from '../../core/dom/create'
1
+ // src/components/card/features.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { createElement } from '../../core/dom/create';
4
+ import { BaseComponent, CardComponent, LoadingFeature, ExpandableFeature, SwipeableFeature } from './types';
5
+
6
+ interface LoadingConfig {
7
+ initialState?: boolean;
8
+ }
9
+
10
+ interface ExpandableConfig {
11
+ initialExpanded?: boolean;
12
+ expandableContent?: HTMLElement;
13
+ }
14
+
15
+ interface SwipeableConfig {
16
+ onSwipeLeft?: (component: CardComponent) => void;
17
+ onSwipeRight?: (component: CardComponent) => void;
18
+ threshold?: number;
19
+ }
4
20
 
5
21
  /**
6
22
  * Higher-order function to add loading state to a card
7
- * @param {Object} config - Loading state configuration
8
- * @param {boolean} [config.initialState=false] - Initial loading state
23
+ * @param {LoadingConfig} config - Loading state configuration
9
24
  * @returns {Function} Card component enhancer
10
25
  */
11
- export const withLoading = (config = {}) => (component) => {
12
- const initialState = config.initialState || false
13
- let loadingElement = null
14
- let isLoading = initialState
26
+ export const withLoading = (config: LoadingConfig = {}) => (component: BaseComponent): BaseComponent & { loading: LoadingFeature } => {
27
+ const initialState = config.initialState || false;
28
+ let loadingElement: HTMLElement | null = null;
29
+ let isLoading = initialState;
15
30
 
16
- if (initialState) {
17
- setLoading(true)
18
- }
19
-
20
- function setLoading (loading) {
21
- isLoading = loading
31
+ function setLoading(loading: boolean): void {
32
+ isLoading = loading;
22
33
 
23
34
  if (loading && !loadingElement) {
24
35
  // Create and add loading overlay
@@ -26,45 +37,47 @@ export const withLoading = (config = {}) => (component) => {
26
37
  tag: 'div',
27
38
  className: `${PREFIX}-card-loading-overlay`,
28
39
  container: component.element
29
- })
40
+ });
30
41
 
31
42
  // Add spinner
32
43
  createElement({
33
44
  tag: 'div',
34
45
  className: `${PREFIX}-card-loading-spinner`,
35
46
  container: loadingElement
36
- })
47
+ });
37
48
 
38
- component.element.classList.add(`${PREFIX}-card--state-loading`)
49
+ component.element.classList.add(`${PREFIX}-card--state-loading`);
39
50
  } else if (!loading && loadingElement) {
40
51
  // Remove loading overlay
41
- loadingElement.remove()
42
- loadingElement = null
43
- component.element.classList.remove(`${PREFIX}-card--state-loading`)
52
+ loadingElement.remove();
53
+ loadingElement = null;
54
+ component.element.classList.remove(`${PREFIX}-card--state-loading`);
44
55
  }
45
56
  }
46
57
 
58
+ if (initialState) {
59
+ setLoading(true);
60
+ }
61
+
47
62
  return {
48
63
  ...component,
49
64
  loading: {
50
65
  isLoading: () => isLoading,
51
66
  setLoading
52
67
  }
53
- }
54
- }
68
+ };
69
+ };
55
70
 
56
71
  /**
57
72
  * Higher-order function to add expandable behavior to a card
58
- * @param {Object} config - Expandable configuration
59
- * @param {boolean} [config.initialExpanded=false] - Whether card is initially expanded
60
- * @param {HTMLElement} [config.expandableContent] - Content to show when expanded
73
+ * @param {ExpandableConfig} config - Expandable configuration
61
74
  * @returns {Function} Card component enhancer
62
75
  */
63
- export const withExpandable = (config = {}) => (component) => {
64
- const initialExpanded = config.initialExpanded || false
65
- let isExpanded = initialExpanded
66
- const expandableContent = config.expandableContent
67
- let expandButton = null
76
+ export const withExpandable = (config: ExpandableConfig = {}) => (component: BaseComponent): BaseComponent & { expandable: ExpandableFeature } => {
77
+ const initialExpanded = config.initialExpanded || false;
78
+ let isExpanded = initialExpanded;
79
+ const expandableContent = config.expandableContent;
80
+ let expandButton: HTMLButtonElement;
68
81
 
69
82
  // Create expand/collapse button
70
83
  expandButton = createElement({
@@ -74,61 +87,61 @@ export const withExpandable = (config = {}) => (component) => {
74
87
  'aria-expanded': isExpanded ? 'true' : 'false',
75
88
  'aria-label': isExpanded ? 'Collapse' : 'Expand'
76
89
  }
77
- })
90
+ }) as HTMLButtonElement;
78
91
 
79
92
  // Add to card as action if not already present
80
- const actionsContainer = component.element.querySelector(`.${PREFIX}-card-actions`)
93
+ const actionsContainer = component.element.querySelector(`.${PREFIX}-card-actions`);
81
94
  if (actionsContainer) {
82
- actionsContainer.appendChild(expandButton)
95
+ actionsContainer.appendChild(expandButton);
83
96
  } else {
84
97
  // Create actions container if not present
85
98
  const newActionsContainer = createElement({
86
99
  tag: 'div',
87
100
  className: `${PREFIX}-card-actions`,
88
101
  container: component.element
89
- })
90
- newActionsContainer.appendChild(expandButton)
102
+ });
103
+ newActionsContainer.appendChild(expandButton);
91
104
  }
92
105
 
93
106
  // Set initial state
94
107
  if (expandableContent) {
95
- expandableContent.classList.add(`${PREFIX}-card-expandable-content`)
108
+ expandableContent.classList.add(`${PREFIX}-card-expandable-content`);
96
109
  if (!initialExpanded) {
97
- expandableContent.style.display = 'none'
110
+ expandableContent.style.display = 'none';
98
111
  }
99
- component.element.appendChild(expandableContent)
100
- }
101
-
102
- // Toggle expanded state
103
- function toggleExpanded () {
104
- setExpanded(!isExpanded)
112
+ component.element.appendChild(expandableContent);
105
113
  }
106
114
 
107
115
  // Set expanded state
108
- function setExpanded (expanded) {
109
- isExpanded = expanded
116
+ function setExpanded(expanded: boolean): void {
117
+ isExpanded = expanded;
110
118
 
111
119
  if (expandableContent) {
112
- expandableContent.style.display = expanded ? 'block' : 'none'
120
+ expandableContent.style.display = expanded ? 'block' : 'none';
113
121
  }
114
122
 
115
- expandButton.setAttribute('aria-expanded', expanded ? 'true' : 'false')
116
- expandButton.setAttribute('aria-label', expanded ? 'Collapse' : 'Expand')
123
+ expandButton.setAttribute('aria-expanded', expanded ? 'true' : 'false');
124
+ expandButton.setAttribute('aria-label', expanded ? 'Collapse' : 'Expand');
117
125
 
118
126
  if (expanded) {
119
- component.element.classList.add(`${PREFIX}-card--expanded`)
127
+ component.element.classList.add(`${PREFIX}-card--expanded`);
120
128
  } else {
121
- component.element.classList.remove(`${PREFIX}-card--expanded`)
129
+ component.element.classList.remove(`${PREFIX}-card--expanded`);
122
130
  }
123
131
 
124
- component.emit('expandedChanged', { expanded })
132
+ component.emit?.('expandedChanged', { expanded });
133
+ }
134
+
135
+ // Toggle expanded state
136
+ function toggleExpanded(): void {
137
+ setExpanded(!isExpanded);
125
138
  }
126
139
 
127
140
  // Add click handler to toggle button
128
141
  expandButton.addEventListener('click', (e) => {
129
- e.stopPropagation()
130
- toggleExpanded()
131
- })
142
+ e.stopPropagation();
143
+ toggleExpanded();
144
+ });
132
145
 
133
146
  return {
134
147
  ...component,
@@ -137,82 +150,79 @@ export const withExpandable = (config = {}) => (component) => {
137
150
  setExpanded,
138
151
  toggleExpanded
139
152
  }
140
- }
141
- }
153
+ };
154
+ };
142
155
 
143
156
  /**
144
157
  * Higher-order function to add swipeable behavior to a card
145
- * @param {Object} config - Swipeable configuration
146
- * @param {Function} [config.onSwipeLeft] - Callback when card is swiped left
147
- * @param {Function} [config.onSwipeRight] - Callback when card is swiped right
148
- * @param {number} [config.threshold=100] - Swipe distance threshold to trigger action
158
+ * @param {SwipeableConfig} config - Swipeable configuration
149
159
  * @returns {Function} Card component enhancer
150
160
  */
151
- export const withSwipeable = (config = {}) => (component) => {
152
- const threshold = config.threshold || 100
153
- let startX = 0
154
- let currentX = 0
155
-
156
- function handleTouchStart (e) {
157
- startX = e.touches[0].clientX
158
- component.element.style.transition = 'none'
161
+ export const withSwipeable = (config: SwipeableConfig = {}) => (component: BaseComponent): BaseComponent & { swipeable: SwipeableFeature } => {
162
+ const threshold = config.threshold || 100;
163
+ let startX = 0;
164
+ let currentX = 0;
165
+
166
+ function handleTouchStart(e: TouchEvent): void {
167
+ startX = e.touches[0].clientX;
168
+ component.element.style.transition = 'none';
159
169
  }
160
170
 
161
- function handleTouchMove (e) {
162
- if (!startX) return
171
+ function handleTouchMove(e: TouchEvent): void {
172
+ if (!startX) return;
163
173
 
164
- currentX = e.touches[0].clientX
165
- const diffX = currentX - startX
174
+ currentX = e.touches[0].clientX;
175
+ const diffX = currentX - startX;
166
176
 
167
177
  // Apply transform to move card
168
- component.element.style.transform = `translateX(${diffX}px)`
178
+ component.element.style.transform = `translateX(${diffX}px)`;
169
179
  }
170
180
 
171
- function handleTouchEnd () {
172
- if (!startX) return
181
+ function handleTouchEnd(): void {
182
+ if (!startX) return;
173
183
 
174
- component.element.style.transition = 'transform 0.3s ease'
175
- const diffX = currentX - startX
184
+ component.element.style.transition = 'transform 0.3s ease';
185
+ const diffX = currentX - startX;
176
186
 
177
187
  if (Math.abs(diffX) >= threshold) {
178
188
  // Swipe threshold reached
179
189
  if (diffX > 0 && config.onSwipeRight) {
180
190
  // Swipe right
181
- component.element.style.transform = 'translateX(100%)'
182
- config.onSwipeRight(component)
191
+ component.element.style.transform = 'translateX(100%)';
192
+ config.onSwipeRight(component as CardComponent);
183
193
  } else if (diffX < 0 && config.onSwipeLeft) {
184
194
  // Swipe left
185
- component.element.style.transform = 'translateX(-100%)'
186
- config.onSwipeLeft(component)
195
+ component.element.style.transform = 'translateX(-100%)';
196
+ config.onSwipeLeft(component as CardComponent);
187
197
  } else {
188
198
  // Reset if no handler
189
- component.element.style.transform = 'translateX(0)'
199
+ component.element.style.transform = 'translateX(0)';
190
200
  }
191
201
  } else {
192
202
  // Reset if below threshold
193
- component.element.style.transform = 'translateX(0)'
203
+ component.element.style.transform = 'translateX(0)';
194
204
  }
195
205
 
196
- startX = 0
197
- currentX = 0
206
+ startX = 0;
207
+ currentX = 0;
198
208
  }
199
209
 
200
210
  // Add event listeners
201
- component.element.addEventListener('touchstart', handleTouchStart)
202
- component.element.addEventListener('touchmove', handleTouchMove)
203
- component.element.addEventListener('touchend', handleTouchEnd)
211
+ component.element.addEventListener('touchstart', handleTouchStart as EventListener);
212
+ component.element.addEventListener('touchmove', handleTouchMove as EventListener);
213
+ component.element.addEventListener('touchend', handleTouchEnd);
204
214
 
205
215
  // Add swipeable class
206
- component.element.classList.add(`${PREFIX}-card--swipeable`)
216
+ component.element.classList.add(`${PREFIX}-card--swipeable`);
207
217
 
208
218
  // Return enhanced component
209
219
  return {
210
220
  ...component,
211
221
  swipeable: {
212
222
  reset: () => {
213
- component.element.style.transition = 'transform 0.3s ease'
214
- component.element.style.transform = 'translateX(0)'
223
+ component.element.style.transition = 'transform 0.3s ease';
224
+ component.element.style.transform = 'translateX(0)';
215
225
  }
216
226
  }
217
- }
218
- }
227
+ };
228
+ };
@@ -1,25 +1,21 @@
1
- // src/components/card/header.js
2
- import { PREFIX } from '../../core/config'
3
- import { pipe } from '../../core/compose'
4
- import { createBase, withElement } from '../../core/compose/component'
5
- import { withText } from '../../core/compose/features'
6
- import { createElement } from '../../core/dom/create'
1
+ // src/components/card/header.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import { createElement } from '../../core/dom/create';
6
+ import { CardHeaderConfig } from './types';
7
7
 
8
8
  /**
9
9
  * Creates a card header component
10
- * @param {Object} config - Header configuration
11
- * @param {string} [config.title] - Title text
12
- * @param {string} [config.subtitle] - Subtitle text
13
- * @param {HTMLElement|string} [config.avatar] - Avatar element or HTML string
14
- * @param {HTMLElement|string} [config.action] - Action element or HTML string
10
+ * @param {CardHeaderConfig} config - Header configuration
15
11
  * @returns {HTMLElement} Card header element
16
12
  */
17
- export const createCardHeader = (config = {}) => {
13
+ export const createCardHeader = (config: CardHeaderConfig = {}): HTMLElement => {
18
14
  const baseConfig = {
19
15
  ...config,
20
16
  componentName: 'card-header',
21
17
  prefix: PREFIX
22
- }
18
+ };
23
19
 
24
20
  try {
25
21
  const header = pipe(
@@ -29,14 +25,14 @@ export const createCardHeader = (config = {}) => {
29
25
  componentName: 'card-header',
30
26
  className: config.class
31
27
  })
32
- )(baseConfig)
28
+ )(baseConfig);
33
29
 
34
30
  // Create text container
35
31
  const textContainer = createElement({
36
32
  tag: 'div',
37
33
  className: `${PREFIX}-card-header-text`,
38
34
  container: header.element
39
- })
35
+ });
40
36
 
41
37
  // Add title if provided
42
38
  if (config.title) {
@@ -45,7 +41,7 @@ export const createCardHeader = (config = {}) => {
45
41
  className: `${PREFIX}-card-header-title`,
46
42
  text: config.title,
47
43
  container: textContainer
48
- })
44
+ });
49
45
  }
50
46
 
51
47
  // Add subtitle if provided
@@ -55,7 +51,7 @@ export const createCardHeader = (config = {}) => {
55
51
  className: `${PREFIX}-card-header-subtitle`,
56
52
  text: config.subtitle,
57
53
  container: textContainer
58
- })
54
+ });
59
55
  }
60
56
 
61
57
  // Add avatar if provided
@@ -66,9 +62,9 @@ export const createCardHeader = (config = {}) => {
66
62
  className: `${PREFIX}-card-header-avatar`,
67
63
  html: config.avatar
68
64
  })
69
- : config.avatar
65
+ : config.avatar;
70
66
 
71
- header.element.insertBefore(avatarElement, header.element.firstChild)
67
+ header.element.insertBefore(avatarElement, header.element.firstChild);
72
68
  }
73
69
 
74
70
  // Add action if provided
@@ -79,14 +75,14 @@ export const createCardHeader = (config = {}) => {
79
75
  className: `${PREFIX}-card-header-action`,
80
76
  html: config.action
81
77
  })
82
- : config.action
78
+ : config.action;
83
79
 
84
- header.element.appendChild(actionElement)
80
+ header.element.appendChild(actionElement);
85
81
  }
86
82
 
87
- return header.element
83
+ return header.element;
88
84
  } catch (error) {
89
- console.error('Card header creation error:', error)
90
- throw new Error(`Failed to create card header: ${error.message}`)
85
+ console.error('Card header creation error:', error instanceof Error ? error.message : String(error));
86
+ throw new Error(`Failed to create card header: ${error instanceof Error ? error.message : String(error)}`);
91
87
  }
92
- }
88
+ };
@@ -0,0 +1,19 @@
1
+ // src/components/card/index.ts
2
+ export { default } from './card'
3
+ export { createCardContent } from './content'
4
+ export { createCardHeader } from './header'
5
+ export { createCardActions } from './actions'
6
+ export { createCardMedia } from './media'
7
+ export {
8
+ CardVariant,
9
+ CardElevation,
10
+ CardSchema,
11
+ CardHeaderConfig,
12
+ CardContentConfig,
13
+ CardActionsConfig,
14
+ CardMediaConfig,
15
+ CardComponent
16
+ } from './types'
17
+
18
+ // Export constants for backward compatibility
19
+ export { CARD_VARIANTS, CARD_ELEVATIONS, CARD_SCHEMA } from './constants'
@@ -0,0 +1,52 @@
1
+ // src/components/card/media.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import { CardMediaConfig } from './types';
6
+
7
+ /**
8
+ * Creates a card media component
9
+ * @param {CardMediaConfig} config - Media configuration
10
+ * @returns {HTMLElement} Card media element
11
+ */
12
+ export const createCardMedia = (config: CardMediaConfig = {}): HTMLElement => {
13
+ const baseConfig = {
14
+ ...config,
15
+ componentName: 'card-media',
16
+ prefix: PREFIX
17
+ };
18
+
19
+ try {
20
+ const media = pipe(
21
+ createBase,
22
+ withElement({
23
+ tag: 'div',
24
+ componentName: 'card-media',
25
+ className: [
26
+ config.class,
27
+ config.aspectRatio ? `${PREFIX}-card-media--${config.aspectRatio.replace(':', '-')}` : null,
28
+ config.contain ? `${PREFIX}-card-media--contain` : null
29
+ ]
30
+ })
31
+ )(baseConfig);
32
+
33
+ // If custom element is provided, use it
34
+ if (config.element instanceof HTMLElement) {
35
+ media.element.appendChild(config.element);
36
+ }
37
+
38
+ // Otherwise create an image if src is provided
39
+ else if (config.src) {
40
+ const img = document.createElement('img');
41
+ img.src = config.src;
42
+ if (config.alt) img.alt = config.alt;
43
+ img.className = `${PREFIX}-card-media-img`;
44
+ media.element.appendChild(img);
45
+ }
46
+
47
+ return media.element;
48
+ } catch (error) {
49
+ console.error('Card media creation error:', error instanceof Error ? error.message : String(error));
50
+ throw new Error(`Failed to create card media: ${error instanceof Error ? error.message : String(error)}`);
51
+ }
52
+ };
@@ -0,0 +1,174 @@
1
+ // src/components/card/types.ts
2
+
3
+ /**
4
+ * Card variant types following Material Design 3
5
+ */
6
+ export enum CardVariant {
7
+ ELEVATED = 'elevated',
8
+ FILLED = 'filled',
9
+ OUTLINED = 'outlined'
10
+ }
11
+
12
+ /**
13
+ * Card elevation levels
14
+ */
15
+ export enum CardElevation {
16
+ RESTING = 1,
17
+ HOVERED = 2,
18
+ DRAGGED = 4
19
+ }
20
+
21
+ /**
22
+ * Interface for card configuration
23
+ */
24
+ export interface CardSchema {
25
+ variant?: CardVariant;
26
+ interactive?: boolean;
27
+ fullWidth?: boolean;
28
+ clickable?: boolean;
29
+ draggable?: boolean;
30
+ class?: string;
31
+ headerConfig?: CardHeaderConfig;
32
+ contentConfig?: CardContentConfig;
33
+ actionsConfig?: CardActionsConfig;
34
+ mediaConfig?: CardMediaConfig;
35
+ }
36
+
37
+ /**
38
+ * Interface for card header configuration
39
+ */
40
+ export interface CardHeaderConfig {
41
+ title?: string;
42
+ subtitle?: string;
43
+ avatar?: HTMLElement | string;
44
+ action?: HTMLElement | string;
45
+ class?: string;
46
+ }
47
+
48
+ /**
49
+ * Interface for card content configuration
50
+ */
51
+ export interface CardContentConfig {
52
+ text?: string;
53
+ html?: string;
54
+ children?: HTMLElement[];
55
+ padding?: boolean;
56
+ class?: string;
57
+ }
58
+
59
+ /**
60
+ * Interface for card actions configuration
61
+ */
62
+ export interface CardActionsConfig {
63
+ actions?: HTMLElement[];
64
+ fullBleed?: boolean;
65
+ vertical?: boolean;
66
+ align?: 'start' | 'center' | 'end' | 'space-between';
67
+ class?: string;
68
+ }
69
+
70
+ /**
71
+ * Interface for card media configuration
72
+ */
73
+ export interface CardMediaConfig {
74
+ src?: string;
75
+ alt?: string;
76
+ element?: HTMLElement;
77
+ aspectRatio?: '16:9' | '4:3' | '1:1' | string;
78
+ contain?: boolean;
79
+ class?: string;
80
+ }
81
+
82
+ /**
83
+ * Base component interface
84
+ */
85
+ export interface BaseComponent {
86
+ element: HTMLElement;
87
+ getClass: (name?: string) => string;
88
+ getModifierClass: (base: string, modifier: string) => string;
89
+ getElementClass: (base: string, element: string) => string;
90
+ addClass: (...classes: string[]) => BaseComponent;
91
+ emit?: (event: string, data?: any) => void;
92
+ config: CardComponentConfig;
93
+ touchState?: TouchState;
94
+ updateTouchState?: (event: TouchEvent | MouseEvent, status: 'start' | 'end') => void;
95
+ lifecycle?: ComponentLifecycle;
96
+ }
97
+
98
+ /**
99
+ * Touch state interface
100
+ */
101
+ export interface TouchState {
102
+ startTime: number;
103
+ startPosition: { x: number; y: number };
104
+ isTouching: boolean;
105
+ activeTarget: EventTarget | null;
106
+ }
107
+
108
+ /**
109
+ * Component lifecycle interface
110
+ */
111
+ export interface ComponentLifecycle {
112
+ mount?: () => void;
113
+ update?: () => void;
114
+ destroy: () => void;
115
+ }
116
+
117
+ /**
118
+ * Card component configuration
119
+ */
120
+ export interface CardComponentConfig extends CardSchema {
121
+ componentName: string;
122
+ prefix: string;
123
+ }
124
+
125
+ /**
126
+ * Card component interface
127
+ */
128
+ export interface CardComponent extends BaseComponent {
129
+ // Card-specific methods
130
+ addContent: (contentElement: HTMLElement) => CardComponent;
131
+ setHeader: (headerElement: HTMLElement) => CardComponent;
132
+ addMedia: (mediaElement: HTMLElement, position?: 'top' | 'bottom') => CardComponent;
133
+ setActions: (actionsElement: HTMLElement) => CardComponent;
134
+ makeDraggable: (dragStartCallback?: (event: DragEvent) => void) => CardComponent;
135
+ destroy: () => void;
136
+
137
+ // Optional feature interfaces
138
+ loading?: LoadingFeature;
139
+ expandable?: ExpandableFeature;
140
+ swipeable?: SwipeableFeature;
141
+ }
142
+
143
+ /**
144
+ * Loading feature interface
145
+ */
146
+ export interface LoadingFeature {
147
+ isLoading: () => boolean;
148
+ setLoading: (loading: boolean) => void;
149
+ }
150
+
151
+ /**
152
+ * Expandable feature interface
153
+ */
154
+ export interface ExpandableFeature {
155
+ isExpanded: () => boolean;
156
+ setExpanded: (expanded: boolean) => void;
157
+ toggleExpanded: () => void;
158
+ }
159
+
160
+ /**
161
+ * Swipeable feature interface
162
+ */
163
+ export interface SwipeableFeature {
164
+ reset: () => void;
165
+ }
166
+
167
+ /**
168
+ * API options interface
169
+ */
170
+ export interface ApiOptions {
171
+ lifecycle: {
172
+ destroy: () => void;
173
+ };
174
+ }