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
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # MTRL Library
2
2
 
3
- > **Project Status:** MTRL is in active early development. The core architecture and initial components are being established, with more features on the roadmap. While we're making rapid progress, the API may evolve as we refine the library. We welcome early adopters and contributors who want to help shape MTRL's future!
3
+ > **Project Status:** MTRL is in active development with TypeScript support! The core architecture and components are established, with more features on the roadmap. We welcome early adopters and contributors who want to help shape MTRL's future!
4
4
 
5
- MTRL is a lightweight, composable JavaScript component library inspired by Material Design principles. Built with vanilla JavaScript and zero dependencies, MTRL provides a robust foundation for creating modern web interfaces with an emphasis on performance and accessibility.
5
+ MTRL is a lightweight, composable TypeScript/JavaScript component library inspired by Material Design principles. Built with zero dependencies, MTRL provides a robust foundation for creating modern web interfaces with an emphasis on performance, type safety, and accessibility.
6
6
 
7
7
  ## Understanding MTRL
8
8
 
@@ -12,16 +12,17 @@ MTRL (pronounced "material") takes its inspiration from Material Design while pr
12
12
 
13
13
  MTRL is built on several core principles:
14
14
 
15
- 1. **Composition Over Inheritance**: Components are constructed through functional composition, making them flexible and maintainable.
16
- 2. **Zero Dependencies**: The entire library is built with vanilla JavaScript, ensuring minimal bundle size and maximum compatibility.
15
+ 1. **Composition Over Inheritance**: Components are constructed through functional composition with full type safety.
16
+ 2. **Zero Dependencies**: The entire library is built with vanilla TypeScript, ensuring minimal bundle size and maximum compatibility.
17
17
  3. **Material Design Inspiration**: While inspired by Material Design, MTRL provides flexibility in styling and behavior.
18
18
  4. **Accessibility First**: Built-in accessibility features ensure your applications are usable by everyone.
19
+ 5. **TypeScript First**: Comprehensive type definitions for better developer experience and code reliability.
19
20
 
20
21
  ## Core Components
21
22
 
22
23
  MTRL provides a comprehensive set of components, each following Material Design principles:
23
24
 
24
- ```javascript
25
+ ```typescript
25
26
  import { createButton, createTextField } from 'mtrl'
26
27
 
27
28
  // Create a material button with ripple effect
@@ -64,7 +65,7 @@ bun add mtrl
64
65
 
65
66
  Let's look at how MTRL components are constructed:
66
67
 
67
- ```javascript
68
+ ```typescript
68
69
  // Example of a button component creation
