@eagami/ui 0.2.0 → 0.3.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 +238 -238
- package/fesm2022/eagami-ui.mjs +1135 -133
- package/fesm2022/eagami-ui.mjs.map +1 -1
- package/package.json +9 -17
- package/src/styles/_tooltip.scss +29 -0
- package/src/styles/eagami-ui.scss +1 -0
- package/types/eagami-ui.d.ts +279 -5
package/README.md
CHANGED
|
@@ -1,388 +1,388 @@
|
|
|
1
|
-
# @eagami/ui
|
|
2
|
-
|
|
3
|
-
A lightweight, accessible Angular UI component library built on CSS custom properties. Zero runtime dependencies beyond Angular itself.
|
|
4
|
-
|
|
5
1
|
<p align="center">
|
|
6
|
-
<img src="
|
|
2
|
+
<img src="docs/images/header.png" alt="eagami design system — elegant web design." width="560" />
|
|
7
3
|
</p>
|
|
8
4
|
|
|
5
|
+
A lightweight, accessible Angular component library built on CSS custom properties. Ready to use out of the box — install, import, and start building.
|
|
6
|
+
|
|
7
|
+
Every component is standalone, signal-based, and fully themed via design tokens. No wrapping modules, no complex setup, no runtime style conflicts. Designed to be AI-friendly with clear APIs, consistent patterns, and comprehensive documentation that makes it easy for both developers and AI assistants to work with.
|
|
8
|
+
|
|
9
9
|
## Why @eagami/ui?
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**Approx. component sizes (gzipped)¹**
|
|
12
|
+
|
|
13
|
+
| Component | **@eagami/ui** | Angular Material | PrimeNG | ng-bootstrap | ng-zorro |
|
|
12
14
|
|---|---|---|---|---|---|
|
|
13
|
-
|
|
|
14
|
-
|
|
|
15
|
-
|
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
| Runtime dependencies | 0 | CDK + animations | PrimeIcons² | Bootstrap CSS | CDK |
|
|
15
|
+
| Button | ~2 KB | ~12 KB | ~8 KB | ~10 KB | ~18 KB |
|
|
16
|
+
| Input | ~4 KB | ~25 KB | ~14 KB | ~20 KB | ~35 KB |
|
|
17
|
+
| Checkbox | ~2 KB | ~15 KB | ~9 KB | ~12 KB | ~22 KB |
|
|
18
|
+
| Dropdown / Select | ~4 KB | ~30 KB | ~20 KB | ~25 KB | ~40 KB |
|
|
19
|
+
| Dialog / Modal | ~2 KB | ~20 KB | ~15 KB | ~18 KB | ~30 KB |
|
|
19
20
|
|
|
20
|
-
> ¹
|
|
21
|
+
> ¹ Approximate — depends on configuration, tree-shaking, and Angular version. @eagami/ui sizes measured from production build.
|
|
21
22
|
|
|
23
|
+
| | **@eagami/ui** | Angular Material | PrimeNG | ng-bootstrap | ng-zorro |
|
|
24
|
+
|---|---|---|---|---|---|
|
|
25
|
+
| External CSS dependency | No | No | Optional | Bootstrap (~30 KB) | No |
|
|
26
|
+
| CSS custom property theming | Yes | Partial (MDC) | Yes | No (Sass vars) | No |
|
|
27
|
+
| Signals-first API | Yes | Partial | No | No | No |
|
|
28
|
+
| `OnPush` by default | Yes | Partial | No | No | No |
|
|
29
|
+
| Runtime dependencies | 0 | CDK + animations | PrimeIcons² | Bootstrap CSS | CDK |
|
|
22
30
|
> ² PrimeNG components are tree-shakable but PrimeIcons font (~50 KB) is typically included globally.
|
|
23
31
|
|
|
24
|
-
##
|
|
32
|
+
## Features
|
|
25
33
|
|
|
26
|
-
-
|
|
27
|
-
-
|
|
34
|
+
- **Zero configuration** — works immediately after install with sensible defaults
|
|
35
|
+
- **Standalone components** — no `NgModule` boilerplate, just import and use
|
|
36
|
+
- **Signal-based** — built on Angular's modern reactivity primitives (`input()`, `model()`, `output()`)
|
|
37
|
+
- **Full theming via CSS custom properties** — override any design token on `:root` or scope overrides to individual components
|
|
38
|
+
- **Dark mode built in** — automatic via `prefers-color-scheme`, no extra setup
|
|
39
|
+
- **Accessible** — ARIA attributes, keyboard navigation, focus management, and screen reader support throughout
|
|
40
|
+
- **Form-ready** — `ControlValueAccessor` on all form components (Input, Textarea, Checkbox, Switch, Radio, Dropdown)
|
|
41
|
+
- **Lightweight** — no third-party runtime dependencies beyond Angular and `tslib`
|
|
42
|
+
- **Tree-shakeable** — only the components you import end up in your bundle
|
|
28
43
|
|
|
29
44
|
## Installation
|
|
30
45
|
|
|
31
|
-
```
|
|
46
|
+
```bash
|
|
32
47
|
npm install @eagami/ui
|
|
48
|
+
# or
|
|
49
|
+
pnpm add @eagami/ui
|
|
33
50
|
```
|
|
34
51
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
### 1. Import the global stylesheet
|
|
52
|
+
Add the global stylesheet to your `angular.json` (or import it in your root SCSS):
|
|
38
53
|
|
|
39
|
-
In `angular.json`:
|
|
40
54
|
```json
|
|
41
55
|
"styles": ["node_modules/@eagami/ui/src/styles/eagami-ui.scss"]
|
|
42
56
|
```
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
```scss
|
|
46
|
-
@use '@eagami/ui/src/styles/eagami-ui';
|
|
47
|
-
```
|
|
58
|
+
Load the fonts in your `index.html`:
|
|
48
59
|
|
|
49
|
-
|
|
60
|
+
```html
|
|
61
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
62
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
63
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=Syne:wght@400;500;600;700&display=swap" />
|
|
64
|
+
```
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
## Quick start
|
|
52
67
|
|
|
53
|
-
```
|
|
54
|
-
import { ButtonComponent
|
|
68
|
+
```typescript
|
|
69
|
+
import { ButtonComponent } from '@eagami/ui';
|
|
55
70
|
|
|
56
71
|
@Component({
|
|
57
|
-
imports: [ButtonComponent
|
|
58
|
-
|
|
72
|
+
imports: [ButtonComponent],
|
|
73
|
+
template: `<ea-button variant="primary" (clicked)="save()">Save</ea-button>`,
|
|
59
74
|
})
|
|
75
|
+
export class MyComponent {
|
|
76
|
+
save() { /* ... */ }
|
|
77
|
+
}
|
|
60
78
|
```
|
|
61
79
|
|
|
62
|
-
|
|
80
|
+
No modules to register, no providers to configure. Every component works the same way — import it, drop it in your template.
|
|
63
81
|
|
|
64
|
-
|
|
82
|
+
## Components
|
|
65
83
|
|
|
66
|
-
|
|
67
|
-
<ea-button variant="primary" (clicked)="onSave($event)">Save</ea-button>
|
|
84
|
+
### Button
|
|
68
85
|
|
|
69
|
-
|
|
86
|
+
Variants: `primary` | `secondary` | `ghost` | `danger`. Sizes: `sm` | `md` | `lg`. Supports `loading`, `disabled`, and `fullWidth` states.
|
|
70
87
|
|
|
71
|
-
|
|
88
|
+
```html
|
|
89
|
+
<ea-button variant="primary" size="md" [loading]="isSaving" (clicked)="save()">
|
|
90
|
+
Save changes
|
|
91
|
+
</ea-button>
|
|
72
92
|
```
|
|
73
93
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
| Input | Type | Default | Description |
|
|
77
|
-
|---|---|---|---|
|
|
78
|
-
| `variant` | `primary \| secondary \| ghost \| danger` | `primary` | Visual style |
|
|
79
|
-
| `size` | `sm \| md \| lg` | `md` | Button size |
|
|
80
|
-
| `type` | `button \| submit \| reset` | `button` | Native button type |
|
|
81
|
-
| `disabled` | `boolean` | `false` | Disables the button |
|
|
82
|
-
| `loading` | `boolean` | `false` | Shows a spinner, disables interaction |
|
|
83
|
-
| `fullWidth` | `boolean` | `false` | Stretches to fill container |
|
|
84
|
-
| `aria-label` | `string` | — | Accessible label for icon-only buttons |
|
|
85
|
-
|
|
86
|
-
**Outputs**
|
|
87
|
-
|
|
88
|
-
| Output | Type | Description |
|
|
89
|
-
|---|---|---|
|
|
90
|
-
| `clicked` | `MouseEvent` | Emitted on click (not emitted when disabled or loading) |
|
|
94
|
+
<img src="docs/images/button.png" alt="Button component" width="560" />
|
|
91
95
|
|
|
92
96
|
---
|
|
93
97
|
|
|
94
98
|
### Input
|
|
95
99
|
|
|
100
|
+
Full `ControlValueAccessor` support. Types: `text` | `email` | `password` | `number` | `search` | `tel` | `url`. Built-in password visibility toggle.
|
|
101
|
+
|
|
96
102
|
```html
|
|
97
103
|
<ea-input
|
|
98
104
|
label="Email"
|
|
99
105
|
type="email"
|
|
100
106
|
placeholder="you@example.com"
|
|
107
|
+
hint="We'll never share your email"
|
|
101
108
|
[(value)]="email" />
|
|
102
|
-
|
|
103
|
-
<ea-input
|
|
104
|
-
label="Password"
|
|
105
|
-
type="password"
|
|
106
|
-
hint="At least 8 characters"
|
|
107
|
-
[required]="true" />
|
|
108
|
-
|
|
109
|
-
<ea-input
|
|
110
|
-
label="Username"
|
|
111
|
-
error="This username is already taken"
|
|
112
|
-
[(value)]="username" />
|
|
113
109
|
```
|
|
114
110
|
|
|
115
|
-
|
|
111
|
+
<img src="docs/images/input.png" alt="Input component" width="560" />
|
|
116
112
|
|
|
117
|
-
|
|
118
|
-
// Reactive
|
|
119
|
-
this.form = this.fb.group({ email: ['', Validators.required] });
|
|
120
|
-
```
|
|
121
|
-
```html
|
|
122
|
-
<ea-input label="Email" formControlName="email" />
|
|
123
|
-
```
|
|
113
|
+
---
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
### Textarea
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
|---|---|---|---|
|
|
129
|
-
| `label` | `string` | — | Field label |
|
|
130
|
-
| `type` | `text \| email \| password \| number \| search \| tel \| url` | `text` | Input type |
|
|
131
|
-
| `placeholder` | `string` | `''` | Placeholder text |
|
|
132
|
-
| `size` | `sm \| md \| lg` | `md` | Field size |
|
|
133
|
-
| `status` | `default \| error \| success` | `default` | Visual validation state |
|
|
134
|
-
| `hint` | `string` | — | Helper text below the input |
|
|
135
|
-
| `error` | `string` | — | Error message (also sets status to `error`) |
|
|
136
|
-
| `disabled` | `boolean` | `false` | Disables the input |
|
|
137
|
-
| `readonly` | `boolean` | `false` | Makes the input read-only |
|
|
138
|
-
| `required` | `boolean` | `false` | Marks as required |
|
|
117
|
+
Mirrors the Input API with `ControlValueAccessor`. Configurable `rows`, `resize` (`none` | `vertical` | `horizontal` | `both`), and `maxlength`.
|
|
139
118
|
|
|
140
|
-
|
|
119
|
+
```html
|
|
120
|
+
<ea-textarea
|
|
121
|
+
label="Message"
|
|
122
|
+
placeholder="Enter your message…"
|
|
123
|
+
hint="Maximum 500 characters"
|
|
124
|
+
[rows]="4"
|
|
125
|
+
[(value)]="message" />
|
|
126
|
+
```
|
|
141
127
|
|
|
142
|
-
|
|
143
|
-
|---|---|---|
|
|
144
|
-
| `[(value)]` | `string` | Two-way signal-based value binding |
|
|
128
|
+
<img src="docs/images/textarea.png" alt="Textarea component" width="560" />
|
|
145
129
|
|
|
146
130
|
---
|
|
147
131
|
|
|
148
132
|
### Checkbox
|
|
149
133
|
|
|
150
|
-
|
|
151
|
-
<ea-checkbox label="Accept terms" [(checked)]="accepted" />
|
|
134
|
+
`ControlValueAccessor` with `indeterminate` state support. Sizes: `sm` | `md` | `lg`.
|
|
152
135
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<ea-checkbox label="Disabled" [disabled]="true" />
|
|
136
|
+
```html
|
|
137
|
+
<ea-checkbox label="Accept terms and conditions" [(checked)]="accepted" />
|
|
156
138
|
```
|
|
157
139
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
**Inputs**
|
|
140
|
+
<img src="docs/images/checkbox.png" alt="Checkbox component" width="560" />
|
|
161
141
|
|
|
162
|
-
|
|
163
|
-
|---|---|---|---|
|
|
164
|
-
| `label` | `string` | — | Checkbox label |
|
|
165
|
-
| `size` | `sm \| md \| lg` | `md` | Checkbox size |
|
|
166
|
-
| `disabled` | `boolean` | `false` | Disables the checkbox |
|
|
167
|
-
| `required` | `boolean` | `false` | Marks as required |
|
|
168
|
-
| `indeterminate` | `boolean` | `false` | Shows indeterminate (minus) state |
|
|
142
|
+
---
|
|
169
143
|
|
|
170
|
-
|
|
144
|
+
### Switch
|
|
171
145
|
|
|
172
|
-
|
|
173
|
-
|---|---|---|
|
|
174
|
-
| `[(checked)]` | `boolean` | Two-way checked state |
|
|
146
|
+
Toggle switch with `ControlValueAccessor`. Sizes: `sm` | `md` | `lg`.
|
|
175
147
|
|
|
176
|
-
|
|
148
|
+
```html
|
|
149
|
+
<ea-switch label="Enable notifications" [(checked)]="notificationsOn" />
|
|
150
|
+
```
|
|
177
151
|
|
|
178
|
-
|
|
179
|
-
|---|---|---|
|
|
180
|
-
| `changed` | `boolean` | Emitted when the checked state changes |
|
|
152
|
+
<img src="docs/images/switch.png" alt="Switch component" width="560" />
|
|
181
153
|
|
|
182
154
|
---
|
|
183
155
|
|
|
184
|
-
### Radio
|
|
156
|
+
### Radio Group
|
|
185
157
|
|
|
186
|
-
|
|
158
|
+
Composite pattern with `ControlValueAccessor`. Supports `vertical` and `horizontal` orientation.
|
|
187
159
|
|
|
188
160
|
```html
|
|
189
|
-
<ea-radio-group [(value)]="
|
|
190
|
-
<ea-radio value="
|
|
191
|
-
<ea-radio value="
|
|
192
|
-
<ea-radio value="
|
|
161
|
+
<ea-radio-group [(value)]="plan">
|
|
162
|
+
<ea-radio value="free" label="Free" />
|
|
163
|
+
<ea-radio value="pro" label="Pro" />
|
|
164
|
+
<ea-radio value="enterprise" label="Enterprise" />
|
|
193
165
|
</ea-radio-group>
|
|
194
166
|
```
|
|
195
167
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
**RadioGroup Inputs**
|
|
168
|
+
<img src="docs/images/radio.png" alt="Radio group component" width="560" />
|
|
199
169
|
|
|
200
|
-
|
|
201
|
-
|---|---|---|---|
|
|
202
|
-
| `name` | `string` | auto | Shared name for all radios |
|
|
203
|
-
| `size` | `sm \| md \| lg` | `md` | Size of all radios |
|
|
204
|
-
| `orientation` | `vertical \| horizontal` | `vertical` | Layout direction |
|
|
205
|
-
| `disabled` | `boolean` | `false` | Disables all radios |
|
|
170
|
+
---
|
|
206
171
|
|
|
207
|
-
|
|
172
|
+
### Dropdown
|
|
208
173
|
|
|
209
|
-
|
|
210
|
-
|---|---|---|
|
|
211
|
-
| `[(value)]` | `string` | Currently selected value |
|
|
174
|
+
Select dropdown with `ControlValueAccessor` and keyboard navigation (Arrow keys, Enter/Space, Escape).
|
|
212
175
|
|
|
213
|
-
|
|
176
|
+
```html
|
|
177
|
+
<ea-dropdown
|
|
178
|
+
label="Country"
|
|
179
|
+
placeholder="Select a country…"
|
|
180
|
+
[options]="countries"
|
|
181
|
+
[(value)]="selectedCountry" />
|
|
182
|
+
```
|
|
214
183
|
|
|
215
|
-
|
|
216
|
-
|---|---|---|---|
|
|
217
|
-
| `value` | `string` | *required* | Option value |
|
|
218
|
-
| `label` | `string` | — | Radio label |
|
|
219
|
-
| `disabled` | `boolean` | `false` | Disables this radio |
|
|
184
|
+
<img src="docs/images/dropdown.png" alt="Dropdown component" width="560" />
|
|
220
185
|
|
|
221
186
|
---
|
|
222
187
|
|
|
223
188
|
### Card
|
|
224
189
|
|
|
190
|
+
Content container with variants: `elevated` | `outlined` | `filled`. Padding: `none` | `sm` | `md` | `lg` | `xl`. Customizable shadow via `--ea-card-shadow`.
|
|
191
|
+
|
|
225
192
|
```html
|
|
226
193
|
<ea-card variant="elevated">
|
|
227
|
-
<span
|
|
228
|
-
|
|
229
|
-
<span
|
|
230
|
-
<ea-button size="sm">
|
|
194
|
+
<span eaCardHeader>Card Title</span>
|
|
195
|
+
Card body content goes here.
|
|
196
|
+
<span eaCardFooter>
|
|
197
|
+
<ea-button variant="secondary" size="sm">Cancel</ea-button>
|
|
198
|
+
<ea-button size="sm">Save</ea-button>
|
|
231
199
|
</span>
|
|
232
200
|
</ea-card>
|
|
233
201
|
```
|
|
234
202
|
|
|
235
|
-
|
|
203
|
+
<img src="docs/images/card.png" alt="Card component" width="560" />
|
|
204
|
+
|
|
205
|
+
---
|
|
236
206
|
|
|
237
|
-
|
|
238
|
-
|---|---|---|---|
|
|
239
|
-
| `variant` | `elevated \| outlined \| filled` | `elevated` | Visual style |
|
|
240
|
-
| `padding` | `none \| sm \| md \| lg` | `md` | Inner padding |
|
|
241
|
-
| `fullWidth` | `boolean` | `false` | Stretches to fill container |
|
|
207
|
+
### Avatar
|
|
242
208
|
|
|
243
|
-
|
|
209
|
+
Image with initials or icon fallback. Sizes: `xs` | `sm` | `md` | `lg` | `xl`. Shapes: `circle` | `square`.
|
|
244
210
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
211
|
+
```html
|
|
212
|
+
<ea-avatar src="/photo.jpg" alt="User" size="lg" />
|
|
213
|
+
<ea-avatar initials="MW" shape="square" />
|
|
214
|
+
<ea-avatar /> <!-- shows fallback user icon -->
|
|
215
|
+
```
|
|
250
216
|
|
|
251
|
-
|
|
217
|
+
<img src="docs/images/avatar.png" alt="Avatar component" width="560" />
|
|
252
218
|
|
|
253
219
|
---
|
|
254
220
|
|
|
255
|
-
###
|
|
221
|
+
### Avatar Editor
|
|
222
|
+
|
|
223
|
+
Canvas-based image editor with drag-and-drop upload, pan, zoom (slider + scroll wheel), and crop export. Outputs a `Blob` and data URL for use with the Avatar component.
|
|
256
224
|
|
|
257
225
|
```html
|
|
258
|
-
<ea-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
226
|
+
<ea-avatar-editor
|
|
227
|
+
shape="circle"
|
|
228
|
+
[canvasSize]="200"
|
|
229
|
+
(cropped)="onCropped($event)" />
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
<img src="docs/images/avatar-editor.png" alt="Avatar editor component" width="560" />
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
### Badge
|
|
237
|
+
|
|
238
|
+
Semantic status indicators. Variants: `default` | `success` | `warning` | `error` | `info`. Sizes: `sm` | `md` | `lg`.
|
|
239
|
+
|
|
240
|
+
```html
|
|
241
|
+
<ea-badge variant="success">Active</ea-badge>
|
|
242
|
+
<ea-badge variant="error">Failed</ea-badge>
|
|
263
243
|
```
|
|
264
244
|
|
|
265
|
-
|
|
245
|
+
<img src="docs/images/badge.png" alt="Badge component" width="560" />
|
|
266
246
|
|
|
267
|
-
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### Spinner
|
|
250
|
+
|
|
251
|
+
SVG loading indicator with `role="status"` for accessibility. Sizes: `sm` | `md` | `lg`.
|
|
252
|
+
|
|
253
|
+
```html
|
|
254
|
+
<ea-spinner size="md" label="Loading data" />
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
<img src="docs/images/spinner.png" alt="Spinner component" width="560" />
|
|
268
258
|
|
|
269
|
-
|
|
270
|
-
|---|---|---|---|
|
|
271
|
-
| `label` | `string` | — | Field label |
|
|
272
|
-
| `placeholder` | `string` | `'Select…'` | Placeholder text |
|
|
273
|
-
| `options` | `DropdownOption[]` | `[]` | Array of `{ value, label, disabled? }` |
|
|
274
|
-
| `size` | `sm \| md \| lg` | `md` | Trigger size |
|
|
275
|
-
| `disabled` | `boolean` | `false` | Disables the dropdown |
|
|
276
|
-
| `required` | `boolean` | `false` | Marks as required |
|
|
277
|
-
| `hint` | `string` | — | Helper text |
|
|
278
|
-
| `error` | `string` | — | Error message |
|
|
259
|
+
---
|
|
279
260
|
|
|
280
|
-
|
|
261
|
+
### Divider
|
|
281
262
|
|
|
282
|
-
|
|
283
|
-
|---|---|---|
|
|
284
|
-
| `[(value)]` | `string` | Selected option value |
|
|
263
|
+
Visual separator with optional label. Orientation: `horizontal` | `vertical`.
|
|
285
264
|
|
|
286
|
-
|
|
265
|
+
```html
|
|
266
|
+
<ea-divider />
|
|
267
|
+
<ea-divider label="or" />
|
|
268
|
+
<ea-divider orientation="vertical" />
|
|
269
|
+
```
|
|
287
270
|
|
|
288
|
-
|
|
289
|
-
|---|---|---|
|
|
290
|
-
| `changed` | `string` | Emitted when selection changes |
|
|
271
|
+
<img src="docs/images/divider.png" alt="Divider component" width="560" />
|
|
291
272
|
|
|
292
273
|
---
|
|
293
274
|
|
|
294
275
|
### Dialog
|
|
295
276
|
|
|
277
|
+
Built on the native `<dialog>` element for built-in focus trapping. Sizes: `sm` | `md` | `lg` | `full`. Two-way `open` binding.
|
|
278
|
+
|
|
296
279
|
```html
|
|
297
|
-
<ea-button (clicked)="
|
|
280
|
+
<ea-button (clicked)="dialogOpen.set(true)">Open</ea-button>
|
|
298
281
|
|
|
299
|
-
<ea-dialog [(open)]="
|
|
300
|
-
<span slot="header">Confirm
|
|
301
|
-
<p>Are you sure
|
|
282
|
+
<ea-dialog [(open)]="dialogOpen" size="md">
|
|
283
|
+
<span slot="header">Confirm</span>
|
|
284
|
+
<p>Are you sure?</p>
|
|
302
285
|
<span slot="footer">
|
|
303
|
-
<ea-button variant="secondary" (clicked)="
|
|
304
|
-
<ea-button (clicked)="
|
|
286
|
+
<ea-button variant="secondary" (clicked)="dialogOpen.set(false)">Cancel</ea-button>
|
|
287
|
+
<ea-button (clicked)="confirm()">Confirm</ea-button>
|
|
305
288
|
</span>
|
|
306
289
|
</ea-dialog>
|
|
307
290
|
```
|
|
308
291
|
|
|
309
|
-
|
|
292
|
+
---
|
|
310
293
|
|
|
311
|
-
|
|
294
|
+
### Tooltip
|
|
312
295
|
|
|
313
|
-
|
|
314
|
-
|---|---|---|---|
|
|
315
|
-
| `size` | `sm \| md \| lg \| full` | `md` | Dialog panel width |
|
|
316
|
-
| `closeOnBackdrop` | `boolean` | `true` | Close on backdrop click |
|
|
317
|
-
| `closeOnEscape` | `boolean` | `true` | Close on Escape key |
|
|
318
|
-
| `showClose` | `boolean` | `true` | Show the close (×) button |
|
|
319
|
-
| `aria-label` | `string` | — | Accessible label for the dialog |
|
|
296
|
+
Directive that shows a positioned tooltip on hover and focus. Positions: `top` | `bottom` | `left` | `right`.
|
|
320
297
|
|
|
321
|
-
|
|
298
|
+
```html
|
|
299
|
+
<ea-button eaTooltip="Save your changes" tooltipPosition="top">Save</ea-button>
|
|
300
|
+
```
|
|
322
301
|
|
|
323
|
-
|
|
324
|
-
|---|---|---|
|
|
325
|
-
| `[(open)]` | `boolean` | Controls dialog visibility |
|
|
302
|
+
---
|
|
326
303
|
|
|
327
|
-
|
|
304
|
+
### Toast
|
|
328
305
|
|
|
329
|
-
|
|
|
330
|
-
|---|---|---|
|
|
331
|
-
| `opened` | `void` | Emitted when the dialog opens |
|
|
332
|
-
| `closed` | `void` | Emitted when the dialog closes |
|
|
306
|
+
Notification system via injectable `ToastService`. Variants: `default` | `success` | `warning` | `error` | `info`. Auto-dismiss with configurable duration. Full-width on mobile, independent widths on desktop.
|
|
333
307
|
|
|
334
|
-
|
|
308
|
+
```typescript
|
|
309
|
+
import { ToastService } from '@eagami/ui';
|
|
335
310
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
| `[slot=header]` | Dialog title |
|
|
339
|
-
| *(default)* | Dialog body |
|
|
340
|
-
| `[slot=footer]` | Dialog actions |
|
|
311
|
+
export class MyComponent {
|
|
312
|
+
private toast = inject(ToastService);
|
|
341
313
|
|
|
342
|
-
|
|
314
|
+
save() {
|
|
315
|
+
this.toast.success('Changes saved');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
handleError() {
|
|
319
|
+
this.toast.error('Something went wrong');
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Add the toast outlet once in your root template:
|
|
325
|
+
|
|
326
|
+
```html
|
|
327
|
+
<ea-toast />
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
<img src="docs/images/toast.png" alt="Toast component" width="560" />
|
|
331
|
+
|
|
332
|
+
## Icons
|
|
333
|
+
|
|
334
|
+
Built-in SVG icon components following the Feather icon style (24x24 viewBox, stroke-based, inherits `currentColor`):
|
|
335
|
+
|
|
336
|
+
`ea-icon-check` | `ea-icon-x` | `ea-icon-user` | `ea-icon-info` | `ea-icon-loader` | `ea-icon-alert-circle` | `ea-icon-eye` | `ea-icon-eye-off` | `ea-icon-google`
|
|
337
|
+
|
|
338
|
+
```html
|
|
339
|
+
<ea-icon-check />
|
|
340
|
+
<ea-icon-info />
|
|
341
|
+
```
|
|
343
342
|
|
|
344
343
|
## Theming
|
|
345
344
|
|
|
346
|
-
All
|
|
345
|
+
All visual properties are controlled through CSS custom properties defined on `:root`. Override any token to customize the entire library:
|
|
347
346
|
|
|
348
347
|
```css
|
|
349
348
|
:root {
|
|
350
|
-
|
|
351
|
-
--
|
|
352
|
-
--
|
|
353
|
-
--color-brand-active: #5b21b6;
|
|
354
|
-
--color-brand-subtle: #f5f3ff;
|
|
355
|
-
--color-brand-muted: #ede9fe;
|
|
349
|
+
--color-primary-600: #2563eb;
|
|
350
|
+
--font-family-sans: 'Inter', sans-serif;
|
|
351
|
+
--radius-md: 0.5rem;
|
|
356
352
|
}
|
|
357
353
|
```
|
|
358
354
|
|
|
359
|
-
|
|
355
|
+
Component-level overrides are available where useful:
|
|
360
356
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
357
|
+
```css
|
|
358
|
+
.my-card {
|
|
359
|
+
--ea-card-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
|
360
|
+
--ea-button-font-weight: 600;
|
|
361
|
+
}
|
|
362
|
+
```
|
|
364
363
|
|
|
365
|
-
|
|
366
|
-
# Install dependencies
|
|
367
|
-
pnpm install
|
|
364
|
+
See [`src/styles/tokens/`](src/styles/tokens/) for the full token reference.
|
|
368
365
|
|
|
369
|
-
|
|
370
|
-
pnpm sandbox
|
|
366
|
+
## Peer dependencies
|
|
371
367
|
|
|
372
|
-
|
|
373
|
-
|
|
368
|
+
| Package | Version |
|
|
369
|
+
|---------|---------|
|
|
370
|
+
| `@angular/common` | `^21.0.0` |
|
|
371
|
+
| `@angular/core` | `^21.0.0` |
|
|
372
|
+
| `@angular/forms` | `^21.0.0` |
|
|
373
|
+
| `rxjs` | `^7.0.0` |
|
|
374
374
|
|
|
375
|
-
|
|
376
|
-
pnpm test
|
|
375
|
+
## Development
|
|
377
376
|
|
|
378
|
-
|
|
379
|
-
pnpm
|
|
377
|
+
```bash
|
|
378
|
+
pnpm install # Install dependencies
|
|
379
|
+
pnpm start # Run sandbox dev app
|
|
380
|
+
pnpm storybook # Run Storybook
|
|
381
|
+
pnpm test # Run tests
|
|
382
|
+
pnpm build # Build the library
|
|
383
|
+
pnpm lint # Lint
|
|
380
384
|
```
|
|
381
385
|
|
|
382
|
-
## Contributing
|
|
383
|
-
|
|
384
|
-
Issues and PRs are welcome. Please open an issue before submitting large changes.
|
|
385
|
-
|
|
386
386
|
## License
|
|
387
387
|
|
|
388
388
|
MIT
|