mtrl 0.1.3 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/README.md +70 -22
  2. package/index.ts +33 -0
  3. package/package.json +14 -5
  4. package/src/components/button/{styles.scss → _styles.scss} +2 -2
  5. package/src/components/button/api.ts +89 -0
  6. package/src/components/button/button.ts +50 -0
  7. package/src/components/button/config.ts +75 -0
  8. package/src/components/button/constants.ts +17 -0
  9. package/src/components/button/index.ts +4 -0
  10. package/src/components/button/types.ts +118 -0
  11. package/src/components/card/{styles.scss → _styles.scss} +79 -7
  12. package/src/components/card/{actions.js → actions.ts} +15 -18
  13. package/src/components/card/{api.js → api.ts} +33 -33
  14. package/src/components/card/card.ts +41 -0
  15. package/src/components/card/config.ts +99 -0
  16. package/src/components/card/{constants.js → constants.ts} +11 -10
  17. package/src/components/card/{content.js → content.ts} +15 -18
  18. package/src/components/card/{features.js → features.ts} +104 -94
  19. package/src/components/card/{header.js → header.ts} +21 -25
  20. package/src/components/card/index.ts +19 -0
  21. package/src/components/card/media.ts +52 -0
  22. package/src/components/card/types.ts +174 -0
  23. package/src/components/checkbox/api.ts +82 -0
  24. package/src/components/checkbox/checkbox.ts +75 -0
  25. package/src/components/checkbox/config.ts +90 -0
  26. package/src/components/checkbox/constants.ts +37 -0
  27. package/src/components/checkbox/index.ts +4 -0
  28. package/src/components/checkbox/types.ts +146 -0
  29. package/src/components/chip/_styles.scss +372 -0
  30. package/src/components/chip/api.ts +115 -0
  31. package/src/components/chip/chip-set.ts +225 -0
  32. package/src/components/chip/chip.ts +82 -0
  33. package/src/components/chip/config.ts +92 -0
  34. package/src/components/chip/constants.ts +38 -0
  35. package/src/components/chip/index.ts +4 -0
  36. package/src/components/chip/types.ts +172 -0
  37. package/src/components/list/api.ts +72 -0
  38. package/src/components/list/config.ts +43 -0
  39. package/src/components/list/{constants.js → constants.ts} +34 -7
  40. package/src/components/list/features.ts +224 -0
  41. package/src/components/list/index.ts +14 -0
  42. package/src/components/list/list-item.ts +120 -0
  43. package/src/components/list/list.ts +37 -0
  44. package/src/components/list/types.ts +179 -0
  45. package/src/components/list/utils.ts +47 -0
  46. package/src/components/menu/api.ts +119 -0
  47. package/src/components/menu/config.ts +54 -0
  48. package/src/components/menu/constants.ts +154 -0
  49. package/src/components/menu/features/items-manager.ts +457 -0
  50. package/src/components/menu/features/keyboard-navigation.ts +133 -0
  51. package/src/components/menu/features/positioning.ts +127 -0
  52. package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
  53. package/src/components/menu/index.ts +14 -0
  54. package/src/components/menu/menu-item.ts +43 -0
  55. package/src/components/menu/menu.ts +53 -0
  56. package/src/components/menu/types.ts +178 -0
  57. package/src/components/navigation/api.ts +79 -0
  58. package/src/components/navigation/config.ts +61 -0
  59. package/src/components/navigation/{constants.js → constants.ts} +10 -10
  60. package/src/components/navigation/index.ts +14 -0
  61. package/src/components/navigation/nav-item.ts +148 -0
  62. package/src/components/navigation/navigation.ts +50 -0
  63. package/src/components/navigation/types.ts +212 -0
  64. package/src/components/progress/_styles.scss +204 -0
  65. package/src/components/progress/api.ts +179 -0
  66. package/src/components/progress/config.ts +124 -0
  67. package/src/components/progress/constants.ts +43 -0
  68. package/src/components/progress/index.ts +5 -0
  69. package/src/components/progress/progress.ts +163 -0
  70. package/src/components/progress/types.ts +102 -0
  71. package/src/components/snackbar/api.ts +162 -0
  72. package/src/components/snackbar/config.ts +62 -0
  73. package/src/components/snackbar/{constants.js → constants.ts} +21 -4
  74. package/src/components/snackbar/features.ts +76 -0
  75. package/src/components/snackbar/index.ts +4 -0
  76. package/src/components/snackbar/position.ts +71 -0
  77. package/src/components/snackbar/queue.ts +76 -0
  78. package/src/components/snackbar/snackbar.ts +60 -0
  79. package/src/components/snackbar/types.ts +58 -0
  80. package/src/components/switch/api.ts +77 -0
  81. package/src/components/switch/config.ts +74 -0
  82. package/src/components/switch/{constants.js → constants.ts} +5 -5
  83. package/src/components/switch/index.ts +4 -0
  84. package/src/components/switch/switch.ts +52 -0
  85. package/src/components/switch/types.ts +142 -0
  86. package/src/components/textfield/api.ts +72 -0
  87. package/src/components/textfield/config.ts +54 -0
  88. package/src/components/textfield/{constants.js → constants.ts} +38 -5
  89. package/src/components/textfield/index.ts +4 -0
  90. package/src/components/textfield/textfield.ts +50 -0
  91. package/src/components/textfield/types.ts +139 -0
  92. package/src/core/compose/base.ts +43 -0
  93. package/src/core/compose/component.ts +255 -0
  94. package/src/core/compose/features/checkable.ts +155 -0
  95. package/src/core/compose/features/disabled.ts +116 -0
  96. package/src/core/compose/features/events.ts +65 -0
  97. package/src/core/compose/features/icon.ts +67 -0
  98. package/src/core/compose/features/index.ts +35 -0
  99. package/src/core/compose/features/input.ts +174 -0
  100. package/src/core/compose/features/lifecycle.ts +139 -0
  101. package/src/core/compose/features/position.ts +94 -0
  102. package/src/core/compose/features/ripple.ts +55 -0
  103. package/src/core/compose/features/size.ts +29 -0
  104. package/src/core/compose/features/style.ts +31 -0
  105. package/src/core/compose/features/text.ts +44 -0
  106. package/src/core/compose/features/textinput.ts +225 -0
  107. package/src/core/compose/features/textlabel.ts +92 -0
  108. package/src/core/compose/features/track.ts +84 -0
  109. package/src/core/compose/features/variant.ts +29 -0
  110. package/src/core/compose/features/withEvents.ts +137 -0
  111. package/src/core/compose/index.ts +54 -0
  112. package/src/core/compose/{pipe.js → pipe.ts} +16 -11
  113. package/src/core/config/component-config.ts +136 -0
  114. package/src/core/config.ts +211 -0
  115. package/src/core/dom/{attributes.js → attributes.ts} +11 -11
  116. package/src/core/dom/classes.ts +60 -0
  117. package/src/core/dom/create.ts +251 -0
  118. package/src/core/dom/events.ts +209 -0
  119. package/src/core/dom/index.ts +10 -0
  120. package/src/core/dom/utils.ts +97 -0
  121. package/src/core/index.ts +111 -0
  122. package/src/core/state/disabled.ts +81 -0
  123. package/src/core/state/emitter.ts +94 -0
  124. package/src/core/state/events.ts +88 -0
  125. package/src/core/state/index.ts +16 -0
  126. package/src/core/state/lifecycle.ts +131 -0
  127. package/src/core/state/store.ts +197 -0
  128. package/src/core/utils/index.ts +45 -0
  129. package/src/core/utils/{mobile.js → mobile.ts} +48 -24
  130. package/src/core/utils/object.ts +41 -0
  131. package/src/core/utils/validate.ts +234 -0
  132. package/src/{index.js → index.ts} +3 -2
  133. package/index.js +0 -11
  134. package/src/components/button/api.js +0 -54
  135. package/src/components/button/button.js +0 -81
  136. package/src/components/button/config.js +0 -10
  137. package/src/components/button/constants.js +0 -63
  138. package/src/components/button/index.js +0 -2
  139. package/src/components/card/card.js +0 -102
  140. package/src/components/card/config.js +0 -16
  141. package/src/components/card/index.js +0 -7
  142. package/src/components/card/media.js +0 -56
  143. package/src/components/checkbox/api.js +0 -45
  144. package/src/components/checkbox/checkbox.js +0 -96
  145. package/src/components/checkbox/constants.js +0 -88
  146. package/src/components/checkbox/index.js +0 -2
  147. package/src/components/container/api.js +0 -42
  148. package/src/components/container/container.js +0 -45
  149. package/src/components/container/index.js +0 -2
  150. package/src/components/container/styles.scss +0 -66
  151. package/src/components/list/index.js +0 -2
  152. package/src/components/list/list-item.js +0 -147
  153. package/src/components/list/list.js +0 -267
  154. package/src/components/menu/api.js +0 -117
  155. package/src/components/menu/constants.js +0 -42
  156. package/src/components/menu/features/items-manager.js +0 -375
  157. package/src/components/menu/features/keyboard-navigation.js +0 -129
  158. package/src/components/menu/features/positioning.js +0 -125
  159. package/src/components/menu/index.js +0 -2
  160. package/src/components/menu/menu-item.js +0 -41
  161. package/src/components/menu/menu.js +0 -54
  162. package/src/components/navigation/api.js +0 -43
  163. package/src/components/navigation/index.js +0 -2
  164. package/src/components/navigation/nav-item.js +0 -137
  165. package/src/components/navigation/navigation.js +0 -55
  166. package/src/components/snackbar/api.js +0 -125
  167. package/src/components/snackbar/features.js +0 -69
  168. package/src/components/snackbar/index.js +0 -2
  169. package/src/components/snackbar/position.js +0 -63
  170. package/src/components/snackbar/queue.js +0 -74
  171. package/src/components/snackbar/snackbar.js +0 -70
  172. package/src/components/switch/api.js +0 -44
  173. package/src/components/switch/index.js +0 -2
  174. package/src/components/switch/switch.js +0 -71
  175. package/src/components/textfield/api.js +0 -49
  176. package/src/components/textfield/index.js +0 -2
  177. package/src/components/textfield/textfield.js +0 -68
  178. package/src/core/build/_ripple.scss +0 -79
  179. package/src/core/build/constants.js +0 -51
  180. package/src/core/build/icon.js +0 -78
  181. package/src/core/build/ripple.js +0 -159
  182. package/src/core/build/text.js +0 -54
  183. package/src/core/compose/base.js +0 -8
  184. package/src/core/compose/component.js +0 -225
  185. package/src/core/compose/features/checkable.js +0 -114
  186. package/src/core/compose/features/disabled.js +0 -64
  187. package/src/core/compose/features/events.js +0 -48
  188. package/src/core/compose/features/icon.js +0 -33
  189. package/src/core/compose/features/index.js +0 -20
  190. package/src/core/compose/features/input.js +0 -100
  191. package/src/core/compose/features/lifecycle.js +0 -69
  192. package/src/core/compose/features/position.js +0 -60
  193. package/src/core/compose/features/ripple.js +0 -32
  194. package/src/core/compose/features/size.js +0 -9
  195. package/src/core/compose/features/style.js +0 -12
  196. package/src/core/compose/features/text.js +0 -17
  197. package/src/core/compose/features/textinput.js +0 -114
  198. package/src/core/compose/features/textlabel.js +0 -28
  199. package/src/core/compose/features/track.js +0 -49
  200. package/src/core/compose/features/variant.js +0 -9
  201. package/src/core/compose/features/withEvents.js +0 -67
  202. package/src/core/compose/index.js +0 -16
  203. package/src/core/config.js +0 -140
  204. package/src/core/dom/classes.js +0 -70
  205. package/src/core/dom/create.js +0 -132
  206. package/src/core/dom/events.js +0 -175
  207. package/src/core/dom/index.js +0 -5
  208. package/src/core/dom/utils.js +0 -22
  209. package/src/core/index.js +0 -23
  210. package/src/core/state/disabled.js +0 -51
  211. package/src/core/state/emitter.js +0 -63
  212. package/src/core/state/events.js +0 -29
  213. package/src/core/state/index.js +0 -6
  214. package/src/core/state/lifecycle.js +0 -64
  215. package/src/core/state/store.js +0 -112
  216. package/src/core/utils/index.js +0 -39
  217. package/src/core/utils/object.js +0 -22
  218. package/src/core/utils/validate.js +0 -37
  219. /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
  220. /package/src/components/list/{styles.scss → _styles.scss} +0 -0
  221. /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
  222. /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
  223. /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
  224. /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
  225. /package/src/components/textfield/{styles.scss → _styles.scss} +0 -0
