mtrl 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -22
- package/index.ts +33 -0
- package/package.json +14 -5
- package/src/components/button/{styles.scss → _styles.scss} +2 -2
- package/src/components/button/api.ts +89 -0
- package/src/components/button/button.ts +50 -0
- package/src/components/button/config.ts +75 -0
- package/src/components/button/constants.ts +17 -0
- package/src/components/button/index.ts +4 -0
- package/src/components/button/types.ts +118 -0
- package/src/components/card/{styles.scss → _styles.scss} +79 -7
- package/src/components/card/{actions.js → actions.ts} +15 -18
- package/src/components/card/{api.js → api.ts} +33 -33
- package/src/components/card/card.ts +41 -0
- package/src/components/card/config.ts +99 -0
- package/src/components/card/{constants.js → constants.ts} +11 -10
- package/src/components/card/{content.js → content.ts} +15 -18
- package/src/components/card/{features.js → features.ts} +104 -94
- package/src/components/card/{header.js → header.ts} +21 -25
- package/src/components/card/index.ts +19 -0
- package/src/components/card/media.ts +52 -0
- package/src/components/card/types.ts +174 -0
- package/src/components/checkbox/api.ts +82 -0
- package/src/components/checkbox/checkbox.ts +75 -0
- package/src/components/checkbox/config.ts +90 -0
- package/src/components/checkbox/index.ts +4 -0
- package/src/components/checkbox/types.ts +146 -0
- package/src/components/chip/_styles.scss +372 -0
- package/src/components/chip/api.ts +115 -0
- package/src/components/chip/chip-set.ts +225 -0
- package/src/components/chip/chip.ts +82 -0
- package/src/components/chip/config.ts +92 -0
- package/src/components/chip/constants.ts +38 -0
- package/src/components/chip/index.ts +4 -0
- package/src/components/chip/types.ts +172 -0
- package/src/components/list/api.ts +72 -0
- package/src/components/list/config.ts +43 -0
- package/src/components/list/{constants.js → constants.ts} +34 -7
- package/src/components/list/features.ts +224 -0
- package/src/components/list/index.ts +14 -0
- package/src/components/list/list-item.ts +120 -0
- package/src/components/list/list.ts +37 -0
- package/src/components/list/types.ts +179 -0
- package/src/components/list/utils.ts +47 -0
- package/src/components/menu/api.ts +119 -0
- package/src/components/menu/config.ts +54 -0
- package/src/components/menu/constants.ts +154 -0
- package/src/components/menu/features/items-manager.ts +457 -0
- package/src/components/menu/features/keyboard-navigation.ts +133 -0
- package/src/components/menu/features/positioning.ts +127 -0
- package/src/components/menu/features/{visibility.js → visibility.ts} +66 -64
- package/src/components/menu/index.ts +14 -0
- package/src/components/menu/menu-item.ts +43 -0
- package/src/components/menu/menu.ts +53 -0
- package/src/components/menu/types.ts +178 -0
- package/src/components/navigation/api.ts +79 -0
- package/src/components/navigation/config.ts +61 -0
- package/src/components/navigation/{constants.js → constants.ts} +10 -10
- package/src/components/navigation/index.ts +14 -0
- package/src/components/navigation/nav-item.ts +148 -0
- package/src/components/navigation/navigation.ts +50 -0
- package/src/components/navigation/types.ts +212 -0
- package/src/components/progress/_styles.scss +204 -0
- package/src/components/progress/api.ts +179 -0
- package/src/components/progress/config.ts +124 -0
- package/src/components/progress/constants.ts +43 -0
- package/src/components/progress/index.ts +5 -0
- package/src/components/progress/progress.ts +163 -0
- package/src/components/progress/types.ts +102 -0
- package/src/components/snackbar/api.ts +162 -0
- package/src/components/snackbar/config.ts +62 -0
- package/src/components/snackbar/{constants.js → constants.ts} +21 -4
- package/src/components/snackbar/features.ts +76 -0
- package/src/components/snackbar/index.ts +4 -0
- package/src/components/snackbar/position.ts +71 -0
- package/src/components/snackbar/queue.ts +76 -0
- package/src/components/snackbar/snackbar.ts +60 -0
- package/src/components/snackbar/types.ts +58 -0
- package/src/components/switch/api.ts +77 -0
- package/src/components/switch/config.ts +74 -0
- package/src/components/switch/index.ts +4 -0
- package/src/components/switch/switch.ts +52 -0
- package/src/components/switch/types.ts +142 -0
- package/src/components/textfield/api.ts +72 -0
- package/src/components/textfield/config.ts +54 -0
- package/src/components/textfield/{constants.js → constants.ts} +38 -5
- package/src/components/textfield/index.ts +4 -0
- package/src/components/textfield/textfield.ts +50 -0
- package/src/components/textfield/types.ts +139 -0
- package/src/core/compose/base.ts +43 -0
- package/src/core/compose/component.ts +247 -0
- package/src/core/compose/features/checkable.ts +155 -0
- package/src/core/compose/features/disabled.ts +116 -0
- package/src/core/compose/features/events.ts +65 -0
- package/src/core/compose/features/icon.ts +67 -0
- package/src/core/compose/features/index.ts +35 -0
- package/src/core/compose/features/input.ts +174 -0
- package/src/core/compose/features/lifecycle.ts +139 -0
- package/src/core/compose/features/position.ts +94 -0
- package/src/core/compose/features/ripple.ts +55 -0
- package/src/core/compose/features/size.ts +29 -0
- package/src/core/compose/features/style.ts +31 -0
- package/src/core/compose/features/text.ts +44 -0
- package/src/core/compose/features/textinput.ts +225 -0
- package/src/core/compose/features/textlabel.ts +92 -0
- package/src/core/compose/features/track.ts +84 -0
- package/src/core/compose/features/variant.ts +29 -0
- package/src/core/compose/features/withEvents.ts +137 -0
- package/src/core/compose/index.ts +54 -0
- package/src/core/compose/{pipe.js → pipe.ts} +16 -11
- package/src/core/config/component-config.ts +136 -0
- package/src/core/config.ts +211 -0
- package/src/core/dom/{attributes.js → attributes.ts} +11 -11
- package/src/core/dom/classes.ts +60 -0
- package/src/core/dom/create.ts +188 -0
- package/src/core/dom/events.ts +209 -0
- package/src/core/dom/index.ts +10 -0
- package/src/core/dom/utils.ts +97 -0
- package/src/core/index.ts +111 -0
- package/src/core/state/disabled.ts +81 -0
- package/src/core/state/emitter.ts +94 -0
- package/src/core/state/events.ts +88 -0
- package/src/core/state/index.ts +16 -0
- package/src/core/state/lifecycle.ts +131 -0
- package/src/core/state/store.ts +197 -0
- package/src/core/utils/index.ts +45 -0
- package/src/core/utils/{mobile.js → mobile.ts} +48 -24
- package/src/core/utils/object.ts +41 -0
- package/src/core/utils/validate.ts +234 -0
- package/src/{index.js → index.ts} +3 -2
- package/index.js +0 -11
- package/src/components/button/api.js +0 -54
- package/src/components/button/button.js +0 -81
- package/src/components/button/config.js +0 -10
- package/src/components/button/constants.js +0 -63
- package/src/components/button/index.js +0 -2
- package/src/components/card/card.js +0 -102
- package/src/components/card/config.js +0 -16
- package/src/components/card/index.js +0 -7
- package/src/components/card/media.js +0 -56
- package/src/components/checkbox/api.js +0 -45
- package/src/components/checkbox/checkbox.js +0 -96
- package/src/components/checkbox/index.js +0 -2
- package/src/components/container/api.js +0 -42
- package/src/components/container/container.js +0 -45
- package/src/components/container/index.js +0 -2
- package/src/components/container/styles.scss +0 -66
- package/src/components/list/index.js +0 -2
- package/src/components/list/list-item.js +0 -147
- package/src/components/list/list.js +0 -267
- package/src/components/menu/api.js +0 -117
- package/src/components/menu/constants.js +0 -42
- package/src/components/menu/features/items-manager.js +0 -375
- package/src/components/menu/features/keyboard-navigation.js +0 -129
- package/src/components/menu/features/positioning.js +0 -125
- package/src/components/menu/index.js +0 -2
- package/src/components/menu/menu-item.js +0 -41
- package/src/components/menu/menu.js +0 -54
- package/src/components/navigation/api.js +0 -43
- package/src/components/navigation/index.js +0 -2
- package/src/components/navigation/nav-item.js +0 -137
- package/src/components/navigation/navigation.js +0 -55
- package/src/components/snackbar/api.js +0 -125
- package/src/components/snackbar/features.js +0 -69
- package/src/components/snackbar/index.js +0 -2
- package/src/components/snackbar/position.js +0 -63
- package/src/components/snackbar/queue.js +0 -74
- package/src/components/snackbar/snackbar.js +0 -70
- package/src/components/switch/api.js +0 -44
- package/src/components/switch/index.js +0 -2
- package/src/components/switch/switch.js +0 -71
- package/src/components/textfield/api.js +0 -49
- package/src/components/textfield/index.js +0 -2
- package/src/components/textfield/textfield.js +0 -68
- package/src/core/build/_ripple.scss +0 -79
- package/src/core/build/constants.js +0 -51
- package/src/core/build/icon.js +0 -78
- package/src/core/build/ripple.js +0 -159
- package/src/core/build/text.js +0 -54
- package/src/core/compose/base.js +0 -8
- package/src/core/compose/component.js +0 -225
- package/src/core/compose/features/checkable.js +0 -114
- package/src/core/compose/features/disabled.js +0 -64
- package/src/core/compose/features/events.js +0 -48
- package/src/core/compose/features/icon.js +0 -33
- package/src/core/compose/features/index.js +0 -20
- package/src/core/compose/features/input.js +0 -100
- package/src/core/compose/features/lifecycle.js +0 -69
- package/src/core/compose/features/position.js +0 -60
- package/src/core/compose/features/ripple.js +0 -32
- package/src/core/compose/features/size.js +0 -9
- package/src/core/compose/features/style.js +0 -12
- package/src/core/compose/features/text.js +0 -17
- package/src/core/compose/features/textinput.js +0 -114
- package/src/core/compose/features/textlabel.js +0 -28
- package/src/core/compose/features/track.js +0 -49
- package/src/core/compose/features/variant.js +0 -9
- package/src/core/compose/features/withEvents.js +0 -67
- package/src/core/compose/index.js +0 -16
- package/src/core/config.js +0 -140
- package/src/core/dom/classes.js +0 -70
- package/src/core/dom/create.js +0 -132
- package/src/core/dom/events.js +0 -175
- package/src/core/dom/index.js +0 -5
- package/src/core/dom/utils.js +0 -22
- package/src/core/index.js +0 -23
- package/src/core/state/disabled.js +0 -51
- package/src/core/state/emitter.js +0 -63
- package/src/core/state/events.js +0 -29
- package/src/core/state/index.js +0 -6
- package/src/core/state/lifecycle.js +0 -64
- package/src/core/state/store.js +0 -112
- package/src/core/utils/index.js +0 -39
- package/src/core/utils/object.js +0 -22
- package/src/core/utils/validate.js +0 -37
- /package/src/components/checkbox/{styles.scss → _styles.scss} +0 -0
- /package/src/components/checkbox/{constants.js → constants.ts} +0 -0
- /package/src/components/list/{styles.scss → _styles.scss} +0 -0
- /package/src/components/menu/{styles.scss → _styles.scss} +0 -0
- /package/src/components/navigation/{styles.scss → _styles.scss} +0 -0
- /package/src/components/snackbar/{styles.scss → _styles.scss} +0 -0
- /package/src/components/switch/{styles.scss → _styles.scss} +0 -0
- /package/src/components/switch/{constants.js → constants.ts} +0 -0
- /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
|
|
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
|
|
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
|
|
16
|
-
2. **Zero Dependencies**: The entire library is built with vanilla
|
|
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
|
-
```
|
|
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
|
-
```
|
|
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
|
-
```
|
|
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
|
-
```
|
|
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
|
-
```
|
|
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
|
-
```
|
|
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
|
-
```
|
|
176
|
-
|
|
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.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A functional JavaScript component library with composable architecture based on Material Design 3",
|
|
5
|
-
"keywords": [
|
|
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
|
+
"dependencies": {
|
|
27
|
+
"typedoc": "^0.27.9"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/components/button/
|
|
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.
|
|
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,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
|
+
}
|