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
@@ -1,4 +1,4 @@
1
- // src/components/card/styles.scss
1
+ // src/components/card/_card.scss
2
2
  @use '../../styles/abstract/base' as base;
3
3
  @use '../../styles/abstract/variables' as v;
4
4
  @use '../../styles/abstract/functions' as f;
@@ -17,9 +17,8 @@ $component: '#{base.$prefix}-card';
17
17
  background-color: t.color('surface');
18
18
  color: t.color('on-surface');
19
19
  overflow: hidden;
20
- // width: v.card('width');
21
- width: 340px;
22
- --card-elevation: m.elevation(2);
20
+ width: 320px; // Fixed width since v.card() isn't available
21
+ --card-elevation: 1;
23
22
 
24
23
  // Typography
25
24
  @include m.typography('body-medium');
@@ -50,10 +49,10 @@ $component: '#{base.$prefix}-card';
50
49
 
51
50
  // Elevated variant
52
51
  &--elevated {
53
- // @include m.elevation(m.elevation(2));
52
+ @include m.elevation(1);
54
53
 
55
- &:hover {
56
- --card-elevation: 2;
54
+ &:hover.#{$component}--interactive {
55
+ @include m.elevation(2);
57
56
  }
58
57
  }
59
58
 
@@ -284,4 +283,77 @@ $component: '#{base.$prefix}-card';
284
283
  &--state-loading {
285
284
  pointer-events: none;
286
285
  }
286
+
287
+ &--dragging {
288
+ @include m.elevation(4);
289
+ opacity: 0.9;
290
+ }
291
+
292
+ // Loading overlay
293
+ &-loading-overlay {
294
+ position: absolute;
295
+ top: 0;
296
+ left: 0;
297
+ width: 100%;
298
+ height: 100%;
299
+ display: flex;
300
+ align-items: center;
301
+ justify-content: center;
302
+ background-color: rgba(t.color('surface'), 0.7);
303
+ z-index: 1;
304
+ }
305
+
306
+ &-loading-spinner {
307
+ width: 40px;
308
+ height: 40px;
309
+ border-radius: 50%;
310
+ border: 3px solid rgba(t.color('primary'), 0.2);
311
+ border-top-color: t.color('primary');
312
+ animation: card-spinner 1s infinite linear;
313
+ }
314
+
315
+ // Expandable content
316
+ &-expandable-content {
317
+ overflow: hidden;
318
+ transition: max-height 0.3s ease;
319
+ }
320
+
321
+ &-expand-button {
322
+ background: none;
323
+ border: none;
324
+ padding: 8px;
325
+ cursor: pointer;
326
+ color: t.color('primary');
327
+
328
+ &::before {
329
+ content: '';
330
+ display: inline-block;
331
+ width: 10px;
332
+ height: 10px;
333
+ border-right: 2px solid currentColor;
334
+ border-bottom: 2px solid currentColor;
335
+ transform: rotate(45deg);
336
+ transition: transform 0.3s ease;
337
+ }
338
+
339
+ &[aria-expanded="true"]::before {
340
+ transform: rotate(-135deg);
341
+ }
342
+ }
343
+
344
+ // Swipeable card
345
+ &--swipeable {
346
+ touch-action: pan-y;
347
+ transition: transform 0.3s ease;
348
+ }
349
+ }
350
+
351
+ // Spinner animation
352
+ @keyframes card-spinner {
353
+ 0% {
354
+ transform: rotate(0deg);
355
+ }
356
+ 100% {
357
+ transform: rotate(360deg);
358
+ }
287
359
  }
@@ -1,23 +1,20 @@
1
- // src/components/card/actions.js
2
- import { PREFIX } from '../../core/config'
3
- import { pipe } from '../../core/compose'
4
- import { createBase, withElement } from '../../core/compose/component'
1
+ // src/components/card/actions.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import { CardActionsConfig } from './types';
5
6
 
6
7
  /**
7
8
  * Creates a card actions component
8
- * @param {Object} config - Actions configuration
9
- * @param {Array<HTMLElement>} [config.actions] - Action elements to include
10
- * @param {boolean} [config.fullBleed=false] - Whether actions extend full width
11
- * @param {boolean} [config.vertical=false] - Whether to stack actions vertically
12
- * @param {string} [config.align='start'] - Horizontal alignment ('start', 'center', 'end', 'space-between')
9
+ * @param {CardActionsConfig} config - Actions configuration
13
10
  * @returns {HTMLElement} Card actions element
14
11
  */