@@ -0,0 +1,234 @@
1
+ // src/core/utils/validate.ts
2
+
3
+ /**
4
+ * Validation rule interface
5
+ */
6
+ export interface ValidationRule {
7
+ /**
8
+ * Whether field is required
9
+ */
10
+ required?: boolean;
11
+
12
+ /**
13
+ * Expected data type
14
+ */
15
+ type?: string;
16
+
17
+ /**
18
+ * Minimum value for numbers
19
+ */
20
+ minimum?: number;
21
+
22
+ /**
23
+ * Maximum value for numbers
24
+ */
25
+ maximum?: number;
26
+
27
+ /**
28
+ * Regular expression pattern for strings
29
+ */
30
+ pattern?: string | RegExp;
31
+
32
+ /**
33
+ * Allowed values (enum)
34
+ */
35
+ enum?: any[];
36
+
37
+ /**
38
+ * Minimum string length
39
+ */
40
+ minLength?: number;
41
+
42
+ /**
43
+ * Maximum string length
44
+ */
45
+ maxLength?: number;
46
+
47
+ /**
48
+ * Default value
49
+ */
50
+ default?: any;
51
+
52
+ /**
53
+ * Custom validator function
54
+ */
55
+ validator?: (value: any) => boolean | string;
56
+ }
57
+
58
+ /**
59
+ * Validation schema type
60
+ */
61
+ export type ValidationSchema = Record<string, ValidationRule>;
62
+
63
+ /**
64
+ * Validates configuration object against schema
65
+ *
66
+ * @param config - Configuration to validate
67
+ * @param schema - Validation schema
68
+ * @throws Error if validation fails
69
+ */
70
+ export const validateConfig = (
71
+ config: Record<string, any>,
72
+ schema: ValidationSchema
73
+ ): void => {
74
+ const errors: string[] = [];
75
+
76
+ Object.entries(schema).forEach(([key, rule]) => {
77
+ // Check required fields
78
+ if (rule.required && config[key] === undefined) {
79
+ errors.push(`Missing required field: ${key}`);
80
+ }
81
+
82
+ if (config[key] !== undefined) {
83
+ // Check type if value exists
84
+ if (rule.type) {
85
+ const actualType = typeof config[key];
86
+ if (actualType !== rule.type) {
87
+ errors.push(`Invalid type for ${key}: expected ${rule.type}, got ${actualType}`);
88
+ }
89
+ }
90
+
91
+ // Check numbers
92
+ if (typeof config[key] === 'number') {
93
+ if (rule.minimum !== undefined && config[key] < rule.minimum) {
94
+ errors.push(`Value for ${key} is too small: minimum is ${rule.minimum}`);
95
+ }
96
+ if (rule.maximum !== undefined && config[key] > rule.maximum) {
97
+ errors.push(`Value for ${key} is too large: maximum is ${rule.maximum}`);
98
+ }
99
+ }
100
+
101
+ // Check strings
102
+ if (typeof config[key] === 'string') {
103
+ if (rule.minLength !== undefined && config[key].length < rule.minLength) {
104
+ errors.push(`String for ${key} is too short: minimum length is ${rule.minLength}`);
105
+ }
106
+ if (rule.maxLength !== undefined && config[key].length > rule.maxLength) {
107
+ errors.push(`String for ${key} is too long: maximum length is ${rule.maxLength}`);
108
+ }
109
+ if (rule.pattern) {
110
+ const pattern = rule.pattern instanceof RegExp
111
+ ? rule.pattern
112
+ : new RegExp(rule.pattern);
113
+
114
+ if (!pattern.test(config[key])) {
115
+ errors.push(`Invalid format for ${key}: must match pattern ${pattern}`);
116
+ }
117
+ }
118
+ }
119
+
120
+ // Check allowed values
121
+ if (rule.enum) {
122
+ if (!rule.enum.includes(config[key])) {
123
+ errors.push(`Invalid value for ${key}. Must be one of: ${rule.enum.join(', ')}`);
124
+ }
125
+ }
126
+
127
+ // Custom validator
128
+ if (rule.validator) {
129
+ const result = rule.validator(config[key]);
130
+ if (result === false) {
131
+ errors.push(`Invalid value for ${key}`);
132
+ } else if (typeof result === 'string') {
133
+ errors.push(result);
134
+ }
135
+ }
136
+ }
137
+ });
138
+
139
+ if (errors.length > 0) {
140
+ throw new Error(`Configuration validation failed:\n${errors.join('\n')}`);
141
+ }
142
+ };
143
+
144
+ /**
145
+ * Validates a single value against a rule
146
+ *
147
+ * @param value - Value to validate
148
+ * @param rule - Validation rule
149
+ * @returns Validation result (true if valid, error message if invalid)
150
+ */
151
+ export const validateValue = (
152
+ value: any,
153
+ rule: ValidationRule
154
+ ): true | string => {
155
+ // Check required
156
+ if (rule.required && value === undefined) {
157
+ return 'Value is required';
158
+ }
159
+
160
+ if (value !== undefined) {
161
+ // Check type
162
+ if (rule.type && typeof value !== rule.type) {
163
+ return `Expected ${rule.type}, got ${typeof value}`;
164
+ }
165
+
166
+ // Check numbers
167
+ if (typeof value === 'number') {
168
+ if (rule.minimum !== undefined && value < rule.minimum) {
169
+ return `Value is too small: minimum is ${rule.minimum}`;
170
+ }
171
+ if (rule.maximum !== undefined && value > rule.maximum) {
172
+ return `Value is too large: maximum is ${rule.maximum}`;
173
+ }
174
+ }
175
+
176
+ // Check strings
177
+ if (typeof value === 'string') {
178
+ if (rule.minLength !== undefined && value.length < rule.minLength) {
179
+ return `String is too short: minimum length is ${rule.minLength}`;
180
+ }
181
+ if (rule.maxLength !== undefined && value.length > rule.maxLength) {
182
+ return `String is too long: maximum length is ${rule.maxLength}`;
183
+ }
184
+ if (rule.pattern) {
185
+ const pattern = rule.pattern instanceof RegExp
186
+ ? rule.pattern
187
+ : new RegExp(rule.pattern);
188
+
189
+ if (!pattern.test(value)) {
190
+ return `Invalid format: must match pattern ${pattern}`;
191
+ }
192
+ }
193
+ }
194
+
195
+ // Check allowed values
196
+ if (rule.enum && !rule.enum.includes(value)) {
197
+ return `Invalid value. Must be one of: ${rule.enum.join(', ')}`;
198
+ }
199
+
200
+ // Custom validator
201
+ if (rule.validator) {
202
+ const result = rule.validator(value);
203
+ if (result === false) {
204
+ return 'Invalid value';
205
+ } else if (typeof result === 'string') {
206
+ return result;
207
+ }
208
+ }
209
+ }
210
+
211
+ return true;
212
+ };
213
+
214
+ /**
215
+ * Applies default values from schema to config
216
+ *
217
+ * @param config - Configuration object
218
+ * @param schema - Validation schema with defaults
219
+ * @returns Configuration with defaults applied
220
+ */
221
+ export const applyDefaults = <T extends Record<string, any>>(
222
+ config: T,
223
+ schema: ValidationSchema
224
+ ): T => {
225
+ const result = { ...config };
226
+
227
+ Object.entries(schema).forEach(([key, rule]) => {
228
+ if (result[key] === undefined && rule.default !== undefined) {
229
+ result[key] = rule.default;
230
+ }
231
+ });
232
+
233
+ return result;
234
+ };
@@ -1,12 +1,13 @@
1
- // src/index.js
1
+ // src/index.ts
2
2
  export { createElement } from './core/dom/create'
