@deay/ui 0.0.1 → 0.0.3
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 +216 -0
- package/fesm2022/deay-ui.mjs +186 -0
- package/fesm2022/deay-ui.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/button/button.component.d.ts +12 -0
- package/{src/lib/button/button.variants.ts → lib/button/button.variants.d.ts} +0 -1
- package/lib/input/input.component.d.ts +26 -0
- package/package.json +6 -5
- package/{src/public-api.ts → public-api.d.ts} +0 -5
- package/ng-package.json +0 -7
- package/src/lib/button/button.component.ts +0 -153
- package/src/lib/input/input.component.ts +0 -209
- package/tsconfig.lib.json +0 -12
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# @deay/ui
|
|
2
|
+
|
|
3
|
+
A modern Angular UI component library built with Angular 19+, following Figma design specifications. Features accessible, customizable components with signal inputs and zoneless-ready architecture.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Angular 19+ with standalone components
|
|
8
|
+
- Signal inputs for reactivity
|
|
9
|
+
- Zoneless-ready with OnPush change detection
|
|
10
|
+
- Full accessibility support (ARIA)
|
|
11
|
+
- Three size variants (sm, md, lg)
|
|
12
|
+
- Comprehensive error and disabled states
|
|
13
|
+
- Figma design specifications
|
|
14
|
+
- TypeScript support
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @deay/ui
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Requirements
|
|
23
|
+
|
|
24
|
+
- Angular 19.0.0 or higher
|
|
25
|
+
- @angular/common 19.0.0 or higher
|
|
26
|
+
- @angular/forms 19.0.0 or higher
|
|
27
|
+
|
|
28
|
+
## Available Components
|
|
29
|
+
|
|
30
|
+
### Button Component (`<dai-button>`)
|
|
31
|
+
|
|
32
|
+
A versatile button component with loading states and multiple sizes.
|
|
33
|
+
|
|
34
|
+
**Selector:** `dai-button`
|
|
35
|
+
|
|
36
|
+
**Inputs:**
|
|
37
|
+
- `variant`: `'primary'` (default) - Visual style variant
|
|
38
|
+
- `size`: `'sm' | 'md' | 'lg'` (default: `'md'`) - Button size
|
|
39
|
+
- `disabled`: `boolean` (default: `false`) - Disable the button
|
|
40
|
+
- `loading`: `boolean` (default: `false`) - Show loading spinner
|
|
41
|
+
|
|
42
|
+
**Usage:**
|
|
43
|
+
|
|
44
|
+
```html
|
|
45
|
+
<!-- Standard button -->
|
|
46
|
+
<dai-button size="md">
|
|
47
|
+
Button
|
|
48
|
+
</dai-button>
|
|
49
|
+
|
|
50
|
+
<!-- All sizes -->
|
|
51
|
+
<dai-button size="sm">Button</dai-button>
|
|
52
|
+
<dai-button size="md">Button</dai-button>
|
|
53
|
+
<dai-button size="lg">Button</dai-button>
|
|
54
|
+
|
|
55
|
+
<!-- Loading state -->
|
|
56
|
+
<dai-button size="md" [loading]="true">
|
|
57
|
+
Button
|
|
58
|
+
</dai-button>
|
|
59
|
+
|
|
60
|
+
<!-- Disabled state -->
|
|
61
|
+
<dai-button size="md" [disabled]="true">
|
|
62
|
+
Button
|
|
63
|
+
</dai-button>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Design Specifications:**
|
|
67
|
+
- Font: Poppins, weight 400
|
|
68
|
+
- Border radius: 50px (fully rounded)
|
|
69
|
+
- Size heights: sm (24px, 12px font), md (32px, 14px font), lg (40px, 16px font)
|
|
70
|
+
- Hover: Primary/600 (#5164F7)
|
|
71
|
+
- Focus: Primary/800 border (#112EAC)
|
|
72
|
+
- Disabled: Primary/400 (#9098FA)
|
|
73
|
+
- Loading: Primary/500 (#6B7FFF)
|
|
74
|
+
|
|
75
|
+
### Input Component (`<dai-input>`)
|
|
76
|
+
|
|
77
|
+
A feature-rich input component with validation states and Angular Forms integration.
|
|
78
|
+
|
|
79
|
+
**Selector:** `dai-input`
|
|
80
|
+
|
|
81
|
+
**Inputs:**
|
|
82
|
+
- `label`: `string` - Label text displayed above input
|
|
83
|
+
- `placeholder`: `string` (default: `'Text'`) - Placeholder text
|
|
84
|
+
- `type`: `'text' | 'password' | 'email'` (default: `'text'`) - HTML input type
|
|
85
|
+
- `size`: `'sm' | 'md' | 'lg'` (default: `'md'`) - Input size
|
|
86
|
+
- `disabled`: `boolean` (default: `false`) - Disable the input
|
|
87
|
+
- `errorMessage`: `string` - Error message that triggers error styling
|
|
88
|
+
- `value`: `string` - Two-way bound value (Angular 19+ model)
|
|
89
|
+
|
|
90
|
+
**Usage:**
|
|
91
|
+
|
|
92
|
+
```html
|
|
93
|
+
<!-- Basic input -->
|
|
94
|
+
<dai-input
|
|
95
|
+
label="Label"
|
|
96
|
+
size="md"
|
|
97
|
+
placeholder="Text"
|
|
98
|
+
/>
|
|
99
|
+
|
|
100
|
+
<!-- All sizes -->
|
|
101
|
+
<dai-input label="Small" size="sm" placeholder="Text" />
|
|
102
|
+
<dai-input label="Medium" size="md" placeholder="Text" />
|
|
103
|
+
<dai-input label="Large" size="lg" placeholder="Text" />
|
|
104
|
+
|
|
105
|
+
<!-- Error state -->
|
|
106
|
+
<dai-input
|
|
107
|
+
label="Email"
|
|
108
|
+
size="md"
|
|
109
|
+
placeholder="Text"
|
|
110
|
+
[errorMessage]="'Invalid email format'"
|
|
111
|
+
/>
|
|
112
|
+
|
|
113
|
+
<!-- Disabled state -->
|
|
114
|
+
<dai-input
|
|
115
|
+
label="Label"
|
|
116
|
+
size="md"
|
|
117
|
+
placeholder="Text"
|
|
118
|
+
[disabled]="true"
|
|
119
|
+
/>
|
|
120
|
+
|
|
121
|
+
<!-- Two-way binding -->
|
|
122
|
+
<dai-input
|
|
123
|
+
label="Email"
|
|
124
|
+
size="md"
|
|
125
|
+
placeholder="Text"
|
|
126
|
+
[(value)]="email"
|
|
127
|
+
/>
|
|
128
|
+
|
|
129
|
+
<!-- Reactive forms -->
|
|
130
|
+
<dai-input
|
|
131
|
+
label="Email"
|
|
132
|
+
size="md"
|
|
133
|
+
[formControl]="emailControl"
|
|
134
|
+
[errorMessage]="emailControl.errors ? 'Error Message' : ''"
|
|
135
|
+
/>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Design Specifications:**
|
|
139
|
+
- Font: Poppins, weight 400
|
|
140
|
+
- Border radius: 50px (fully rounded)
|
|
141
|
+
- Label: 16px, color #000000
|
|
142
|
+
- Input text: 14px, placeholder #ABA7AF
|
|
143
|
+
- Default border: #E5E0EB (1px)
|
|
144
|
+
- Focus border sm: #061764 (2px)
|
|
145
|
+
- Focus border md/lg: #112EAC (1px)
|
|
146
|
+
- Error border: #D51A52 (2px)
|
|
147
|
+
- Error text: #D51A52, 14px
|
|
148
|
+
- Disabled: #DFDFDF background and border
|
|
149
|
+
- Heights: sm (~36px), md (44px), lg (50px)
|
|
150
|
+
- Gap between elements: 8px
|
|
151
|
+
|
|
152
|
+
## Best Practices
|
|
153
|
+
|
|
154
|
+
### Button
|
|
155
|
+
- Use `size="sm"` for dense UI areas and tables
|
|
156
|
+
- Use `size="md"` for standard buttons (default)
|
|
157
|
+
- Use `size="lg"` for prominent call-to-action buttons
|
|
158
|
+
- Loading state automatically disables the button
|
|
159
|
+
- Always provide accessible button text
|
|
160
|
+
|
|
161
|
+
### Input
|
|
162
|
+
- Always provide labels for accessibility
|
|
163
|
+
- Use appropriate input types for better mobile experience
|
|
164
|
+
- Connect error messages to form validation
|
|
165
|
+
- Use size="sm" for compact forms
|
|
166
|
+
- Use size="md" for standard forms (default)
|
|
167
|
+
- Use size="lg" for prominent inputs
|
|
168
|
+
|
|
169
|
+
## Development
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
# Install dependencies
|
|
173
|
+
npm install
|
|
174
|
+
|
|
175
|
+
# Build the library
|
|
176
|
+
npm run build
|
|
177
|
+
|
|
178
|
+
# Watch mode for development
|
|
179
|
+
npm run dev
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Build Output
|
|
183
|
+
|
|
184
|
+
The library builds to the `dist/` directory using ng-packagr and includes:
|
|
185
|
+
- Angular library format
|
|
186
|
+
- TypeScript definitions
|
|
187
|
+
- Metadata
|
|
188
|
+
- Styles
|
|
189
|
+
|
|
190
|
+
## Accessibility
|
|
191
|
+
|
|
192
|
+
All components follow WCAG 2.1 guidelines:
|
|
193
|
+
- Proper ARIA attributes
|
|
194
|
+
- Keyboard navigation support
|
|
195
|
+
- Focus indicators
|
|
196
|
+
- Screen reader support
|
|
197
|
+
- Semantic HTML
|
|
198
|
+
|
|
199
|
+
## Browser Support
|
|
200
|
+
|
|
201
|
+
- Chrome (latest)
|
|
202
|
+
- Firefox (latest)
|
|
203
|
+
- Safari (latest)
|
|
204
|
+
- Edge (latest)
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
|
209
|
+
|
|
210
|
+
## Contributing
|
|
211
|
+
|
|
212
|
+
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
|
|
213
|
+
|
|
214
|
+
## Related Packages
|
|
215
|
+
|
|
216
|
+
- [@deay/mcp](../mcp-server) - MCP server providing AI assistants with @deay/ui component documentation
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, computed, Component, model, output, forwardRef } from '@angular/core';
|
|
3
|
+
import { CommonModule } from '@angular/common';
|
|
4
|
+
import { NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
5
|
+
|
|
6
|
+
class DaiButtonComponent {
|
|
7
|
+
// Signal Inputs (Angular 19+)
|
|
8
|
+
variant = input('primary');
|
|
9
|
+
size = input('md');
|
|
10
|
+
disabled = input(false);
|
|
11
|
+
loading = input(false);
|
|
12
|
+
// Computed properties for dynamic classes
|
|
13
|
+
computedClasses = computed(() => {
|
|
14
|
+
const classes = [
|
|
15
|
+
'dai-button',
|
|
16
|
+
`dai-button-${this.variant()}`,
|
|
17
|
+
`dai-button-${this.size()}`,
|
|
18
|
+
];
|
|
19
|
+
if (this.loading()) {
|
|
20
|
+
classes.push('dai-button-loading');
|
|
21
|
+
}
|
|
22
|
+
return classes.join(' ');
|
|
23
|
+
});
|
|
24
|
+
// Computed disabled state (disabled or loading)
|
|
25
|
+
isDisabled = computed(() => this.disabled() || this.loading());
|
|
26
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DaiButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
27
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: DaiButtonComponent, isStandalone: true, selector: "dai-button", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
28
|
+
<button
|
|
29
|
+
[class]="computedClasses()"
|
|
30
|
+
[disabled]="isDisabled()"
|
|
31
|
+
[attr.aria-disabled]="isDisabled()"
|
|
32
|
+
[attr.aria-busy]="loading()"
|
|
33
|
+
>
|
|
34
|
+
@if (loading()) {
|
|
35
|
+
<span class="dai-spinner" aria-hidden="true"></span>
|
|
36
|
+
}
|
|
37
|
+
<ng-content />
|
|
38
|
+
</button>
|
|
39
|
+
`, isInline: true, styles: [":host{display:inline-block}button{display:inline-flex;align-items:center;justify-content:center;gap:4px;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:400;line-height:1.5;border-radius:50px;cursor:pointer;transition:all .15s ease-in-out;border:1px solid transparent;box-sizing:border-box}button:focus-visible{outline:none}button:disabled{cursor:not-allowed;opacity:1}.dai-button-sm{padding:2px 8px;height:24px;font-size:12px;line-height:1.5em}.dai-button-md{padding:6px 12px;height:32px;font-size:14px;line-height:1.4285714285714286em}.dai-button-lg{padding:8px 16px;height:40px;font-size:16px;line-height:1.375em}.dai-button-primary{background-color:#2047f4;color:#fff}.dai-button-primary:hover:not(:disabled){background-color:#5164f7}.dai-button-primary:focus-visible{background-color:#2047f4;border-color:#112eac;box-shadow:0 0 0 1px #112eac}.dai-button-primary:disabled,.dai-button-primary.dai-button-loading{background-color:#9098fa}.dai-button-primary.dai-button-loading{cursor:wait}.dai-button-sm .dai-spinner{width:14px;height:14px}.dai-button-md .dai-spinner{width:16px;height:16px}.dai-button-lg .dai-spinner{width:22px;height:22px}.dai-spinner{display:inline-block;border:2px solid #FFFFFF;border-right-color:transparent;border-radius:50%;animation:dai-spin .6s linear infinite}@keyframes dai-spin{to{transform:rotate(360deg)}}\n"] });
|
|
40
|
+
}
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DaiButtonComponent, decorators: [{
|
|
42
|
+
type: Component,
|
|
43
|
+
args: [{ selector: 'dai-button', standalone: true, template: `
|
|
44
|
+
<button
|
|
45
|
+
[class]="computedClasses()"
|
|
46
|
+
[disabled]="isDisabled()"
|
|
47
|
+
[attr.aria-disabled]="isDisabled()"
|
|
48
|
+
[attr.aria-busy]="loading()"
|
|
49
|
+
>
|
|
50
|
+
@if (loading()) {
|
|
51
|
+
<span class="dai-spinner" aria-hidden="true"></span>
|
|
52
|
+
}
|
|
53
|
+
<ng-content />
|
|
54
|
+
</button>
|
|
55
|
+
`, styles: [":host{display:inline-block}button{display:inline-flex;align-items:center;justify-content:center;gap:4px;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-weight:400;line-height:1.5;border-radius:50px;cursor:pointer;transition:all .15s ease-in-out;border:1px solid transparent;box-sizing:border-box}button:focus-visible{outline:none}button:disabled{cursor:not-allowed;opacity:1}.dai-button-sm{padding:2px 8px;height:24px;font-size:12px;line-height:1.5em}.dai-button-md{padding:6px 12px;height:32px;font-size:14px;line-height:1.4285714285714286em}.dai-button-lg{padding:8px 16px;height:40px;font-size:16px;line-height:1.375em}.dai-button-primary{background-color:#2047f4;color:#fff}.dai-button-primary:hover:not(:disabled){background-color:#5164f7}.dai-button-primary:focus-visible{background-color:#2047f4;border-color:#112eac;box-shadow:0 0 0 1px #112eac}.dai-button-primary:disabled,.dai-button-primary.dai-button-loading{background-color:#9098fa}.dai-button-primary.dai-button-loading{cursor:wait}.dai-button-sm .dai-spinner{width:14px;height:14px}.dai-button-md .dai-spinner{width:16px;height:16px}.dai-button-lg .dai-spinner{width:22px;height:22px}.dai-spinner{display:inline-block;border:2px solid #FFFFFF;border-right-color:transparent;border-radius:50%;animation:dai-spin .6s linear infinite}@keyframes dai-spin{to{transform:rotate(360deg)}}\n"] }]
|
|
56
|
+
}] });
|
|
57
|
+
|
|
58
|
+
class DaiInputComponent {
|
|
59
|
+
// Signal Inputs
|
|
60
|
+
label = input('');
|
|
61
|
+
placeholder = input('Text');
|
|
62
|
+
type = input('text');
|
|
63
|
+
disabled = input(false);
|
|
64
|
+
errorMessage = input('');
|
|
65
|
+
size = input('md');
|
|
66
|
+
inputId = input(`dai-input-${Math.random().toString(36).substr(2, 9)}`);
|
|
67
|
+
// Model for two-way binding (Angular 19+)
|
|
68
|
+
value = model('');
|
|
69
|
+
// Outputs for custom handling
|
|
70
|
+
valueChange = output();
|
|
71
|
+
blur = output();
|
|
72
|
+
// Internal state
|
|
73
|
+
onChange = () => { };
|
|
74
|
+
onTouched = () => { };
|
|
75
|
+
// Computed error state
|
|
76
|
+
hasError = computed(() => !!this.errorMessage());
|
|
77
|
+
// Unique error message ID
|
|
78
|
+
errorId = () => `${this.inputId()}-error`;
|
|
79
|
+
// Handle input changes
|
|
80
|
+
onInput(event) {
|
|
81
|
+
const target = event.target;
|
|
82
|
+
const newValue = target.value;
|
|
83
|
+
this.value.set(newValue);
|
|
84
|
+
this.onChange(newValue);
|
|
85
|
+
this.valueChange.emit(newValue);
|
|
86
|
+
}
|
|
87
|
+
// ControlValueAccessor implementation
|
|
88
|
+
writeValue(value) {
|
|
89
|
+
this.value.set(value || '');
|
|
90
|
+
}
|
|
91
|
+
registerOnChange(fn) {
|
|
92
|
+
this.onChange = fn;
|
|
93
|
+
}
|
|
94
|
+
registerOnTouched(fn) {
|
|
95
|
+
this.onTouched = fn;
|
|
96
|
+
}
|
|
97
|
+
setDisabledState(isDisabled) {
|
|
98
|
+
// Handled through the disabled input signal
|
|
99
|
+
}
|
|
100
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DaiInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
101
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: DaiInputComponent, isStandalone: true, selector: "dai-input", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", valueChange: "valueChange", blur: "blur" }, providers: [
|
|
102
|
+
{
|
|
103
|
+
provide: NG_VALUE_ACCESSOR,
|
|
104
|
+
useExisting: forwardRef(() => DaiInputComponent),
|
|
105
|
+
multi: true,
|
|
106
|
+
},
|
|
107
|
+
], ngImport: i0, template: `
|
|
108
|
+
<div class="dai-input-wrapper" [class.dai-input-error]="hasError()">
|
|
109
|
+
<label [for]="inputId()" class="dai-input-label">
|
|
110
|
+
{{ label() }}
|
|
111
|
+
</label>
|
|
112
|
+
|
|
113
|
+
<input
|
|
114
|
+
[id]="inputId()"
|
|
115
|
+
[type]="type()"
|
|
116
|
+
[placeholder]="placeholder()"
|
|
117
|
+
[value]="value()"
|
|
118
|
+
(input)="onInput($event)"
|
|
119
|
+
(blur)="onTouched()"
|
|
120
|
+
[disabled]="disabled()"
|
|
121
|
+
[class.dai-input-field]="true"
|
|
122
|
+
[class.dai-input-sm]="size() === 'sm'"
|
|
123
|
+
[class.dai-input-md]="size() === 'md'"
|
|
124
|
+
[class.dai-input-lg]="size() === 'lg'"
|
|
125
|
+
[attr.aria-invalid]="hasError()"
|
|
126
|
+
[attr.aria-describedby]="hasError() ? errorId() : null"
|
|
127
|
+
/>
|
|
128
|
+
|
|
129
|
+
@if (hasError() && errorMessage()) {
|
|
130
|
+
<span [id]="errorId()" class="dai-input-error-message" role="alert">
|
|
131
|
+
{{ errorMessage() }}
|
|
132
|
+
</span>
|
|
133
|
+
}
|
|
134
|
+
</div>
|
|
135
|
+
`, isInline: true, styles: [":host{display:block;width:100%}.dai-input-wrapper{display:flex;flex-direction:column;gap:8px;width:100%}.dai-input-label{display:block;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-size:16px;font-weight:400;line-height:1.5em;color:#000}.dai-input-field{width:100%;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:400;line-height:1.5em;color:#000;background-color:#fff;border:1px solid #E5E0EB;border-radius:50px;box-sizing:border-box;outline:none;transition:all .15s ease-in-out}.dai-input-field::placeholder{color:#aba7af}.dai-input-sm{padding:8px 12px}.dai-input-md{padding:12px;height:44px}.dai-input-lg{padding:14px 12px;height:50px}.dai-input-sm:focus{border-color:#061764;border-width:2px;padding:7px 11px}.dai-input-md:focus,.dai-input-lg:focus{border-color:#112eac;border-width:1px}.dai-input-field:disabled{background-color:#dfdfdf;border-color:#dfdfdf;color:#aba7af;cursor:not-allowed}.dai-input-error .dai-input-field{border-color:#d51a52;border-width:2px}.dai-input-error .dai-input-sm{padding:7px 11px}.dai-input-error .dai-input-md{padding:11px}.dai-input-error .dai-input-lg{padding:13px 11px}.dai-input-error-message{display:block;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:400;line-height:1.5em;color:#d51a52}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] });
|
|
136
|
+
}
|
|
137
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: DaiInputComponent, decorators: [{
|
|
138
|
+
type: Component,
|
|
139
|
+
args: [{ selector: 'dai-input', standalone: true, imports: [CommonModule], template: `
|
|
140
|
+
<div class="dai-input-wrapper" [class.dai-input-error]="hasError()">
|
|
141
|
+
<label [for]="inputId()" class="dai-input-label">
|
|
142
|
+
{{ label() }}
|
|
143
|
+
</label>
|
|
144
|
+
|
|
145
|
+
<input
|
|
146
|
+
[id]="inputId()"
|
|
147
|
+
[type]="type()"
|
|
148
|
+
[placeholder]="placeholder()"
|
|
149
|
+
[value]="value()"
|
|
150
|
+
(input)="onInput($event)"
|
|
151
|
+
(blur)="onTouched()"
|
|
152
|
+
[disabled]="disabled()"
|
|
153
|
+
[class.dai-input-field]="true"
|
|
154
|
+
[class.dai-input-sm]="size() === 'sm'"
|
|
155
|
+
[class.dai-input-md]="size() === 'md'"
|
|
156
|
+
[class.dai-input-lg]="size() === 'lg'"
|
|
157
|
+
[attr.aria-invalid]="hasError()"
|
|
158
|
+
[attr.aria-describedby]="hasError() ? errorId() : null"
|
|
159
|
+
/>
|
|
160
|
+
|
|
161
|
+
@if (hasError() && errorMessage()) {
|
|
162
|
+
<span [id]="errorId()" class="dai-input-error-message" role="alert">
|
|
163
|
+
{{ errorMessage() }}
|
|
164
|
+
</span>
|
|
165
|
+
}
|
|
166
|
+
</div>
|
|
167
|
+
`, providers: [
|
|
168
|
+
{
|
|
169
|
+
provide: NG_VALUE_ACCESSOR,
|
|
170
|
+
useExisting: forwardRef(() => DaiInputComponent),
|
|
171
|
+
multi: true,
|
|
172
|
+
},
|
|
173
|
+
], styles: [":host{display:block;width:100%}.dai-input-wrapper{display:flex;flex-direction:column;gap:8px;width:100%}.dai-input-label{display:block;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-size:16px;font-weight:400;line-height:1.5em;color:#000}.dai-input-field{width:100%;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:400;line-height:1.5em;color:#000;background-color:#fff;border:1px solid #E5E0EB;border-radius:50px;box-sizing:border-box;outline:none;transition:all .15s ease-in-out}.dai-input-field::placeholder{color:#aba7af}.dai-input-sm{padding:8px 12px}.dai-input-md{padding:12px;height:44px}.dai-input-lg{padding:14px 12px;height:50px}.dai-input-sm:focus{border-color:#061764;border-width:2px;padding:7px 11px}.dai-input-md:focus,.dai-input-lg:focus{border-color:#112eac;border-width:1px}.dai-input-field:disabled{background-color:#dfdfdf;border-color:#dfdfdf;color:#aba7af;cursor:not-allowed}.dai-input-error .dai-input-field{border-color:#d51a52;border-width:2px}.dai-input-error .dai-input-sm{padding:7px 11px}.dai-input-error .dai-input-md{padding:11px}.dai-input-error .dai-input-lg{padding:13px 11px}.dai-input-error-message{display:block;font-family:Poppins,-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;font-weight:400;line-height:1.5em;color:#d51a52}\n"] }]
|
|
174
|
+
}] });
|
|
175
|
+
|
|
176
|
+
/*
|
|
177
|
+
* Public API Surface of @deay/ui
|
|
178
|
+
*/
|
|
179
|
+
// Export components
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Generated bundle index. Do not edit.
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
export { DaiButtonComponent, DaiInputComponent };
|
|
186
|
+
//# sourceMappingURL=deay-ui.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deay-ui.mjs","sources":["../../src/lib/button/button.component.ts","../../src/lib/input/input.component.ts","../../src/public-api.ts","../../src/deay-ui.ts"],"sourcesContent":["import { Component, input, computed } from '@angular/core';\nimport type { CvButtonVariant, CvButtonSize } from './button.variants';\n\n@Component({\n selector: 'dai-button',\n standalone: true,\n template: `\n <button\n [class]=\"computedClasses()\"\n [disabled]=\"isDisabled()\"\n [attr.aria-disabled]=\"isDisabled()\"\n [attr.aria-busy]=\"loading()\"\n >\n @if (loading()) {\n <span class=\"dai-spinner\" aria-hidden=\"true\"></span>\n }\n <ng-content />\n </button>\n `,\n styles: [\n `\n :host {\n display: inline-block;\n }\n\n button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;\n font-weight: 400;\n line-height: 1.5;\n border-radius: 50px;\n cursor: pointer;\n transition: all 150ms ease-in-out;\n border: 1px solid transparent;\n box-sizing: border-box;\n }\n\n button:focus-visible {\n outline: none;\n }\n\n button:disabled {\n cursor: not-allowed;\n opacity: 1;\n }\n\n /* Sizes */\n .dai-button-sm {\n padding: 2px 8px;\n height: 24px;\n font-size: 12px;\n line-height: 1.5em;\n }\n\n .dai-button-md {\n padding: 6px 12px;\n height: 32px;\n font-size: 14px;\n line-height: 1.4285714285714286em;\n }\n\n .dai-button-lg {\n padding: 8px 16px;\n height: 40px;\n font-size: 16px;\n line-height: 1.375em;\n }\n\n /* Primary Variant - Default State */\n .dai-button-primary {\n background-color: #2047F4;\n color: #FFFFFF;\n }\n\n .dai-button-primary:hover:not(:disabled) {\n background-color: #5164F7;\n }\n\n .dai-button-primary:focus-visible {\n background-color: #2047F4;\n border-color: #112EAC;\n box-shadow: 0 0 0 1px #112EAC;\n }\n\n .dai-button-primary:disabled,\n .dai-button-primary.dai-button-loading {\n background-color: #9098FA;\n }\n\n .dai-button-primary.dai-button-loading {\n cursor: wait;\n }\n\n /* Spinner sizes */\n .dai-button-sm .dai-spinner {\n width: 14px;\n height: 14px;\n }\n\n .dai-button-md .dai-spinner {\n width: 16px;\n height: 16px;\n }\n\n .dai-button-lg .dai-spinner {\n width: 22px;\n height: 22px;\n }\n\n .dai-spinner {\n display: inline-block;\n border: 2px solid #FFFFFF;\n border-right-color: transparent;\n border-radius: 50%;\n animation: dai-spin 0.6s linear infinite;\n }\n\n @keyframes dai-spin {\n to {\n transform: rotate(360deg);\n }\n }\n `,\n ],\n})\nexport class DaiButtonComponent {\n // Signal Inputs (Angular 19+)\n readonly variant = input<CvButtonVariant>('primary');\n readonly size = input<CvButtonSize>('md');\n readonly disabled = input<boolean>(false);\n readonly loading = input<boolean>(false);\n\n // Computed properties for dynamic classes\n protected computedClasses = computed(() => {\n const classes = [\n 'dai-button',\n `dai-button-${this.variant()}`,\n `dai-button-${this.size()}`,\n ];\n\n if (this.loading()) {\n classes.push('dai-button-loading');\n }\n\n return classes.join(' ');\n });\n\n // Computed disabled state (disabled or loading)\n protected isDisabled = computed(() => this.disabled() || this.loading());\n}\n","import { Component, input, output, model, forwardRef, computed } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n type ControlValueAccessor,\n NG_VALUE_ACCESSOR,\n} from '@angular/forms';\n\nexport type CvInputSize = 'sm' | 'md' | 'lg';\n\n@Component({\n selector: 'dai-input',\n standalone: true,\n imports: [CommonModule],\n template: `\n <div class=\"dai-input-wrapper\" [class.dai-input-error]=\"hasError()\">\n <label [for]=\"inputId()\" class=\"dai-input-label\">\n {{ label() }}\n </label>\n\n <input\n [id]=\"inputId()\"\n [type]=\"type()\"\n [placeholder]=\"placeholder()\"\n [value]=\"value()\"\n (input)=\"onInput($event)\"\n (blur)=\"onTouched()\"\n [disabled]=\"disabled()\"\n [class.dai-input-field]=\"true\"\n [class.dai-input-sm]=\"size() === 'sm'\"\n [class.dai-input-md]=\"size() === 'md'\"\n [class.dai-input-lg]=\"size() === 'lg'\"\n [attr.aria-invalid]=\"hasError()\"\n [attr.aria-describedby]=\"hasError() ? errorId() : null\"\n />\n\n @if (hasError() && errorMessage()) {\n <span [id]=\"errorId()\" class=\"dai-input-error-message\" role=\"alert\">\n {{ errorMessage() }}\n </span>\n }\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n width: 100%;\n }\n\n .dai-input-wrapper {\n display: flex;\n flex-direction: column;\n gap: 8px;\n width: 100%;\n }\n\n .dai-input-label {\n display: block;\n font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 16px;\n font-weight: 400;\n line-height: 1.5em;\n color: #000000;\n }\n\n .dai-input-field {\n width: 100%;\n font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.5em;\n color: #000000;\n background-color: #FFFFFF;\n border: 1px solid #E5E0EB;\n border-radius: 50px;\n box-sizing: border-box;\n outline: none;\n transition: all 150ms ease-in-out;\n }\n\n .dai-input-field::placeholder {\n color: #ABA7AF;\n }\n\n /* Sizes */\n .dai-input-sm {\n padding: 8px 12px;\n }\n\n .dai-input-md {\n padding: 12px;\n height: 44px;\n }\n\n .dai-input-lg {\n padding: 14px 12px;\n height: 50px;\n }\n\n /* Focus State */\n .dai-input-sm:focus {\n border-color: #061764;\n border-width: 2px;\n padding: 7px 11px; /* Adjust for 2px border */\n }\n\n .dai-input-md:focus,\n .dai-input-lg:focus {\n border-color: #112EAC;\n border-width: 1px;\n }\n\n /* Disabled State */\n .dai-input-field:disabled {\n background-color: #DFDFDF;\n border-color: #DFDFDF;\n color: #ABA7AF;\n cursor: not-allowed;\n }\n\n /* Error State */\n .dai-input-error .dai-input-field {\n border-color: #D51A52;\n border-width: 2px;\n }\n\n .dai-input-error .dai-input-sm {\n padding: 7px 11px; /* Adjust for 2px border */\n }\n\n .dai-input-error .dai-input-md {\n padding: 11px; /* Adjust for 2px border */\n }\n\n .dai-input-error .dai-input-lg {\n padding: 13px 11px; /* Adjust for 2px border */\n }\n\n .dai-input-error-message {\n display: block;\n font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.5em;\n color: #D51A52;\n }\n `,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DaiInputComponent),\n multi: true,\n },\n ],\n})\nexport class DaiInputComponent implements ControlValueAccessor {\n // Signal Inputs\n readonly label = input<string>('');\n readonly placeholder = input<string>('Text');\n readonly type = input<'text' | 'password' | 'email'>('text');\n readonly disabled = input<boolean>(false);\n readonly errorMessage = input<string>('');\n readonly size = input<CvInputSize>('md');\n readonly inputId = input<string>(`dai-input-${Math.random().toString(36).substr(2, 9)}`);\n\n // Model for two-way binding (Angular 19+)\n readonly value = model<string>('');\n\n // Outputs for custom handling\n readonly valueChange = output<string>();\n readonly blur = output<void>();\n\n // Internal state\n private onChange: (value: string) => void = () => {};\n onTouched: () => void = () => {};\n\n // Computed error state\n protected hasError = computed(() => !!this.errorMessage());\n\n // Unique error message ID\n protected errorId = () => `${this.inputId()}-error`;\n\n // Handle input changes\n protected onInput(event: Event): void {\n const target = event.target as HTMLInputElement;\n const newValue = target.value;\n this.value.set(newValue);\n this.onChange(newValue);\n this.valueChange.emit(newValue);\n }\n\n // ControlValueAccessor implementation\n writeValue(value: string): void {\n this.value.set(value || '');\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n // Handled through the disabled input signal\n }\n}\n","/*\n * Public API Surface of @deay/ui\n */\n\n// Export components\nexport * from './lib/button/button.component';\nexport * from './lib/button/button.variants';\nexport * from './lib/input/input.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CvButtonSize } from './button.variants';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export declare class DaiButtonComponent {
|
|
4
|
+
readonly variant: import("@angular/core").InputSignal<"primary">;
|
|
5
|
+
readonly size: import("@angular/core").InputSignal<CvButtonSize>;
|
|
6
|
+
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
7
|
+
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
8
|
+
protected computedClasses: import("@angular/core").Signal<string>;
|
|
9
|
+
protected isDisabled: import("@angular/core").Signal<boolean>;
|
|
10
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DaiButtonComponent, never>;
|
|
11
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DaiButtonComponent, "dai-button", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ControlValueAccessor } from '@angular/forms';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export type CvInputSize = 'sm' | 'md' | 'lg';
|
|
4
|
+
export declare class DaiInputComponent implements ControlValueAccessor {
|
|
5
|
+
readonly label: import("@angular/core").InputSignal<string>;
|
|
6
|
+
readonly placeholder: import("@angular/core").InputSignal<string>;
|
|
7
|
+
readonly type: import("@angular/core").InputSignal<"text" | "password" | "email">;
|
|
8
|
+
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
9
|
+
readonly errorMessage: import("@angular/core").InputSignal<string>;
|
|
10
|
+
readonly size: import("@angular/core").InputSignal<CvInputSize>;
|
|
11
|
+
readonly inputId: import("@angular/core").InputSignal<string>;
|
|
12
|
+
readonly value: import("@angular/core").ModelSignal<string>;
|
|
13
|
+
readonly valueChange: import("@angular/core").OutputEmitterRef<string>;
|
|
14
|
+
readonly blur: import("@angular/core").OutputEmitterRef<void>;
|
|
15
|
+
private onChange;
|
|
16
|
+
onTouched: () => void;
|
|
17
|
+
protected hasError: import("@angular/core").Signal<boolean>;
|
|
18
|
+
protected errorId: () => string;
|
|
19
|
+
protected onInput(event: Event): void;
|
|
20
|
+
writeValue(value: string): void;
|
|
21
|
+
registerOnChange(fn: (value: string) => void): void;
|
|
22
|
+
registerOnTouched(fn: () => void): void;
|
|
23
|
+
setDisabledState(isDisabled: boolean): void;
|
|
24
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<DaiInputComponent, never>;
|
|
25
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<DaiInputComponent, "dai-input", never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "type": { "alias": "type"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "inputId": { "alias": "inputId"; "required": false; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "valueChange": "valueChange"; "blur": "blur"; }, never, never, true, never>;
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deay/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"peerDependencies": {
|
|
6
|
-
"@angular/core": "
|
|
7
|
-
"@angular/common": "
|
|
8
|
-
"@angular/forms": "
|
|
6
|
+
"@angular/core": "19.2.17",
|
|
7
|
+
"@angular/common": "19.2.17",
|
|
8
|
+
"@angular/forms": "19.2.17",
|
|
9
|
+
"zone.js": "0.15.1"
|
|
9
10
|
},
|
|
10
11
|
"dependencies": {
|
|
11
|
-
"tslib": "
|
|
12
|
+
"tslib": "2.8.1"
|
|
12
13
|
},
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "ng-packagr -p ng-package.json"
|
package/ng-package.json
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { Component, input, computed } from '@angular/core';
|
|
2
|
-
import type { CvButtonVariant, CvButtonSize } from './button.variants';
|
|
3
|
-
|
|
4
|
-
@Component({
|
|
5
|
-
selector: 'dai-button',
|
|
6
|
-
standalone: true,
|
|
7
|
-
template: `
|
|
8
|
-
<button
|
|
9
|
-
[class]="computedClasses()"
|
|
10
|
-
[disabled]="isDisabled()"
|
|
11
|
-
[attr.aria-disabled]="isDisabled()"
|
|
12
|
-
[attr.aria-busy]="loading()"
|
|
13
|
-
>
|
|
14
|
-
@if (loading()) {
|
|
15
|
-
<span class="dai-spinner" aria-hidden="true"></span>
|
|
16
|
-
}
|
|
17
|
-
<ng-content />
|
|
18
|
-
</button>
|
|
19
|
-
`,
|
|
20
|
-
styles: [
|
|
21
|
-
`
|
|
22
|
-
:host {
|
|
23
|
-
display: inline-block;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
button {
|
|
27
|
-
display: inline-flex;
|
|
28
|
-
align-items: center;
|
|
29
|
-
justify-content: center;
|
|
30
|
-
gap: 4px;
|
|
31
|
-
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
32
|
-
font-weight: 400;
|
|
33
|
-
line-height: 1.5;
|
|
34
|
-
border-radius: 50px;
|
|
35
|
-
cursor: pointer;
|
|
36
|
-
transition: all 150ms ease-in-out;
|
|
37
|
-
border: 1px solid transparent;
|
|
38
|
-
box-sizing: border-box;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
button:focus-visible {
|
|
42
|
-
outline: none;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
button:disabled {
|
|
46
|
-
cursor: not-allowed;
|
|
47
|
-
opacity: 1;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/* Sizes */
|
|
51
|
-
.dai-button-sm {
|
|
52
|
-
padding: 2px 8px;
|
|
53
|
-
height: 24px;
|
|
54
|
-
font-size: 12px;
|
|
55
|
-
line-height: 1.5em;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.dai-button-md {
|
|
59
|
-
padding: 6px 12px;
|
|
60
|
-
height: 32px;
|
|
61
|
-
font-size: 14px;
|
|
62
|
-
line-height: 1.4285714285714286em;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
.dai-button-lg {
|
|
66
|
-
padding: 8px 16px;
|
|
67
|
-
height: 40px;
|
|
68
|
-
font-size: 16px;
|
|
69
|
-
line-height: 1.375em;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/* Primary Variant - Default State */
|
|
73
|
-
.dai-button-primary {
|
|
74
|
-
background-color: #2047F4;
|
|
75
|
-
color: #FFFFFF;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.dai-button-primary:hover:not(:disabled) {
|
|
79
|
-
background-color: #5164F7;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.dai-button-primary:focus-visible {
|
|
83
|
-
background-color: #2047F4;
|
|
84
|
-
border-color: #112EAC;
|
|
85
|
-
box-shadow: 0 0 0 1px #112EAC;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
.dai-button-primary:disabled,
|
|
89
|
-
.dai-button-primary.dai-button-loading {
|
|
90
|
-
background-color: #9098FA;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.dai-button-primary.dai-button-loading {
|
|
94
|
-
cursor: wait;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/* Spinner sizes */
|
|
98
|
-
.dai-button-sm .dai-spinner {
|
|
99
|
-
width: 14px;
|
|
100
|
-
height: 14px;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
.dai-button-md .dai-spinner {
|
|
104
|
-
width: 16px;
|
|
105
|
-
height: 16px;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
.dai-button-lg .dai-spinner {
|
|
109
|
-
width: 22px;
|
|
110
|
-
height: 22px;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
.dai-spinner {
|
|
114
|
-
display: inline-block;
|
|
115
|
-
border: 2px solid #FFFFFF;
|
|
116
|
-
border-right-color: transparent;
|
|
117
|
-
border-radius: 50%;
|
|
118
|
-
animation: dai-spin 0.6s linear infinite;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
@keyframes dai-spin {
|
|
122
|
-
to {
|
|
123
|
-
transform: rotate(360deg);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
`,
|
|
127
|
-
],
|
|
128
|
-
})
|
|
129
|
-
export class DaiButtonComponent {
|
|
130
|
-
// Signal Inputs (Angular 19+)
|
|
131
|
-
readonly variant = input<CvButtonVariant>('primary');
|
|
132
|
-
readonly size = input<CvButtonSize>('md');
|
|
133
|
-
readonly disabled = input<boolean>(false);
|
|
134
|
-
readonly loading = input<boolean>(false);
|
|
135
|
-
|
|
136
|
-
// Computed properties for dynamic classes
|
|
137
|
-
protected computedClasses = computed(() => {
|
|
138
|
-
const classes = [
|
|
139
|
-
'dai-button',
|
|
140
|
-
`dai-button-${this.variant()}`,
|
|
141
|
-
`dai-button-${this.size()}`,
|
|
142
|
-
];
|
|
143
|
-
|
|
144
|
-
if (this.loading()) {
|
|
145
|
-
classes.push('dai-button-loading');
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return classes.join(' ');
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
// Computed disabled state (disabled or loading)
|
|
152
|
-
protected isDisabled = computed(() => this.disabled() || this.loading());
|
|
153
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { Component, input, output, model, forwardRef, computed } from '@angular/core';
|
|
2
|
-
import { CommonModule } from '@angular/common';
|
|
3
|
-
import {
|
|
4
|
-
type ControlValueAccessor,
|
|
5
|
-
NG_VALUE_ACCESSOR,
|
|
6
|
-
} from '@angular/forms';
|
|
7
|
-
|
|
8
|
-
export type CvInputSize = 'sm' | 'md' | 'lg';
|
|
9
|
-
|
|
10
|
-
@Component({
|
|
11
|
-
selector: 'dai-input',
|
|
12
|
-
standalone: true,
|
|
13
|
-
imports: [CommonModule],
|
|
14
|
-
template: `
|
|
15
|
-
<div class="dai-input-wrapper" [class.dai-input-error]="hasError()">
|
|
16
|
-
<label [for]="inputId()" class="dai-input-label">
|
|
17
|
-
{{ label() }}
|
|
18
|
-
</label>
|
|
19
|
-
|
|
20
|
-
<input
|
|
21
|
-
[id]="inputId()"
|
|
22
|
-
[type]="type()"
|
|
23
|
-
[placeholder]="placeholder()"
|
|
24
|
-
[value]="value()"
|
|
25
|
-
(input)="onInput($event)"
|
|
26
|
-
(blur)="onTouched()"
|
|
27
|
-
[disabled]="disabled()"
|
|
28
|
-
[class.dai-input-field]="true"
|
|
29
|
-
[class.dai-input-sm]="size() === 'sm'"
|
|
30
|
-
[class.dai-input-md]="size() === 'md'"
|
|
31
|
-
[class.dai-input-lg]="size() === 'lg'"
|
|
32
|
-
[attr.aria-invalid]="hasError()"
|
|
33
|
-
[attr.aria-describedby]="hasError() ? errorId() : null"
|
|
34
|
-
/>
|
|
35
|
-
|
|
36
|
-
@if (hasError() && errorMessage()) {
|
|
37
|
-
<span [id]="errorId()" class="dai-input-error-message" role="alert">
|
|
38
|
-
{{ errorMessage() }}
|
|
39
|
-
</span>
|
|
40
|
-
}
|
|
41
|
-
</div>
|
|
42
|
-
`,
|
|
43
|
-
styles: [
|
|
44
|
-
`
|
|
45
|
-
:host {
|
|
46
|
-
display: block;
|
|
47
|
-
width: 100%;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.dai-input-wrapper {
|
|
51
|
-
display: flex;
|
|
52
|
-
flex-direction: column;
|
|
53
|
-
gap: 8px;
|
|
54
|
-
width: 100%;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.dai-input-label {
|
|
58
|
-
display: block;
|
|
59
|
-
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
60
|
-
font-size: 16px;
|
|
61
|
-
font-weight: 400;
|
|
62
|
-
line-height: 1.5em;
|
|
63
|
-
color: #000000;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.dai-input-field {
|
|
67
|
-
width: 100%;
|
|
68
|
-
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
69
|
-
font-size: 14px;
|
|
70
|
-
font-weight: 400;
|
|
71
|
-
line-height: 1.5em;
|
|
72
|
-
color: #000000;
|
|
73
|
-
background-color: #FFFFFF;
|
|
74
|
-
border: 1px solid #E5E0EB;
|
|
75
|
-
border-radius: 50px;
|
|
76
|
-
box-sizing: border-box;
|
|
77
|
-
outline: none;
|
|
78
|
-
transition: all 150ms ease-in-out;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.dai-input-field::placeholder {
|
|
82
|
-
color: #ABA7AF;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/* Sizes */
|
|
86
|
-
.dai-input-sm {
|
|
87
|
-
padding: 8px 12px;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.dai-input-md {
|
|
91
|
-
padding: 12px;
|
|
92
|
-
height: 44px;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.dai-input-lg {
|
|
96
|
-
padding: 14px 12px;
|
|
97
|
-
height: 50px;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/* Focus State */
|
|
101
|
-
.dai-input-sm:focus {
|
|
102
|
-
border-color: #061764;
|
|
103
|
-
border-width: 2px;
|
|
104
|
-
padding: 7px 11px; /* Adjust for 2px border */
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.dai-input-md:focus,
|
|
108
|
-
.dai-input-lg:focus {
|
|
109
|
-
border-color: #112EAC;
|
|
110
|
-
border-width: 1px;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/* Disabled State */
|
|
114
|
-
.dai-input-field:disabled {
|
|
115
|
-
background-color: #DFDFDF;
|
|
116
|
-
border-color: #DFDFDF;
|
|
117
|
-
color: #ABA7AF;
|
|
118
|
-
cursor: not-allowed;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* Error State */
|
|
122
|
-
.dai-input-error .dai-input-field {
|
|
123
|
-
border-color: #D51A52;
|
|
124
|
-
border-width: 2px;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.dai-input-error .dai-input-sm {
|
|
128
|
-
padding: 7px 11px; /* Adjust for 2px border */
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.dai-input-error .dai-input-md {
|
|
132
|
-
padding: 11px; /* Adjust for 2px border */
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
.dai-input-error .dai-input-lg {
|
|
136
|
-
padding: 13px 11px; /* Adjust for 2px border */
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.dai-input-error-message {
|
|
140
|
-
display: block;
|
|
141
|
-
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
142
|
-
font-size: 14px;
|
|
143
|
-
font-weight: 400;
|
|
144
|
-
line-height: 1.5em;
|
|
145
|
-
color: #D51A52;
|
|
146
|
-
}
|
|
147
|
-
`,
|
|
148
|
-
],
|
|
149
|
-
providers: [
|
|
150
|
-
{
|
|
151
|
-
provide: NG_VALUE_ACCESSOR,
|
|
152
|
-
useExisting: forwardRef(() => DaiInputComponent),
|
|
153
|
-
multi: true,
|
|
154
|
-
},
|
|
155
|
-
],
|
|
156
|
-
})
|
|
157
|
-
export class DaiInputComponent implements ControlValueAccessor {
|
|
158
|
-
// Signal Inputs
|
|
159
|
-
readonly label = input<string>('');
|
|
160
|
-
readonly placeholder = input<string>('Text');
|
|
161
|
-
readonly type = input<'text' | 'password' | 'email'>('text');
|
|
162
|
-
readonly disabled = input<boolean>(false);
|
|
163
|
-
readonly errorMessage = input<string>('');
|
|
164
|
-
readonly size = input<CvInputSize>('md');
|
|
165
|
-
readonly inputId = input<string>(`dai-input-${Math.random().toString(36).substr(2, 9)}`);
|
|
166
|
-
|
|
167
|
-
// Model for two-way binding (Angular 19+)
|
|
168
|
-
readonly value = model<string>('');
|
|
169
|
-
|
|
170
|
-
// Outputs for custom handling
|
|
171
|
-
readonly valueChange = output<string>();
|
|
172
|
-
readonly blur = output<void>();
|
|
173
|
-
|
|
174
|
-
// Internal state
|
|
175
|
-
private onChange: (value: string) => void = () => {};
|
|
176
|
-
onTouched: () => void = () => {};
|
|
177
|
-
|
|
178
|
-
// Computed error state
|
|
179
|
-
protected hasError = computed(() => !!this.errorMessage());
|
|
180
|
-
|
|
181
|
-
// Unique error message ID
|
|
182
|
-
protected errorId = () => `${this.inputId()}-error`;
|
|
183
|
-
|
|
184
|
-
// Handle input changes
|
|
185
|
-
protected onInput(event: Event): void {
|
|
186
|
-
const target = event.target as HTMLInputElement;
|
|
187
|
-
const newValue = target.value;
|
|
188
|
-
this.value.set(newValue);
|
|
189
|
-
this.onChange(newValue);
|
|
190
|
-
this.valueChange.emit(newValue);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// ControlValueAccessor implementation
|
|
194
|
-
writeValue(value: string): void {
|
|
195
|
-
this.value.set(value || '');
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
registerOnChange(fn: (value: string) => void): void {
|
|
199
|
-
this.onChange = fn;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
registerOnTouched(fn: () => void): void {
|
|
203
|
-
this.onTouched = fn;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
setDisabledState(isDisabled: boolean): void {
|
|
207
|
-
// Handled through the disabled input signal
|
|
208
|
-
}
|
|
209
|
-
}
|
package/tsconfig.lib.json
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extends": "../../tsconfig.base.json",
|
|
3
|
-
"compilerOptions": {
|
|
4
|
-
"outDir": "../../dist/out-tsc/packages/ui",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"declarationMap": true,
|
|
7
|
-
"inlineSources": true,
|
|
8
|
-
"types": []
|
|
9
|
-
},
|
|
10
|
-
"include": ["src/**/*.ts"],
|
|
11
|
-
"exclude": ["src/test.ts", "**/*.spec.ts"]
|
|
12
|
-
}
|