15
- export const createCardActions = (config = {}) => {
12
+ export const createCardActions = (config: CardActionsConfig = {}): HTMLElement => {
16
13
  const baseConfig = {
17
14
  ...config,
18
15
  componentName: 'card-actions',
19
16
  prefix: PREFIX
20
- }
17
+ };
21
18
 
22
19
  try {
23
20
  const actions = pipe(
@@ -32,20 +29,20 @@ export const createCardActions = (config = {}) => {
32
29
  config.align ? `${PREFIX}-card-actions--${config.align}` : null
33
30
  ]
34
31
  })
35
- )(baseConfig)
32
+ )(baseConfig);
36
33
 
37
34
  // Add action elements if provided
38
35
  if (Array.isArray(config.actions)) {
39
36
  config.actions.forEach(action => {
40
37
  if (action instanceof HTMLElement) {
41
- actions.element.appendChild(action)
38
+ actions.element.appendChild(action);
42
39
  }
43
- })
40
+ });
44
41
  }
45
42
 
46
- return actions.element
43
+ return actions.element;
47
44
  } catch (error) {
48
- console.error('Card actions creation error:', error)
49
- throw new Error(`Failed to create card actions: ${error.message}`)
45
+ console.error('Card actions creation error:', error instanceof Error ? error.message : String(error));
46
+ throw new Error(`Failed to create card actions: ${error instanceof Error ? error.message : String(error)}`);
50
47
  }
51
- }
48
+ };
@@ -1,102 +1,102 @@
1
- // src/components/card/api.js
1
+ // src/components/card/api.ts
2
+ import { BaseComponent, CardComponent, ApiOptions } from './types';
2
3
 
3
4
  /**
4
5
  * Enhances a card component with API methods
5
- * @param {Object} options - API configuration options
6
- * @param {Object} options.lifecycle - Object containing lifecycle methods
6
+ * @param {ApiOptions} options - API configuration options
7
7
  * @returns {Function} Higher-order function that adds API methods to component
8
8
  * @internal This is an internal utility for the Card component
9
9
  */