3
3
  export { default as createLayout } from './core/layout'
4
4
  export { default as createButton } from './components/button'
5
5
  export { default as createCard } from './components/card'
6
6
  export { default as createCheckbox } from './components/checkbox'
7
- export { default as createContainer } from './components/container'
7
+ export { default as createChip } from './components/chip'
8
8
  export { default as createMenu } from './components/menu'
9
9
  export { default as createNavigation } from './components/navigation'
10
+ export { default as createProgress } from './components/progress'
10
11
  export { default as createSnackbar } from './components/snackbar'
11
12
  export { default as createSwitch } from './components/switch'
12
13
  export { default as createTextfield } from './components/textfield'
package/index.js DELETED
@@ -1,11 +0,0 @@
1
- // index.js
2
- import {
3
- createLayout,
4
- createElement,
5
- createButton, createCard, createCheckbox, createTextfield, createSwitch, createContainer, createList, createSnackbar, createNavigation, createMenu
6
- } from './src/index.js'
7
-
8
- export {
9
- createLayout,
10
- createElement, createCard, createButton, createCheckbox, createTextfield, createSwitch, createContainer, createList, createSnackbar, createNavigation, createMenu
11
- }
@@ -1,54 +0,0 @@
1
- // src/components/button/api.js
2
-
3
- /**
4
- * Enhances a button component with API methods
5
- * @param {Object} options - API configuration options
6
- * @param {Object} options.disabled - Object containing enable/disable methods
7
- * @param {Object} options.lifecycle - Object containing lifecycle methods
8
- * @returns {Function} Higher-order function that adds API methods to component
9
- * @internal This is an internal utility for the Button component
10
- */
11
- export const withAPI = ({ disabled, lifecycle }) => (component) => ({
12
- ...component,
13
- element: component.element,
14
- getValue: () => component.element.value,
15
- setValue (value) {
16
- component.element.value = value
17
- return this
18
- },
19
- enable () {
20
- disabled.enable()
21
- return this
22
- },
23
- disable () {
24
- disabled.disable()
25
- return this
26
- },
27
- setText (content) {
28
- component.text.setText(content)
29
- this.updateCircularStyle()
30
- return this
31
- },
32
- getText () {
33
- return component.text.getText()
34
- },
35
- setIcon (icon) {
36
- component.icon.setIcon(icon)
37
- this.updateCircularStyle()
38
- return this
39
- },
40
- getIcon () {
41
- return component.icon.getIcon()
42
- },
43
- destroy () {
44
- lifecycle.destroy()
45
- },
46
- updateCircularStyle () {
47
- const hasText = component.text.getElement()
48
- if (!hasText && component.icon.getElement()) {
49
- component.element.classList.add(`${component.getClass('button')}--circular`)
50
- } else {
51
- component.element.classList.remove(`${component.getClass('button')}--circular`)
52
- }
53
- }
54
- })
@@ -1,81 +0,0 @@
1
- // src/components/button/button.js
2
- import { PREFIX } from '../../core/config'
3
- import { pipe } from '../../core/compose'
4
- import { createBase, withElement } from '../../core/compose/component'
5
- import {
6
- withEvents,
7
- withText,
8
- withIcon,
9
- withVariant,
10
- withSize,
11
- withRipple,
12
- withDisabled,
13
- withLifecycle
14
- } from '../../core/compose/features'
15
- import { withAPI } from './api'
16
- import { BUTTON_VARIANTS } from './constants'
17
-
18
- /**
19
- * Creates a new Button component
20
- * @param {Object} config - Button configuration object
21
- * @param {string} [config.variant='filled'] - Button variant (filled, tonal, outlined, elevated, text)
22
- * @param {string} [config.size] - Button size (small, medium, large)
23
- * @param {boolean} [config.disabled] - Whether the button is initially disabled
24
- * @param {string} [config.text] - Initial button text content
25
- * @param {string} [config.icon] - Initial button icon HTML content
26
- * @param {string} [config.class] - Additional CSS classes
27
- * @param {string} [config.value] - Button value attribute
28
- */
29
- const createButton = (config = {}) => {
30
- const baseConfig = {
31
- ...config,
32
- variant: config.variant || BUTTON_VARIANTS.FILLED,
33
- componentName: 'button',
34
- prefix: PREFIX
35
- }
36
-
37
- try {
38
- const button = pipe(
39
- createBase,
40
- withEvents(),
41
- withElement({
42
- tag: 'button',
43
- componentName: 'button',
44
- attrs: {
45
- type: config.type || 'button',
46
- disabled: config.disabled,
47
- value: config.value
48
- },
49
- className: config.class,
50
- forwardEvents: {
51
- click: (component) => !component.element.disabled,
52
- focus: true,
53
- blur: true
54
- }
55
- }),
56
- withVariant(baseConfig),
57
- withSize(baseConfig),
58
- withText(baseConfig),
59
- withIcon(baseConfig),
60
- withDisabled(baseConfig),
61
- withRipple(baseConfig),
62
- withLifecycle(),
63
- comp => withAPI({
64
- disabled: {
65
- enable: () => comp.disabled.enable(),
66
- disable: () => comp.disabled.disable()
67
- },
68
- lifecycle: {
69
- destroy: () => comp.lifecycle.destroy()
70
- }
71
- })(comp)
72
- )(baseConfig)
73
-
74
- return button
75
- } catch (error) {
76
- console.error('Button creation error:', error)
77
- throw new Error(`Failed to create button: ${error.message}`)
78
- }
79
- }
80
-
81
- export default createButton
@@ -1,10 +0,0 @@
1
- // src/components/button/config.js
2
-
3
- import { PREFIX } from '../../core/config'
4
-
5
- const defaultConfig = {
6
- componentName: 'button',
7
- prefix: PREFIX
8
- }
9
-
10
- export default defaultConfig
@@ -1,63 +0,0 @@
1
- // src/components/button/constants.js
2
-
3
- import { RIPPLE_SCHEMA } from '../../core/build/constants'
4
-
5
- export const BUTTON_VARIANTS = {
6
- FILLED: 'filled',
7
- TONAL: 'tonal',
8
- OUTLINED: 'outlined',
9
- ELEVATED: 'elevated',
10
- TEXT: 'text'
11
- }
12
-
13
- export const BUTTON_SIZES = {
14
- SMALL: 'small',
15
- MEDIUM: 'medium',
16
- LARGE: 'large'
17
- }
18
-
19
- /**
20
- * Validation schema for button configuration
21
- */
22
- export const BUTTON_SCHEMA = {
23
- variant: {
24
- type: 'string',
25
- enum: Object.values(BUTTON_VARIANTS),
26
- required: false
27
- },
28
- size: {
29
- type: 'string',
30
- enum: Object.values(BUTTON_SIZES),
31
- required: false
32
- },
33
- disabled: {
34
- type: 'boolean',
35
- required: false
36
- },
37
- text: {
38
- type: 'string',
39
- required: false
40
- },
41
- icon: {
42
- type: 'string',
43
- required: false
44
- },
45
- class: {
46
- type: 'string',
47
- required: false
48
- },
49
- value: {
50
- type: 'string',
51
- required: false
52
- },
53
- ripple: {
54
- type: 'boolean',
55
- required: false,
56
- default: true
57
- },
58
- rippleConfig: {
59
- type: 'object',
60
- required: false,
61
- properties: RIPPLE_SCHEMA
62
- }
63
- }
@@ -1,2 +0,0 @@
1
- // src/components/button/index.js
2
- export { default } from './button.js'
@@ -1,102 +0,0 @@
1
- // src/components/card/card.js
2
- import { PREFIX } from '../../core/config'
3
- import { pipe } from '../../core/compose'
4
- import { createBase, withElement } from '../../core/compose/component'
5
- import {
6
- withEvents,
7
- withVariant,
8
- withRipple,
9
- withLifecycle
10
- } from '../../core/compose/features'
11
- import { withAPI } from './api'
12
- import { CARD_VARIANTS, CARD_ELEVATIONS } from './constants'
13
- import defaultConfig from './config'
14
-
15
- /**
16
- * Creates a new Card component following Material Design 3 principles
17
- * @param {Object} config - Card configuration object
18
- * @param {string} [config.variant='elevated'] - Card variant (elevated, filled, outlined)
19
- * @param {boolean} [config.interactive=false] - Whether the card has hover/focus states
20
- * @param {boolean} [config.fullWidth=false] - Whether the card spans full width of container
21
- * @param {boolean} [config.clickable=false] - Whether the card is clickable with ripple effect
22
- * @param {boolean} [config.draggable=false] - Whether the card is draggable
23
- * @param {string} [config.class] - Additional CSS classes
24
- * @returns {Object} Card component instance
25
- */
26
- const createCard = (config = {}) => {
27
- const baseConfig = {
28
- ...defaultConfig,
29
- ...config,
30
- componentName: 'card',
31
- prefix: PREFIX
32
- }
33
-
34
- try {
35
- const card = pipe(
36
- createBase,
37
- withEvents(),
38
- withElement({
39
- tag: 'div',
40
- componentName: 'card',
41
- className: [
42
- config.class,
43
- config.fullWidth ? `${PREFIX}-card--full-width` : null,
44
- config.interactive ? `${PREFIX}-card--interactive` : null
45
- ],
46
- forwardEvents: {
47
- click: (component) => config.clickable,
48
- mouseenter: (component) => config.interactive,
49
- mouseleave: (component) => config.interactive
50
- },
51
- interactive: config.interactive || config.clickable
52
- }),
53
- withVariant(baseConfig),
54
- config.clickable ? withRipple(baseConfig) : (c) => c,
55
- withLifecycle(),
56
- comp => {
57
- // Implement hover state elevation changes for interactive cards
58
- if (comp.config.interactive) {
59
- comp.element.addEventListener('mouseenter', () => {
60
- if (comp.config.variant === CARD_VARIANTS.ELEVATED) {
61
- comp.element.style.setProperty('--card-elevation', CARD_ELEVATIONS.HOVERED)
62
- }
63
- })
64
-
65
- comp.element.addEventListener('mouseleave', () => {
66
- if (comp.config.variant === CARD_VARIANTS.ELEVATED) {
67
- comp.element.style.setProperty('--card-elevation', CARD_ELEVATIONS.RESTING)
68
- }
69
- })
70
- }
71
-
72
- // Set up draggable
73
- if (comp.config.draggable) {
74
- comp.element.setAttribute('draggable', 'true')
75
- comp.element.addEventListener('dragstart', (e) => {
76
- comp.element.style.setProperty('--card-elevation', CARD_ELEVATIONS.DRAGGED)
77
- comp.emit('dragstart', { event: e })
78
- })
79
-
80
- comp.element.addEventListener('dragend', (e) => {
81
- comp.element.style.setProperty('--card-elevation', CARD_ELEVATIONS.RESTING)
82
- comp.emit('dragend', { event: e })
83
- })
84
- }
85
-
86
- return comp
87
- },
88
- comp => withAPI({
89
- lifecycle: {
90
- destroy: () => comp.lifecycle.destroy()
91
- }
92
- })(comp)
93
- )(baseConfig)
94
-
95
- return card
96
- } catch (error) {
97
- console.error('Card creation error:', error)
98
- throw new Error(`Failed to create card: ${error.message}`)
99
- }
100
- }
101
-
102
- export default createCard
@@ -1,16 +0,0 @@
1
- // src/components/card/config.js
2
-
3
- import { PREFIX } from '../../core/config'
4
- import { CARD_VARIANTS } from './constants'
5
-
6
- const defaultConfig = {
7
- componentName: 'card',
8
- prefix: PREFIX,
9
- variant: CARD_VARIANTS.ELEVATED,
10
- interactive: false,
11
- fullWidth: false,
12
- clickable: false,
13
- draggable: false
14
- }
15
-
16
- export default defaultConfig
@@ -1,7 +0,0 @@
1
- // src/components/card/index.js
2
- export { default } from './card.js'
3
- export { createCardContent } from './content.js'
4
- export { createCardHeader } from './header.js'
5
- export { createCardActions } from './actions.js'
6
- export { createCardMedia } from './media.js'
7
- export { CARD_VARIANTS, CARD_ELEVATIONS } from './constants.js'
@@ -1,56 +0,0 @@
1
- // src/components/card/media.js
2
- import { PREFIX } from '../../core/config'
3
- import { pipe } from '../../core/compose'
4
- import { createBase, withElement } from '../../core/compose/component'
5
-
6
- /**
7
- * Creates a card media component
8
- * @param {Object} config - Media configuration
9
- * @param {string} [config.src] - Image source URL
10
- * @param {string} [config.alt] - Image alt text
11
- * @param {HTMLElement} [config.element] - Custom media element
12
- * @param {string} [config.aspectRatio='16:9'] - Media aspect ratio
13
- * @param {boolean} [config.contain=false] - Whether to use object-fit: contain
14
- * @returns {HTMLElement} Card media element
15
- */
16
- export const createCardMedia = (config = {}) => {
17
- const baseConfig = {
18
- ...config,
19
- componentName: 'card-media',
20
- prefix: PREFIX
21
- }
22
-
23
- try {
24
- const media = pipe(
25
- createBase,
26
- withElement({
27
- tag: 'div',
28
- componentName: 'card-media',
29
- className: [
30
- config.class,
31
- config.aspectRatio ? `${PREFIX}-card-media--${config.aspectRatio.replace(':', '-')}` : null,
32
- config.contain ? `${PREFIX}-card-media--contain` : null
33
- ]
34
- })
35
- )(baseConfig)
36
-
37
- // If custom element is provided, use it
38
- if (config.element instanceof HTMLElement) {
39
- media.element.appendChild(config.element)
40
- }
41
-
42
- // Otherwise create an image if src is provided
43
- else if (config.src) {
44
- const img = document.createElement('img')
45
- img.src = config.src
46
- if (config.alt) img.alt = config.alt
47
- img.className = `${PREFIX}-card-media-img`
48
- media.element.appendChild(img)
49
- }
50
-
51
- return media.element
52
- } catch (error) {
53
- console.error('Card media creation error:', error)
54
- throw new Error(`Failed to create card media: ${error.message}`)
55
- }
56
- }