69
70
  const button = createButton({
70
71
  prefix: 'mtrl', // The library's prefix
@@ -77,11 +78,11 @@ const button = createButton({
77
78
 
78
79
  ### The Composition System
79
80
 
80
- MTRL uses a pipe-based composition system for building components:
81
+ MTRL uses a pipe-based composition system with full type safety for building components:
81
82
 
82
- ```javascript
83
+ ```typescript
83
84
  // Internal component creation
84
- const createButton = (config) => {
85
+ const createButton = (config: ButtonConfig): ButtonComponent => {
85
86
  return pipe(
86
87
  createBase, // Base component structure
87
88
  withEvents(), // Event handling capability
@@ -98,6 +99,34 @@ const createButton = (config) => {
98
99
  }
99
100
  ```
100
101
 
102
+ ### TypeScript Integration
103
+
104
+ MTRL provides comprehensive TypeScript definitions:
105
+
106
+ ```typescript
107
+ // Component interfaces for better developer experience
108
+ export interface ButtonComponent extends
109
+ BaseComponent,
110
+ ElementComponent,
111
+ TextComponent,
112
+ IconComponent,
113
+ DisabledComponent,
114
+ LifecycleComponent {
115
+
116
+ // Button-specific properties and methods
117
+ getValue: () => string;
118
+ setValue: (value: string) => ButtonComponent;
119
+ enable: () => ButtonComponent;
120
+ disable: () => ButtonComponent;
121
+ setText: (content: string) => ButtonComponent;
122
+ getText: () => string;
123
+ setIcon: (icon: string) => ButtonComponent;
124
+ getIcon: () => string;
125
+ destroy: () => void;
126
+ updateCircularStyle: () => void;
127
+ }
128
+ ```
129
+
101
130
  ### CSS Classes
102
131
 
103
132
  MTRL follows a consistent class naming convention:
@@ -115,7 +144,7 @@ MTRL provides several approaches to state management:
115
144
 
116
145
  ### Local Component State
117
146
 
118
- ```javascript
147
+ ```typescript
119
148
  const textField = createTextField({
120
149
  label: 'Username'
121
150
  })
@@ -131,8 +160,8 @@ textField.setValue('New value')
131
160
 
132
161
  For managing lists and datasets:
133
162
 
134
- ```javascript
135
- const collection = new Collection({
163
+ ```typescript
164
+ const collection = new Collection<User>({
136
165
  transform: (item) => ({
137
166
  ...item,
138
167
  displayName: `${item.firstName} ${item.lastName}`
@@ -148,7 +177,7 @@ collection.subscribe(({ event, data }) => {
148
177
 
149
178
  MTRL provides adapters for different data sources:
150
179
 
151
- ```javascript
180
+ ```typescript
152
181
  // MongoDB adapter
153
182
  const mongoAdapter = createMongoAdapter({
154
183
  uri: 'mongodb://localhost:27017',
@@ -170,10 +199,19 @@ const routeAdapter = createRouteAdapter({
170
199
 
171
200
  ### Creating Custom Components
172
201
 
173
- Extend MTRL by creating custom components:
202
+ Extend MTRL by creating custom components with full type safety:
174
203
 
175
- ```javascript
176
- const createCustomCard = (config) => {
204
+ ```typescript
205
+ interface CustomCardConfig {
206
+ title?: string;
207
+ class?: string;
208
+ }
209
+
210
+ interface CustomCardComponent extends ElementComponent {
211
+ setContent: (content: string) => CustomCardComponent;
212
+ }
213
+
214
+ const createCustomCard = (config: CustomCardConfig): CustomCardComponent => {
177
215
  return pipe(
178
216
  createBase,
179
217
  withEvents(),
@@ -185,12 +223,12 @@ const createCustomCard = (config) => {
185
223
  // Add custom features
186
224
  (component) => ({
187
225
  ...component,
188
- setContent(content) {
189
- component.element.innerHTML = content
190
- return this
226
+ setContent(content: string) {
227
+ component.element.innerHTML = content;
228
+ return this;
191
229
  }
192
230
  })
193
- )(config)
231
+ )(config);
194
232
  }
195
233
  ```
196
234
 
@@ -218,6 +256,16 @@ MTRL is designed with performance in mind:
218
256
  - Automatic cleanup of resources
219
257
  - Lazy initialization of features
220
258
 
259
+ ### Type Safety
260
+
261
+ MTRL leverages TypeScript for better developer experience:
262
+
263
+ - Clear component interfaces
264
+ - Type-safe method chaining
265
+ - Intelligent code completion
266
+ - Compile-time error checking
267
+ - Self-documenting code
268
+
221
269
  ### Accessibility
222
270
 
223
271
  Built-in accessibility features include:
@@ -238,7 +286,7 @@ MTRL supports modern browsers:
238
286
 
239
287
  ## Contributing
240
288
 
241
- We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
289
+ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details and our [Migration Guide](MIGRATION-GUIDE.md) for TypeScript information.
242
290
 
243
291
  ## License
244
292
 
@@ -250,4 +298,4 @@ For detailed API documentation, examples, and guides, visit our [documentation s
250
298
 
251
299
  ---
252
300
 
253
- This library is designed to provide a solid foundation for building modern web interfaces while maintaining flexibility for custom implementations. For questions, issues, or contributions, please visit our GitHub repository.
301
+ This library is designed to provide a solid foundation for building modern web interfaces with TypeScript while maintaining flexibility for custom implementations. For questions, issues, or contributions, please visit our GitHub repository.
package/index.ts ADDED
@@ -0,0 +1,33 @@
1
+ // index.js
2
+ import {
3
+ createLayout,
4
+ createElement,
5
+ createButton,
6
+ createCard,
7
+ createCheckbox,
8
+ createChip,
9
+ createList,
10
+ createMenu,
11
+ createNavigation,
12
+ createProgress,
13
+ createTextfield,
14
+ createSnackbar,
15
+ createSwitch
16
+
17
+ } from './src/index.js'
18
+
19
+ export {
20
+ createLayout,
21
+ createElement,
22
+ createButton,
23
+ createCard,
24
+ createCheckbox,
25
+ createChip,
26
+ createList,
27
+ createMenu,
28
+ createNavigation,
29
+ createProgress,
30
+ createTextfield,
31
+ createSnackbar,
32
+ createSwitch
33
+ }
package/package.json CHANGED
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "name": "mtrl",
3
- "version": "0.1.3",
3
+ "version": "0.2.1",
4
4
  "description": "A functional JavaScript component library with composable architecture based on Material Design 3",
5
- "keywords": ["component", "library", "ui", "user interface", "functional", "composable"],
5
+ "keywords": [
6
+ "component",
7
+ "library",
8
+ "ui",
9
+ "user interface",
10
+ "functional",
11
+ "composable"
12
+ ],
6
13
  "main": "index.js",
7
14
  "scripts": {
8
15
  "test": "bun test",
@@ -14,7 +21,9 @@
14
21
  "type": "git",
15
22
  "url": "https://github.com/floor/mtrl.git"
16
23
  },
17
-
18
24
  "author": "floor",
19
- "license": "MIT License"
20
- }
25
+ "license": "MIT License",
26
+ "devDependencies": {
27
+ "typedoc": "^0.27.9"
28
+ }
29
+ }
@@ -1,4 +1,4 @@
1
- // src/components/button/_button.scss
1
+ // src/components/button/_styles.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;
@@ -52,7 +52,7 @@ $component: '#{base.$prefix}-button';
52
52
  // Interactive states
53
53
  &:disabled {
54
54
  pointer-events: none;
55
- opacity: 0.85;
55
+ opacity: 0.38;
56
56
  }
57
57
 
58
58
  // Ensure proper layout with icons
@@ -0,0 +1,89 @@
1
+ // src/components/button/api.ts
2
+ import { ButtonComponent } from './types';
3
+
4
+ interface ApiOptions {
5
+ disabled: {
6
+ enable: () => void;
7
+ disable: () => void;
8
+ };
9
+ lifecycle: {
10
+ destroy: () => void;
11
+ };
12
+ }
13
+
14
+ interface ComponentWithElements {
15
+ element: HTMLElement;
16
+ text: {
17
+ setText: (content: string) => any;
18
+ getText: () => string;
19
+ getElement: () => HTMLElement | null;
20
+ };
21
+ icon: {
22
+ setIcon: (html: string) => any;
23
+ getIcon: () => string;
24
+ getElement: () => HTMLElement | null;
25
+ };
26
+ getClass: (name: string) => string;
27
+ }
28
+
29
+ /**
30
+ * Enhances a button component with API methods
31
+ * @param {ApiOptions} options - API configuration options
32
+ * @returns {Function} Higher-order function that adds API methods to component
33
+ * @internal This is an internal utility for the Button component
34
+ */
35
+ export const withAPI = ({ disabled, lifecycle }: ApiOptions) =>
36
+ (component: ComponentWithElements): ButtonComponent => ({
37
+ ...component as any,
38
+ element: component.element as HTMLButtonElement,
39
+
40
+ getValue: () => component.element.value,
41
+
42
+ setValue(value: string) {
43
+ component.element.value = value;
44
+ return this;
45
+ },
46
+
47
+ enable() {
48
+ disabled.enable();
49
+ return this;
50
+ },
51
+
52
+ disable() {
53
+ disabled.disable();
54
+ return this;
55
+ },
56
+
57
+ setText(content: string) {
58
+ component.text.setText(content);
59
+ this.updateCircularStyle();
60
+ return this;
61
+ },
62
+
63
+ getText() {
64
+ return component.text.getText();
65
+ },
66
+
67
+ setIcon(icon: string) {
68
+ component.icon.setIcon(icon);
69
+ this.updateCircularStyle();
70
+ return this;
71
+ },
72
+
73
+ getIcon() {
74
+ return component.icon.getIcon();
75
+ },
76
+
77
+ destroy() {
78
+ lifecycle.destroy();
79
+ },
80
+
81
+ updateCircularStyle() {
82
+ const hasText = component.text.getElement();
83
+ if (!hasText && component.icon.getElement()) {
84
+ component.element.classList.add(`${component.getClass('button')}--circular`);
85
+ } else {
86
+ component.element.classList.remove(`${component.getClass('button')}--circular`);
87
+ }
88
+ }
89
+ });
@@ -0,0 +1,50 @@
1
+ // src/components/button/button.ts
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 { ButtonConfig } from './types';
17
+ import { BUTTON_VARIANTS } from './constants';
18
+ import { createBaseConfig, getElementConfig, getApiConfig } from './config';
19
+
20
+ /**
21
+ * Creates a new Button component
22
+ * @param {ButtonConfig} config - Button configuration object
23
+ * @returns {ButtonComponent} Button component instance
24
+ */
25
+ const createButton = (config: ButtonConfig = {}) => {
26
+ const baseConfig = createBaseConfig(config);
27
+
28
+ try {
29
+ const button = pipe(
30
+ createBase,
31
+ withEvents(),
32
+ withElement(getElementConfig(baseConfig)),
33
+ withVariant(baseConfig),
34
+ withSize(baseConfig),
35
+ withText(baseConfig),
36
+ withIcon(baseConfig),
37
+ withDisabled(baseConfig),
38
+ withRipple(baseConfig),
39
+ withLifecycle(),
40
+ comp => withAPI(getApiConfig(comp))(comp)
41
+ )(baseConfig);
42
+
43
+ return button;
44
+ } catch (error) {
45
+ console.error('Button creation error:', error);
46
+ throw new Error(`Failed to create button: ${(error as Error).message}`);
47
+ }
48
+ };
49
+
50
+ export default createButton;
@@ -0,0 +1,75 @@
1
+ // src/components/button/config.ts
2
+ import {
3
+ createComponentConfig,
4
+ createElementConfig,
5
+ BaseComponentConfig
6
+ } from '../../core/config/component-config';
7
+ import { ButtonConfig } from './types';
8
+ import { BUTTON_VARIANTS } from './constants';
9
+
10
+ /**
11
+ * Default configuration for the Button component
12
+ */
13
+ export const defaultConfig: ButtonConfig = {
14
+ variant: BUTTON_VARIANTS.FILLED,
15
+ type: 'button'
16
+ // Don't set disabled: false as default - it should be undefined by default
17
+ };
18
+
19
+ /**
20
+ * Creates the base configuration for Button component
21
+ * @param {ButtonConfig} config - User provided configuration
22
+ * @returns {ButtonConfig} Complete configuration with defaults applied
23
+ */
24
+ export const createBaseConfig = (config: ButtonConfig = {}): ButtonConfig =>
25
+ createComponentConfig(defaultConfig, config, 'button') as ButtonConfig;
26
+
27
+ /**
28
+ * Generates element configuration for the Button component
29
+ * @param {ButtonConfig} config - Button configuration
30
+ * @returns {Object} Element configuration object for withElement
31
+ */
32
+ export const getElementConfig = (config: ButtonConfig) => {
33
+ // Create the attributes object
34
+ const attrs: Record<string, any> = {
35
+ type: config.type || 'button'
36
+ };
37
+
38
+ // Only add disabled attribute if it's explicitly true
39
+ if (config.disabled === true) {
40
+ attrs.disabled = true;
41
+ }
42
+
43
+ // Add value attribute only if it exists
44
+ if (config.value !== undefined) {
45
+ attrs.value = config.value;
46
+ }
47
+
48
+ return createElementConfig(config, {
49
+ tag: 'button',
50
+ attrs,
51
+ className: config.class,
52
+ forwardEvents: {
53
+ click: (component) => !component.element.disabled,
54
+ focus: true,
55
+ blur: true
56
+ }
57
+ });
58
+ };
59
+
60
+ /**
61
+ * Creates API configuration for the Button component
62
+ * @param {Object} comp - Component with disabled and lifecycle features
63
+ * @returns {Object} API configuration object
64
+ */
65
+ export const getApiConfig = (comp) => ({
66
+ disabled: {
67
+ enable: () => comp.disabled.enable(),
68
+ disable: () => comp.disabled.disable()
69
+ },
70
+ lifecycle: {
71
+ destroy: () => comp.lifecycle.destroy()
72
+ }
73
+ });
74
+
75
+ export default defaultConfig;
@@ -0,0 +1,17 @@
1
+ // src/components/button/constants.ts
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
+ }
@@ -0,0 +1,4 @@
1
+ // src/components/button/index.ts
2
+ export { default } from './button'
3
+ export { BUTTON_VARIANTS, BUTTON_SIZES } from './constants'
4
+ export { ButtonConfig, ButtonComponent } from './types'
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Configuration interface for the Button component
3
+ */
4
+ export interface ButtonConfig {
5
+ /** Button variant (filled, tonal, outlined, elevated, text) */
6
+ variant?: keyof typeof BUTTON_VARIANTS | BUTTON_VARIANTS;
7
+
8
+ /** Button size (small, medium, large) */
9
+ size?: keyof typeof BUTTON_SIZES | BUTTON_SIZES;
10
+
11
+ /** Whether the button is initially disabled */
12
+ disabled?: boolean;
13
+
14
+ /** Initial button text content */
15
+ text?: string;
16
+
17
+ /** Initial button icon HTML content */
18
+ icon?: string;
19
+
20
+ /** Icon size */
21
+ iconSize?: string;
22
+
23
+ /** Additional CSS classes */
24
+ class?: string;
25
+
26
+ /** Button value attribute */
27
+ value?: string;
28
+
29
+ /** Button type attribute (default: 'button') */
30
+ type?: 'button' | 'submit' | 'reset';
31
+
32
+ /** Whether to enable ripple effect */
33
+ ripple?: boolean;
34
+
35
+ /** Ripple effect configuration */
36
+ rippleConfig?: {
37
+ duration?: number;
38
+ timing?: string;
39
+ opacity?: [string, string];
40
+ };
41
+ }
42
+
43
+ /**
44
+ * Icon API interface
45
+ */
46
+ export interface IconAPI {
47
+ setIcon: (html: string) => IconAPI;
48
+ getIcon: () => string;
49
+ getElement: () => HTMLElement | null;
50
+ }
51
+
52
+ /**
53
+ * Text API interface
54
+ */
55
+ export interface TextAPI {
56
+ setText: (content: string) => TextAPI;
57
+ getText: () => string;
58
+ getElement: () => HTMLElement | null;
59
+ }
60
+
61
+ /**
62
+ * Button component interface
63
+ */
64
+ export interface ButtonComponent {
65
+ element: HTMLButtonElement;
66
+ text: TextAPI;
67
+ icon: IconAPI;
68
+ disabled: {
69
+ enable: () => void;
70
+ disable: () => void;
71
+ isDisabled: () => boolean;
72
+ };
73
+ lifecycle: {
74
+ destroy: () => void;
75
+ };
76
+
77
+ /** Gets the class with the specified name */
78
+ getClass: (name: string) => string;
79
+
80
+ /** Gets the button's value */
81
+ getValue: () => string;
82
+
83
+ /** Sets the button's value */
84
+ setValue: (value: string) => ButtonComponent;
85
+
86
+ /** Enables the button */
87
+ enable: () => ButtonComponent;
88
+
89
+ /** Disables the button */
90
+ disable: () => ButtonComponent;
91
+
92
+ /** Sets the button's text content */
93
+ setText: (content: string) => ButtonComponent;
94
+
95
+ /** Gets the button's text content */
96
+ getText: () => string;
97
+
98
+ /** Sets the button's icon */
99
+ setIcon: (icon: string) => ButtonComponent;
100
+
101
+ /** Gets the button's icon */
102
+ getIcon: () => string;
103
+
104
+ /** Destroys the button component and cleans up resources */
105
+ destroy: () => void;
106
+
107
+ /** Updates the button's circular style based on content */
108
+ updateCircularStyle: () => void;
109
+
110
+ /** Adds event listener */
111
+ on: (event: string, handler: Function) => ButtonComponent;
112
+
113
+ /** Removes event listener */
114
+ off: (event: string, handler: Function) => ButtonComponent;
115
+
116
+ /** Add CSS classes */
117
+ addClass: (...classes: string[]) => ButtonComponent;
118
+ }