10
- export const withAPI = ({ lifecycle }) => (component) => ({
10
+ export const withAPI = ({ lifecycle }: ApiOptions) => (component: BaseComponent): CardComponent => ({
11
11
  ...component,
12
12
  element: component.element,
13
13
 
14
14
  /**
15
15
  * Adds content to the card
16
16
  * @param {HTMLElement} contentElement - The content element to add
17
- * @returns {Object} The card instance for chaining
17
+ * @returns {CardComponent} The card instance for chaining
18
18
  */
19
- addContent (contentElement) {
19
+ addContent(contentElement: HTMLElement): CardComponent {
20
20
  if (contentElement && contentElement.classList.contains(`${component.getClass('card')}-content`)) {
21
- component.element.appendChild(contentElement)
21
+ component.element.appendChild(contentElement);
22
22
  }
23
- return this
23
+ return this;
24
24
  },
25
25
 
26
26
  /**
27
27
  * Sets the card header
28
28
  * @param {HTMLElement} headerElement - The header element to add
29
- * @returns {Object} The card instance for chaining
29
+ * @returns {CardComponent} The card instance for chaining
30
30
  */
31
- setHeader (headerElement) {
31
+ setHeader(headerElement: HTMLElement): CardComponent {
32
32
  if (headerElement && headerElement.classList.contains(`${component.getClass('card')}-header`)) {
33
33
  // Remove existing header if present
34
- const existingHeader = component.element.querySelector(`.${component.getClass('card')}-header`)
34
+ const existingHeader = component.element.querySelector(`.${component.getClass('card')}-header`);
35
35
  if (existingHeader) {
36
- existingHeader.remove()
36
+ existingHeader.remove();
37
37
  }
38
38
 
39
39
  // Insert at the beginning of the card
40
- component.element.insertBefore(headerElement, component.element.firstChild)
40
+ component.element.insertBefore(headerElement, component.element.firstChild);
41
41
  }
42
- return this
42
+ return this;
43
43
  },
44
44
 
45
45
  /**
46
46
  * Adds media to the card
47
47
  * @param {HTMLElement} mediaElement - The media element to add
48
48
  * @param {string} [position='top'] - Position to place media ('top', 'bottom')
49
- * @returns {Object} The card instance for chaining
49
+ * @returns {CardComponent} The card instance for chaining
50
50
  */
51
- addMedia (mediaElement, position = 'top') {
51
+ addMedia(mediaElement: HTMLElement, position: 'top' | 'bottom' = 'top'): CardComponent {
52
52
  if (mediaElement && mediaElement.classList.contains(`${component.getClass('card')}-media`)) {
53
53
  if (position === 'top') {
54
- component.element.insertBefore(mediaElement, component.element.firstChild)
54
+ component.element.insertBefore(mediaElement, component.element.firstChild);
55
55
  } else {
56
- component.element.appendChild(mediaElement)
56
+ component.element.appendChild(mediaElement);
57
57
  }
58
58
  }
59
- return this
59
+ return this;
60
60
  },
61
61
 
62
62
  /**
63
63
  * Sets the card actions section
64
64
  * @param {HTMLElement} actionsElement - The actions element to add
65
- * @returns {Object} The card instance for chaining
65
+ * @returns {CardComponent} The card instance for chaining
66
66
  */
67
- setActions (actionsElement) {
67
+ setActions(actionsElement: HTMLElement): CardComponent {
68
68
  if (actionsElement && actionsElement.classList.contains(`${component.getClass('card')}-actions`)) {
69
69
  // Remove existing actions if present
70
- const existingActions = component.element.querySelector(`.${component.getClass('card')}-actions`)
70
+ const existingActions = component.element.querySelector(`.${component.getClass('card')}-actions`);
71
71
  if (existingActions) {
72
- existingActions.remove()
72
+ existingActions.remove();
73
73
  }
74
74
 
75
75
  // Add actions at the end
76
- component.element.appendChild(actionsElement)
76
+ component.element.appendChild(actionsElement);
77
77
  }
78
- return this
78
+ return this;
79
79
  },
80
80
 
81
81
  /**
82
82
  * Makes the card draggable
83
83
  * @param {Function} [dragStartCallback] - Callback for drag start event
84
- * @returns {Object} The card instance for chaining
84
+ * @returns {CardComponent} The card instance for chaining
85
85
  */
86
- makeDraggable (dragStartCallback) {
87
- component.element.setAttribute('draggable', 'true')
86
+ makeDraggable(dragStartCallback?: (event: DragEvent) => void): CardComponent {
87
+ component.element.setAttribute('draggable', 'true');
88
88
 
89
89
  if (typeof dragStartCallback === 'function') {
90
- component.element.addEventListener('dragstart', dragStartCallback)
90
+ component.element.addEventListener('dragstart', dragStartCallback as EventListener);
91
91
  }
92
92
 
93
- return this
93
+ return this;
94
94
  },
95
95
 
96
96
  /**
97
97
  * Destroys the card component and removes event listeners
98
98
  */
99
- destroy () {
100
- lifecycle.destroy()
99
+ destroy(): void {
100
+ lifecycle.destroy();
101
101
  }
102
- })
102
+ });
@@ -0,0 +1,41 @@
1
+ // src/components/card/card.ts
2
+ import { pipe } from '../../core/compose';
3
+ import { createBase, withElement } from '../../core/compose/component';
4
+ import {
5
+ withEvents,
6
+ withVariant,
7
+ withRipple,
8
+ withLifecycle
9
+ } from '../../core/compose/features';
10
+ import { withAPI } from './api';
11
+ import { CardComponent, BaseComponent, CardSchema } from './types';
12
+ import { createBaseConfig, getElementConfig, getApiConfig, withInteractiveBehavior } from './config';
13
+
14
+ /**
15
+ * Creates a new Card component following Material Design 3 principles
16
+ * @param {CardSchema} config - Card configuration object
17
+ * @returns {CardComponent} Card component instance
18
+ */
19
+ const createCard = (config: CardSchema = {}): CardComponent => {
20
+ const baseConfig = createBaseConfig(config);
21
+
22
+ try {
23
+ const card = pipe(
24
+ createBase,
25
+ withEvents(),
26
+ withElement(getElementConfig(baseConfig)),
27
+ withVariant(baseConfig),
28
+ config.clickable ? withRipple(baseConfig) : (c: BaseComponent) => c,
29
+ withLifecycle(),
30
+ withInteractiveBehavior,
31
+ comp => withAPI(getApiConfig(comp))(comp)
32
+ )(baseConfig);
33
+
34
+ return card as CardComponent;
35
+ } catch (error) {
36
+ console.error('Card creation error:', error instanceof Error ? error.message : String(error));
37
+ throw new Error(`Failed to create card: ${error instanceof Error ? error.message : String(error)}`);
38
+ }
39
+ };
40
+
41
+ export default createCard;
@@ -0,0 +1,99 @@
1
+ // src/components/card/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig,
5
+ BaseComponentConfig
6
+ } from '../../core/config/component-config';
7
+ import { BaseComponent, CardSchema } from './types';
8
+ import { CARD_VARIANTS, CARD_ELEVATIONS } from './constants';
9
+
10
+ /**
11
+ * Default configuration for the Card component
12
+ */
13
+ export const defaultConfig: CardSchema = {
14
+ variant: CARD_VARIANTS.ELEVATED,
15
+ interactive: false,
16
+ fullWidth: false,
17
+ clickable: false,
18
+ draggable: false
19
+ };
20
+
21
+ /**
22
+ * Creates the base configuration for Card component
23
+ * @param {CardSchema} config - User provided configuration
24
+ * @returns {CardSchema} Complete configuration with defaults applied
25
+ */
26
+ export const createBaseConfig = (config: CardSchema = {}): CardSchema =>
27
+ createComponentConfig(defaultConfig, config, 'card') as CardSchema;
28
+
29
+ /**
30
+ * Generates element configuration for the Card component
31
+ * @param {CardSchema} config - Card configuration
32
+ * @returns {Object} Element configuration object for withElement
33
+ */
34
+ export const getElementConfig = (config: CardSchema) =>
35
+ createElementConfig(config, {
36
+ tag: 'div',
37
+ className: [
38
+ config.class,
39
+ config.fullWidth ? `${config.prefix}-card--full-width` : null,
40
+ config.interactive ? `${config.prefix}-card--interactive` : null
41
+ ],
42
+ forwardEvents: {
43
+ click: (component: BaseComponent) => !!config.clickable,
44
+ mouseenter: (component: BaseComponent) => !!config.interactive,
45
+ mouseleave: (component: BaseComponent) => !!config.interactive
46
+ },
47
+ interactive: config.interactive || config.clickable
48
+ });
49
+
50
+ /**
51
+ * Creates API configuration for the Card component
52
+ * @param {Object} comp - Component with lifecycle feature
53
+ * @returns {Object} API configuration object
54
+ */
55
+ export const getApiConfig = (comp) => ({
56
+ lifecycle: {
57
+ destroy: () => comp.lifecycle?.destroy?.()
58
+ }
59
+ });
60
+
61
+ /**
62
+ * Adds interactive behavior to card component
63
+ * @param {BaseComponent} comp - Card component
64
+ * @returns {BaseComponent} Enhanced card component
65
+ */
66
+ export const withInteractiveBehavior = (comp: BaseComponent): BaseComponent => {
67
+ // Implement hover state elevation changes for interactive cards
68
+ if (comp.config.interactive) {
69
+ comp.element.addEventListener('mouseenter', () => {
70
+ if (comp.config.variant === CARD_VARIANTS.ELEVATED) {
71
+ comp.element.style.setProperty('--card-elevation', String(CARD_ELEVATIONS.HOVERED));
72
+ }
73
+ });
74
+
75
+ comp.element.addEventListener('mouseleave', () => {
76
+ if (comp.config.variant === CARD_VARIANTS.ELEVATED) {
77
+ comp.element.style.setProperty('--card-elevation', String(CARD_ELEVATIONS.RESTING));
78
+ }
79
+ });
80
+ }
81
+
82
+ // Set up draggable
83
+ if (comp.config.draggable) {
84
+ comp.element.setAttribute('draggable', 'true');
85
+ comp.element.addEventListener('dragstart', (e) => {
86
+ comp.element.style.setProperty('--card-elevation', String(CARD_ELEVATIONS.DRAGGED));
87
+ comp.emit?.('dragstart', { event: e });
88
+ });
89
+
90
+ comp.element.addEventListener('dragend', (e) => {
91
+ comp.element.style.setProperty('--card-elevation', String(CARD_ELEVATIONS.RESTING));
92
+ comp.emit?.('dragend', { event: e });
93
+ });
94
+ }
95
+
96
+ return comp;
97
+ };
98
+
99
+ export default defaultConfig;
@@ -1,24 +1,25 @@
1
- // src/components/card/constants.js
1
+ // src/components/card/constants.ts
2
+ import { CardVariant, CardElevation } from './types';
2
3
 
3
4
  /**
4
5
  * Card variant types following Material Design 3
5
6
  * @enum {string}
6
7
  */
7
8
  export const CARD_VARIANTS = {
8
- ELEVATED: 'elevated',
9
- FILLED: 'filled',
10
- OUTLINED: 'outlined'
11
- }
9
+ ELEVATED: CardVariant.ELEVATED,
10
+ FILLED: CardVariant.FILLED,
11
+ OUTLINED: CardVariant.OUTLINED
12
+ };
12
13
 
13
14
  /**
14
15
  * Card elevation levels
15
16
  * @enum {number}
16
17
  */
17
18
  export const CARD_ELEVATIONS = {
18
- RESTING: 1,
19
- HOVERED: 2,
20
- DRAGGED: 4
21
- }
19
+ RESTING: CardElevation.RESTING,
20
+ HOVERED: CardElevation.HOVERED,
21
+ DRAGGED: CardElevation.DRAGGED
22
+ };
22
23
 
23
24
  /**
24
25
  * Validation schema for card configuration
@@ -65,4 +66,4 @@ export const CARD_SCHEMA = {
65
66
  type: 'object',
66
67
  required: false
67
68
  }
68
- }
69
+ };
@@ -1,23 +1,20 @@
1
- // src/components/card/content.js
2
- import { PREFIX } from '../../core/config'
3
- import { pipe } from '../../core/compose'
4
- import { createBase, withElement } from '../../core/compose/component'
1
+ // src/components/card/content.ts
2
+ import { PREFIX } from '../../core/config';
3
+ import { pipe } from '../../core/compose';
4
+ import { createBase, withElement } from '../../core/compose/component';
5
+ import { CardContentConfig } from './types';
5
6
 
6
7
  /**
7
8
  * Creates a card content component
8
- * @param {Object} config - Content configuration
9
- * @param {string} [config.text] - Text content
10
- * @param {string} [config.html] - HTML content
11
- * @param {Array<HTMLElement>} [config.children] - Child elements to append
12
- * @param {boolean} [config.padding=true] - Whether to apply default padding
9
+ * @param {CardContentConfig} config - Content configuration
13
10
  * @returns {HTMLElement} Card content element
14
11
  */
15
- export const createCardContent = (config = {}) => {
12
+ export const createCardContent = (config: CardContentConfig = {}): HTMLElement => {
16
13
  const baseConfig = {
17
14
  ...config,
18
15
  componentName: 'card-content',
19
16
  prefix: PREFIX
20
- }
17
+ };
21
18
 
22
19
  try {
23
20
  const content = pipe(
@@ -32,20 +29,20 @@ export const createCardContent = (config = {}) => {
32
29
  html: config.html,
33
30
  text: config.text
34
31
  })
35
- )(baseConfig)
32
+ )(baseConfig);
36
33
 
37
34
  // Add children if provided
38
35
  if (Array.isArray(config.children)) {
39
36
  config.children.forEach(child => {
40
37
  if (child instanceof HTMLElement) {
41
- content.element.appendChild(child)
38
+ content.element.appendChild(child);
42
39
  }
43
- })
40
+ });
44
41
  }
45
42
 
46
- return content.element
43
+ return content.element;
47
44
  } catch (error) {
48
- console.error('Card content creation error:', error)
49
- throw new Error(`Failed to create card content: ${error.message}`)
45
+ console.error('Card content creation error:', error instanceof Error ? error.message : String(error));
46
+ throw new Error(`Failed to create card content: ${error instanceof Error ? error.message : String(error)}`);
50
47
  }
51
- }
48
+ };