@eagami/ui 0.12.0 → 1.0.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 +41 -670
- package/fesm2022/eagami-ui.mjs +648 -182
- package/fesm2022/eagami-ui.mjs.map +1 -1
- package/package.json +4 -1
- package/src/styles/tokens/_colors.scss +3 -1
- package/types/eagami-ui.d.ts +488 -86
package/README.md
CHANGED
|
@@ -2,32 +2,17 @@
|
|
|
2
2
|
<img src="docs/images/eagami-header.png" alt="eagami design system — elegant web design" width="800" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/@eagami/ui"><img src="https://img.shields.io/npm/v/@eagami/ui.svg" alt="npm version" /></a>
|
|
7
|
+
<a href="https://github.com/mwiraszka/eagami-design-system/actions/workflows/ci.yml"><img src="https://github.com/mwiraszka/eagami-design-system/actions/workflows/ci.yml/badge.svg" alt="CI" /></a>
|
|
8
|
+
<a href="https://github.com/mwiraszka/eagami-design-system/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@eagami/ui.svg" alt="license" /></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
5
11
|
A lightweight, accessible Angular component library built on CSS custom properties, with portable design system integration guides for Flutter and React ([see more](#framework-integration)). Ready to use out of the box — install, import, and start building.
|
|
6
12
|
|
|
7
13
|
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
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
**Approx. component sizes (gzipped)¹**
|
|
12
|
-
|
|
13
|
-
| Component | **@eagami/ui** | Angular Material | PrimeNG | ng-bootstrap | ng-zorro |
|
|
14
|
-
|---|---|---|---|---|---|
|
|
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 |
|
|
20
|
-
|
|
21
|
-
> ¹ Approximate — depends on configuration, tree-shaking, and Angular version. @eagami/ui sizes measured from production build.
|
|
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 |
|
|
30
|
-
> ² PrimeNG components are tree-shakable but PrimeIcons font (~50 KB) is typically included globally.
|
|
15
|
+
**Component reference and live examples:** [eagami.com/ui](https://eagami.com/ui)
|
|
31
16
|
|
|
32
17
|
## Features
|
|
33
18
|
|
|
@@ -37,9 +22,9 @@ Every component is standalone, signal-based, and fully themed via design tokens.
|
|
|
37
22
|
- **Full theming via CSS custom properties** — override any design token on `:root` or scope overrides to individual components
|
|
38
23
|
- **Dark mode built in** — automatic via `prefers-color-scheme`, no extra setup
|
|
39
24
|
- **Accessible** — ARIA attributes, keyboard navigation, focus management, and screen reader support throughout
|
|
40
|
-
- **Form-ready** — `ControlValueAccessor` on
|
|
41
|
-
- **Lightweight** — zero runtime dependencies beyond Angular
|
|
25
|
+
- **Form-ready** — `ControlValueAccessor` on every form control (input, textarea, checkbox, switch, radio, dropdown, autocomplete, date picker, slider, code input, segmented)
|
|
42
26
|
- **Tree-shakeable** — only the components you import end up in your bundle
|
|
27
|
+
- **Tiny** — the entire library is **70 KB gzipped**, and only the components you import end up in your bundle
|
|
43
28
|
|
|
44
29
|
## Installation
|
|
45
30
|
|
|
@@ -79,656 +64,23 @@ export class MyComponent {
|
|
|
79
64
|
|
|
80
65
|
No modules to register, no providers to configure. Every component works the same way — import it, drop it in your template.
|
|
81
66
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<details>
|
|
85
|
-
<summary><strong>Accordion</strong> — expandable content sections</summary>
|
|
86
|
-
|
|
87
|
-
Supports single or `multi` expand mode. Built-in chevron animation and disabled state.
|
|
88
|
-
|
|
89
|
-
```html
|
|
90
|
-
<ea-accordion>
|
|
91
|
-
<ea-accordion-item label="Section 1">Content for section 1</ea-accordion-item>
|
|
92
|
-
<ea-accordion-item label="Section 2">Content for section 2</ea-accordion-item>
|
|
93
|
-
</ea-accordion>
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
<img src="docs/images/accordion.png" alt="Accordion component" width="560" />
|
|
97
|
-
|
|
98
|
-
</details>
|
|
99
|
-
|
|
100
|
-
<details>
|
|
101
|
-
<summary><strong>Alert</strong> — semantic alert banners with optional dismiss</summary>
|
|
102
|
-
|
|
103
|
-
Variants: `default` | `success` | `warning` | `error` | `info`. Two-way `visible` binding.
|
|
104
|
-
|
|
105
|
-
```html
|
|
106
|
-
<ea-alert variant="success">Changes saved successfully.</ea-alert>
|
|
107
|
-
<ea-alert variant="error" [dismissible]="true">Something went wrong.</ea-alert>
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
<img src="docs/images/alert.png" alt="Alert component" width="560" />
|
|
111
|
-
|
|
112
|
-
</details>
|
|
113
|
-
|
|
114
|
-
<details>
|
|
115
|
-
<summary><strong>Autocomplete</strong> — text input with filtered suggestion dropdown</summary>
|
|
116
|
-
|
|
117
|
-
Arrow key navigation, case-insensitive substring matching, configurable `minLength` and `maxResults`. Full `ControlValueAccessor` support.
|
|
118
|
-
|
|
119
|
-
```html
|
|
120
|
-
<ea-autocomplete
|
|
121
|
-
label="Country"
|
|
122
|
-
placeholder="Start typing…"
|
|
123
|
-
[options]="countries"
|
|
124
|
-
[(value)]="selectedCountry"
|
|
125
|
-
(optionSelected)="onSelect($event)" />
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
<img src="docs/images/autocomplete.png" alt="Autocomplete component" width="560" />
|
|
129
|
-
|
|
130
|
-
</details>
|
|
131
|
-
|
|
132
|
-
<details>
|
|
133
|
-
<summary><strong>Avatar</strong> — image with initials or icon fallback</summary>
|
|
134
|
-
|
|
135
|
-
Sizes: `xs` | `sm` | `md` | `lg` | `xl`. Shapes: `circle` | `square`.
|
|
136
|
-
|
|
137
|
-
```html
|
|
138
|
-
<ea-avatar src="/photo.jpg" alt="User" size="lg" />
|
|
139
|
-
<ea-avatar initials="MW" shape="square" />
|
|
140
|
-
<ea-avatar /> <!-- shows fallback user icon -->
|
|
141
|
-
```
|
|
67
|
+
> **Upgrading from v0.x?** See [MIGRATION.md](MIGRATION.md) for the full list of breaking changes and a find/replace table that covers most upgrades in one pass.
|
|
142
68
|
|
|
143
|
-
|
|
69
|
+
## What's included
|
|
144
70
|
|
|
145
|
-
|
|
71
|
+
- **Form controls** — Input, Textarea, Checkbox, Switch, Radio, Dropdown, Autocomplete, Date picker, Slider, Code input, Segmented
|
|
72
|
+
- **Overlays** — Dialog, Drawer, Tooltip, Menu, Toast
|
|
73
|
+
- **Navigation** — Tabs, Breadcrumbs, Paginator, Accordion
|
|
74
|
+
- **Display** — Card, Badge, Tag, Alert, Avatar, Skeleton, Spinner, Progress bar, Empty state, Divider, Eagami wordmark
|
|
75
|
+
- **Data** — Data table
|
|
76
|
+
- **Specialised** — Avatar editor
|
|
77
|
+
- **Icons** — 52 stroke-based SVG icon components (`<ea-icon-*>`)
|
|
146
78
|
|
|
147
|
-
|
|
148
|
-
<summary><strong>Avatar editor</strong> — canvas-based image editor with pan, zoom, and crop</summary>
|
|
149
|
-
|
|
150
|
-
Drag-and-drop upload, zoom via slider or scroll wheel. Outputs a `Blob` and data URL.
|
|
151
|
-
|
|
152
|
-
```html
|
|
153
|
-
<ea-avatar-editor
|
|
154
|
-
shape="circle"
|
|
155
|
-
[canvasSize]="200"
|
|
156
|
-
(cropped)="onCropped($event)" />
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
<img src="docs/images/avatar-editor.png" alt="Avatar editor component" width="560" />
|
|
160
|
-
|
|
161
|
-
</details>
|
|
162
|
-
|
|
163
|
-
<details>
|
|
164
|
-
<summary><strong>Badge</strong> — semantic status indicators</summary>
|
|
165
|
-
|
|
166
|
-
Variants: `default` | `success` | `warning` | `error` | `info`. Sizes: `sm` | `md` | `lg`.
|
|
167
|
-
|
|
168
|
-
```html
|
|
169
|
-
<ea-badge variant="success">Active</ea-badge>
|
|
170
|
-
<ea-badge variant="error">Failed</ea-badge>
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
<img src="docs/images/badge.png" alt="Badge component" width="560" />
|
|
174
|
-
|
|
175
|
-
</details>
|
|
176
|
-
|
|
177
|
-
<details>
|
|
178
|
-
<summary><strong>Breadcrumbs</strong> — navigation trail with chevron or slash separators</summary>
|
|
179
|
-
|
|
180
|
-
Separators: `chevron` | `slash`. Items can be links (`href`), buttons (no `href`), or disabled. The last item is automatically rendered as the current page.
|
|
181
|
-
|
|
182
|
-
```html
|
|
183
|
-
<ea-breadcrumbs
|
|
184
|
-
[items]="[
|
|
185
|
-
{ label: 'Home', href: '/' },
|
|
186
|
-
{ label: 'Products', href: '/products' },
|
|
187
|
-
{ label: 'MacBook Pro' }
|
|
188
|
-
]"
|
|
189
|
-
(itemClicked)="navigate($event)" />
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
<img src="docs/images/breadcrumbs.png" alt="Breadcrumbs component" width="560" />
|
|
193
|
-
|
|
194
|
-
</details>
|
|
195
|
-
|
|
196
|
-
<details>
|
|
197
|
-
<summary><strong>Button</strong> — primary, secondary, ghost, danger variants with loading state</summary>
|
|
198
|
-
|
|
199
|
-
Sizes: `sm` | `md` | `lg`. Supports `loading`, `disabled`, and `fullWidth` states.
|
|
200
|
-
|
|
201
|
-
```html
|
|
202
|
-
<ea-button variant="primary" size="md" [loading]="isSaving" (clicked)="save()">
|
|
203
|
-
Save changes
|
|
204
|
-
</ea-button>
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
<img src="docs/images/button.png" alt="Button component" width="560" />
|
|
208
|
-
|
|
209
|
-
</details>
|
|
210
|
-
|
|
211
|
-
<details>
|
|
212
|
-
<summary><strong>Card</strong> — content container with elevated, outlined, and filled variants</summary>
|
|
213
|
-
|
|
214
|
-
Padding: `none` | `sm` | `md` | `lg` | `xl`. Customizable shadow via `--ea-card-shadow`.
|
|
215
|
-
|
|
216
|
-
```html
|
|
217
|
-
<ea-card variant="elevated">
|
|
218
|
-
<span eaCardHeader>Card Title</span>
|
|
219
|
-
Card body content goes here.
|
|
220
|
-
<span eaCardFooter>
|
|
221
|
-
<ea-button variant="secondary" size="sm">Cancel</ea-button>
|
|
222
|
-
<ea-button size="sm">Save</ea-button>
|
|
223
|
-
</span>
|
|
224
|
-
</ea-card>
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
<img src="docs/images/card.png" alt="Card component" width="560" />
|
|
228
|
-
|
|
229
|
-
</details>
|
|
230
|
-
|
|
231
|
-
<details>
|
|
232
|
-
<summary><strong>Checkbox</strong> — with indeterminate state and ControlValueAccessor</summary>
|
|
233
|
-
|
|
234
|
-
Sizes: `sm` | `md` | `lg`.
|
|
235
|
-
|
|
236
|
-
```html
|
|
237
|
-
<ea-checkbox label="Accept terms and conditions" [(checked)]="accepted" />
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
<img src="docs/images/checkbox.png" alt="Checkbox component" width="560" />
|
|
241
|
-
|
|
242
|
-
</details>
|
|
243
|
-
|
|
244
|
-
<details>
|
|
245
|
-
<summary><strong>Code input</strong> — verification code entry with auto-advance and paste support</summary>
|
|
246
|
-
|
|
247
|
-
Configurable `length` (default 6). Full `ControlValueAccessor` support.
|
|
248
|
-
|
|
249
|
-
```html
|
|
250
|
-
<ea-code-input [(value)]="code" [length]="6" (completed)="verify()" />
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
<img src="docs/images/code-input.png" alt="Code input component" width="560" />
|
|
254
|
-
|
|
255
|
-
</details>
|
|
256
|
-
|
|
257
|
-
<details>
|
|
258
|
-
<summary><strong>Data table</strong> — sortable columns, sticky headers, density modes</summary>
|
|
259
|
-
|
|
260
|
-
Striped, bordered, and hoverable rows. Custom cell templates via `ng-template`. Density: `compact` | `comfortable` | `spacious`. Two-way `sort` binding.
|
|
261
|
-
|
|
262
|
-
```html
|
|
263
|
-
<ea-data-table
|
|
264
|
-
[columns]="columns"
|
|
265
|
-
[data]="users"
|
|
266
|
-
[stickyHeader]="true"
|
|
267
|
-
[striped]="true"
|
|
268
|
-
[(sort)]="sortState"
|
|
269
|
-
trackBy="id" />
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
<img src="docs/images/data-table.png" alt="Data table component" width="560" />
|
|
273
|
-
|
|
274
|
-
</details>
|
|
275
|
-
|
|
276
|
-
<details>
|
|
277
|
-
<summary><strong>Date picker</strong> — calendar popover with keyboard navigation and min/max bounds</summary>
|
|
278
|
-
|
|
279
|
-
Sizes: `sm` | `md` | `lg`. Formats: `short` | `medium` | `long` (locale-aware via `Intl.DateTimeFormat`). Configurable week start (Sunday or Monday). Full keyboard navigation (arrows, PageUp/PageDown, Home/End, Enter, Escape) and `ControlValueAccessor` integration.
|
|
280
|
-
|
|
281
|
-
```html
|
|
282
|
-
<ea-date-picker
|
|
283
|
-
label="Appointment"
|
|
284
|
-
placeholder="Pick a date…"
|
|
285
|
-
format="medium"
|
|
286
|
-
[minDate]="today"
|
|
287
|
-
[(value)]="appointmentDate" />
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
<img src="docs/images/date-picker.png" alt="Date picker component" width="560" />
|
|
291
|
-
|
|
292
|
-
</details>
|
|
293
|
-
|
|
294
|
-
<details>
|
|
295
|
-
<summary><strong>Dialog</strong> — native dialog element with focus trapping</summary>
|
|
296
|
-
|
|
297
|
-
Sizes: `sm` | `md` | `lg` | `full`. Two-way `open` binding.
|
|
298
|
-
|
|
299
|
-
```html
|
|
300
|
-
<ea-button (clicked)="dialogOpen.set(true)">Open</ea-button>
|
|
301
|
-
|
|
302
|
-
<ea-dialog [(open)]="dialogOpen" size="md">
|
|
303
|
-
<span slot="header">Confirm</span>
|
|
304
|
-
<p>Are you sure?</p>
|
|
305
|
-
<span slot="footer">
|
|
306
|
-
<ea-button variant="secondary" (clicked)="dialogOpen.set(false)">Cancel</ea-button>
|
|
307
|
-
<ea-button (clicked)="confirm()">Confirm</ea-button>
|
|
308
|
-
</span>
|
|
309
|
-
</ea-dialog>
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
<img src="docs/images/dialog.png" alt="Dialog component" width="560" />
|
|
313
|
-
|
|
314
|
-
</details>
|
|
315
|
-
|
|
316
|
-
<details>
|
|
317
|
-
<summary><strong>Divider</strong> — visual separator with optional label</summary>
|
|
318
|
-
|
|
319
|
-
Orientation: `horizontal` | `vertical`.
|
|
320
|
-
|
|
321
|
-
```html
|
|
322
|
-
<ea-divider />
|
|
323
|
-
<ea-divider label="or" />
|
|
324
|
-
<ea-divider orientation="vertical" />
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
<img src="docs/images/divider.png" alt="Divider component" width="560" />
|
|
328
|
-
|
|
329
|
-
</details>
|
|
330
|
-
|
|
331
|
-
<details>
|
|
332
|
-
<summary><strong>Drawer</strong> — side panel using native dialog with focus trapping</summary>
|
|
333
|
-
|
|
334
|
-
Positions: `left` | `right` | `top` | `bottom`. Sizes: `sm` | `md` | `lg` | `full`. Two-way `open` binding.
|
|
335
|
-
|
|
336
|
-
```html
|
|
337
|
-
<ea-button (clicked)="drawerOpen.set(true)">Open</ea-button>
|
|
338
|
-
|
|
339
|
-
<ea-drawer [(open)]="drawerOpen" position="right" size="md">
|
|
340
|
-
<span slot="header">Details</span>
|
|
341
|
-
<p>Drawer body content…</p>
|
|
342
|
-
<span slot="footer">
|
|
343
|
-
<ea-button variant="secondary" (clicked)="drawerOpen.set(false)">Cancel</ea-button>
|
|
344
|
-
<ea-button (clicked)="save()">Save</ea-button>
|
|
345
|
-
</span>
|
|
346
|
-
</ea-drawer>
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
<img src="docs/images/drawer.png" alt="Drawer component" width="560" />
|
|
350
|
-
|
|
351
|
-
</details>
|
|
352
|
-
|
|
353
|
-
<details>
|
|
354
|
-
<summary><strong>Dropdown</strong> — select with ControlValueAccessor and keyboard navigation</summary>
|
|
355
|
-
|
|
356
|
-
Arrow keys, Enter/Space to select, Escape to close. Sizes: `sm` | `md` | `lg`.
|
|
357
|
-
|
|
358
|
-
```html
|
|
359
|
-
<ea-dropdown
|
|
360
|
-
label="Country"
|
|
361
|
-
placeholder="Select a country…"
|
|
362
|
-
[options]="countries"
|
|
363
|
-
[(value)]="selectedCountry" />
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
<img src="docs/images/dropdown.png" alt="Dropdown component" width="560" />
|
|
367
|
-
|
|
368
|
-
</details>
|
|
369
|
-
|
|
370
|
-
<details>
|
|
371
|
-
<summary><strong>Eagami wordmark</strong> — branded logo wordmark linking to eagami.com</summary>
|
|
372
|
-
|
|
373
|
-
| Variant | Text |
|
|
374
|
-
| --- | --- |
|
|
375
|
-
| `1` | eagami |
|
|
376
|
-
| `2` | handcrafted by eagami |
|
|
377
|
-
| `3` | eagami design system |
|
|
378
|
-
| `4` | eagami design system — elegant web design |
|
|
379
|
-
|
|
380
|
-
Layout: `stacked` (default, multi-line) | `inline` (single line, uniform font size — adds em dash before tagline). Size is a number (pixels) for continuous scaling; the logo, brand text, and secondary text all scale proportionally.
|
|
381
|
-
|
|
382
|
-
```html
|
|
383
|
-
<ea-eagami-wordmark [variant]="4" [size]="96" />
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
<img src="docs/images/eagami-wordmark.png" alt="Eagami wordmark component" width="560" />
|
|
387
|
-
|
|
388
|
-
</details>
|
|
389
|
-
|
|
390
|
-
<details>
|
|
391
|
-
<summary><strong>Empty state</strong> — pattern for "no results" and "nothing here yet" screens</summary>
|
|
392
|
-
|
|
393
|
-
Optional `title` and `description`, with `[slot=media]` for an icon or illustration and `[slot=actions]` for follow-up buttons. Sizes: `sm` | `md` | `lg`.
|
|
394
|
-
|
|
395
|
-
```html
|
|
396
|
-
<ea-empty-state title="No items yet" description="Get started by creating your first item.">
|
|
397
|
-
<ea-icon-file slot="media" />
|
|
398
|
-
<ea-button slot="actions" variant="primary">Create item</ea-button>
|
|
399
|
-
</ea-empty-state>
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
<img src="docs/images/empty-state.png" alt="Empty state component" width="560" />
|
|
403
|
-
|
|
404
|
-
</details>
|
|
405
|
-
|
|
406
|
-
<details>
|
|
407
|
-
<summary><strong>Input</strong> — text field with ControlValueAccessor and password toggle</summary>
|
|
408
|
-
|
|
409
|
-
Types: `text` | `email` | `password` | `number` | `search` | `tel` | `url`. Sizes: `sm` | `md` | `lg`.
|
|
410
|
-
|
|
411
|
-
```html
|
|
412
|
-
<ea-input
|
|
413
|
-
label="Email"
|
|
414
|
-
type="email"
|
|
415
|
-
placeholder="you@example.com"
|
|
416
|
-
hint="We'll never share your email"
|
|
417
|
-
[(value)]="email" />
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
<img src="docs/images/input.png" alt="Input component" width="560" />
|
|
421
|
-
|
|
422
|
-
</details>
|
|
423
|
-
|
|
424
|
-
<details>
|
|
425
|
-
<summary><strong>Menu</strong> — popup action menu with menu items</summary>
|
|
426
|
-
|
|
427
|
-
Attach the menu to any focusable element with the `[eaMenuTrigger]` directive. Placements: `bottom-start` | `bottom-end` | `top-start` | `top-end`. Menu items support icons, disabled state, and a `danger` variant. Closes on outside click or Escape and restores focus to the trigger.
|
|
428
|
-
|
|
429
|
-
```html
|
|
430
|
-
<ea-button [eaMenuTrigger]="actions" variant="secondary">Actions</ea-button>
|
|
431
|
-
<ea-menu #actions placement="bottom-end">
|
|
432
|
-
<ea-menu-item (itemClicked)="edit()">
|
|
433
|
-
<ea-icon-pencil slot="icon" />
|
|
434
|
-
Edit
|
|
435
|
-
</ea-menu-item>
|
|
436
|
-
<ea-menu-item variant="danger" (itemClicked)="delete()">
|
|
437
|
-
<ea-icon-trash slot="icon" />
|
|
438
|
-
Delete
|
|
439
|
-
</ea-menu-item>
|
|
440
|
-
</ea-menu>
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
<img src="docs/images/menu.png" alt="Menu component" width="560" />
|
|
444
|
-
|
|
445
|
-
</details>
|
|
446
|
-
|
|
447
|
-
<details>
|
|
448
|
-
<summary><strong>Paginator</strong> — page navigation with configurable page sizes</summary>
|
|
449
|
-
|
|
450
|
-
Placement: `left` | `center` | `right`. Emits `pageChange` events with current page, page size, and total.
|
|
451
|
-
|
|
452
|
-
```html
|
|
453
|
-
<ea-paginator
|
|
454
|
-
[total]="100"
|
|
455
|
-
[pageSize]="10"
|
|
456
|
-
placement="center"
|
|
457
|
-
(pageChange)="onPageChange($event)" />
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
<img src="docs/images/paginator.png" alt="Paginator component" width="560" />
|
|
461
|
-
|
|
462
|
-
</details>
|
|
463
|
-
|
|
464
|
-
<details>
|
|
465
|
-
<summary><strong>Progress bar</strong> — determinate and indeterminate linear indicator</summary>
|
|
466
|
-
|
|
467
|
-
Variants: `default` | `success` | `warning` | `error` | `info`. Sizes: `sm` | `md` | `lg`. Optional `label` and `showValue` display.
|
|
468
|
-
|
|
469
|
-
```html
|
|
470
|
-
<ea-progress-bar [value]="72" label="Uploading" [showValue]="true" />
|
|
471
|
-
<ea-progress-bar variant="success" [value]="100" />
|
|
472
|
-
<ea-progress-bar [indeterminate]="true" label="Processing…" />
|
|
473
|
-
```
|
|
474
|
-
|
|
475
|
-
<img src="docs/images/progress-bar.png" alt="Progress bar component" width="560" />
|
|
476
|
-
|
|
477
|
-
</details>
|
|
478
|
-
|
|
479
|
-
<details>
|
|
480
|
-
<summary><strong>Radio Group</strong> — composite pattern with ControlValueAccessor</summary>
|
|
481
|
-
|
|
482
|
-
Supports `vertical` and `horizontal` orientation. Sizes: `sm` | `md` | `lg`.
|
|
483
|
-
|
|
484
|
-
```html
|
|
485
|
-
<ea-radio-group [(value)]="plan">
|
|
486
|
-
<ea-radio value="free" label="Free" />
|
|
487
|
-
<ea-radio value="pro" label="Pro" />
|
|
488
|
-
<ea-radio value="enterprise" label="Enterprise" />
|
|
489
|
-
</ea-radio-group>
|
|
490
|
-
```
|
|
491
|
-
|
|
492
|
-
<img src="docs/images/radio.png" alt="Radio group component" width="560" />
|
|
493
|
-
|
|
494
|
-
</details>
|
|
495
|
-
|
|
496
|
-
<details>
|
|
497
|
-
<summary><strong>Segmented</strong> — toggle button group for picking one of a few options</summary>
|
|
498
|
-
|
|
499
|
-
Compact alternative to a radio group for view/mode switches (e.g. List/Grid/Kanban, Light/Dark). Implements `radiogroup` semantics and `ControlValueAccessor`. Sizes: `sm` | `md` | `lg`. Supports `fullWidth` and per-option `disabled`.
|
|
500
|
-
|
|
501
|
-
```html
|
|
502
|
-
<ea-segmented
|
|
503
|
-
[options]="[
|
|
504
|
-
{ value: 'list', label: 'List' },
|
|
505
|
-
{ value: 'grid', label: 'Grid' },
|
|
506
|
-
{ value: 'kanban', label: 'Kanban' }
|
|
507
|
-
]"
|
|
508
|
-
[(value)]="view" />
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
<img src="docs/images/segmented.png" alt="Segmented component" width="560" />
|
|
512
|
-
|
|
513
|
-
</details>
|
|
514
|
-
|
|
515
|
-
<details>
|
|
516
|
-
<summary><strong>Skeleton</strong> — loading placeholder with animated pulse</summary>
|
|
517
|
-
|
|
518
|
-
Variants: `text` | `circle` | `rect`. Custom `width` and `height`. Respects `prefers-reduced-motion`.
|
|
519
|
-
|
|
520
|
-
```html
|
|
521
|
-
<ea-skeleton variant="text" width="200px" />
|
|
522
|
-
<ea-skeleton variant="circle" width="48px" height="48px" />
|
|
523
|
-
<ea-skeleton variant="rect" width="100%" height="120px" />
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
<img src="docs/images/skeleton.png" alt="Skeleton component" width="560" />
|
|
527
|
-
|
|
528
|
-
</details>
|
|
529
|
-
|
|
530
|
-
<details>
|
|
531
|
-
<summary><strong>Slider</strong> — single-value range input with keyboard and pointer drag</summary>
|
|
532
|
-
|
|
533
|
-
Configurable `min`, `max`, `step`. Sizes: `sm` | `md` | `lg`. Optional value display, min/max labels, hint and error messages. Full keyboard navigation (arrows, PageUp/PageDown, Home/End) and `ControlValueAccessor` integration.
|
|
534
|
-
|
|
535
|
-
```html
|
|
536
|
-
<ea-slider
|
|
537
|
-
label="Volume"
|
|
538
|
-
[min]="0"
|
|
539
|
-
[max]="100"
|
|
540
|
-
[step]="5"
|
|
541
|
-
[showValue]="true"
|
|
542
|
-
[(value)]="volume" />
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
<img src="docs/images/slider.png" alt="Slider component" width="560" />
|
|
546
|
-
|
|
547
|
-
</details>
|
|
548
|
-
|
|
549
|
-
<details>
|
|
550
|
-
<summary><strong>Spinner</strong> — SVG loading indicator with accessible role</summary>
|
|
551
|
-
|
|
552
|
-
Sizes: `sm` | `md` | `lg`.
|
|
553
|
-
|
|
554
|
-
```html
|
|
555
|
-
<ea-spinner size="md" label="Loading data" />
|
|
556
|
-
```
|
|
557
|
-
|
|
558
|
-
<img src="docs/images/spinner.png" alt="Spinner component" width="560" />
|
|
559
|
-
|
|
560
|
-
</details>
|
|
561
|
-
|
|
562
|
-
<details>
|
|
563
|
-
<summary><strong>Switch</strong> — toggle with ControlValueAccessor</summary>
|
|
564
|
-
|
|
565
|
-
Sizes: `sm` | `md` | `lg`.
|
|
566
|
-
|
|
567
|
-
```html
|
|
568
|
-
<ea-switch label="Enable notifications" [(checked)]="notificationsOn" />
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
<img src="docs/images/switch.png" alt="Switch component" width="560" />
|
|
572
|
-
|
|
573
|
-
</details>
|
|
574
|
-
|
|
575
|
-
<details>
|
|
576
|
-
<summary><strong>Tabs</strong> — tab navigation with keyboard support</summary>
|
|
577
|
-
|
|
578
|
-
Variants: `underline` | `filled`. Sizes: `sm` | `md` | `lg`.
|
|
579
|
-
|
|
580
|
-
```html
|
|
581
|
-
<ea-tabs activeTab="account" variant="underline">
|
|
582
|
-
<ea-tab value="account" label="Account">Account content</ea-tab>
|
|
583
|
-
<ea-tab value="security" label="Security">Security content</ea-tab>
|
|
584
|
-
</ea-tabs>
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
<img src="docs/images/tabs.png" alt="Tabs component" width="560" />
|
|
588
|
-
|
|
589
|
-
</details>
|
|
590
|
-
|
|
591
|
-
<details>
|
|
592
|
-
<summary><strong>Tag</strong> — inline label with optional remove button</summary>
|
|
593
|
-
|
|
594
|
-
Variants: `default` | `primary` | `success` | `warning` | `error` | `info`. Sizes: `sm` | `md` | `lg`.
|
|
595
|
-
|
|
596
|
-
```html
|
|
597
|
-
<ea-tag variant="primary">TypeScript</ea-tag>
|
|
598
|
-
<ea-tag variant="success" [removable]="true" (removed)="onRemove()">Active</ea-tag>
|
|
599
|
-
```
|
|
600
|
-
|
|
601
|
-
<img src="docs/images/tag.png" alt="Tag component" width="560" />
|
|
602
|
-
|
|
603
|
-
</details>
|
|
604
|
-
|
|
605
|
-
<details>
|
|
606
|
-
<summary><strong>Textarea</strong> — multiline text with ControlValueAccessor</summary>
|
|
607
|
-
|
|
608
|
-
Mirrors the Input API. Configurable `rows`, `resize` (`none` | `vertical` | `horizontal` | `both`), and `maxlength`.
|
|
609
|
-
|
|
610
|
-
```html
|
|
611
|
-
<ea-textarea
|
|
612
|
-
label="Message"
|
|
613
|
-
placeholder="Enter your message…"
|
|
614
|
-
hint="Maximum 500 characters"
|
|
615
|
-
[rows]="4"
|
|
616
|
-
[(value)]="message" />
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
<img src="docs/images/textarea.png" alt="Textarea component" width="560" />
|
|
620
|
-
|
|
621
|
-
</details>
|
|
622
|
-
|
|
623
|
-
<details>
|
|
624
|
-
<summary><strong>Toast</strong> — notification system via injectable ToastService</summary>
|
|
625
|
-
|
|
626
|
-
Variants: `default` | `success` | `warning` | `error` | `info`. Auto-dismiss with configurable duration. Full-width on mobile, independent widths on desktop.
|
|
627
|
-
|
|
628
|
-
```typescript
|
|
629
|
-
import { ToastService } from '@eagami/ui';
|
|
630
|
-
|
|
631
|
-
export class MyComponent {
|
|
632
|
-
private toast = inject(ToastService);
|
|
633
|
-
|
|
634
|
-
save() {
|
|
635
|
-
this.toast.success('Changes saved');
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
handleError() {
|
|
639
|
-
this.toast.error('Something went wrong');
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
```
|
|
643
|
-
|
|
644
|
-
Add the toast outlet once in your root template:
|
|
645
|
-
|
|
646
|
-
```html
|
|
647
|
-
<ea-toast />
|
|
648
|
-
```
|
|
649
|
-
|
|
650
|
-
<img src="docs/images/toast.png" alt="Toast component" width="560" />
|
|
651
|
-
|
|
652
|
-
</details>
|
|
653
|
-
|
|
654
|
-
<details>
|
|
655
|
-
<summary><strong>Tooltip</strong> — positioned tooltip on hover and focus</summary>
|
|
656
|
-
|
|
657
|
-
Positions: `top` | `bottom` | `left` | `right`.
|
|
658
|
-
|
|
659
|
-
```html
|
|
660
|
-
<ea-button eaTooltip="Save your changes" tooltipPosition="top">Save</ea-button>
|
|
661
|
-
```
|
|
662
|
-
|
|
663
|
-
<img src="docs/images/tooltip.png" alt="Tooltip component" width="560" />
|
|
664
|
-
|
|
665
|
-
</details>
|
|
666
|
-
|
|
667
|
-
## Icons
|
|
668
|
-
|
|
669
|
-
<details>
|
|
670
|
-
<summary><strong>52 built-in SVG icon components</strong> — Feather-style (24x24, stroke-based, inherits <code>currentColor</code>)</summary>
|
|
671
|
-
|
|
672
|
-
| Tag | Preview |
|
|
673
|
-
|---|---|
|
|
674
|
-
| `<ea-icon-alert-circle />` | <img src="docs/images/icons/alert-circle.png" width="48" height="48" alt="alert-circle" /> |
|
|
675
|
-
| `<ea-icon-alert-triangle />` | <img src="docs/images/icons/alert-triangle.png" width="48" height="48" alt="alert-triangle" /> |
|
|
676
|
-
| `<ea-icon-apple />` | <img src="docs/images/icons/apple.png" width="48" height="48" alt="apple" /> |
|
|
677
|
-
| `<ea-icon-arrow-down />` | <img src="docs/images/icons/arrow-down.png" width="48" height="48" alt="arrow-down" /> |
|
|
678
|
-
| `<ea-icon-arrow-left />` | <img src="docs/images/icons/arrow-left.png" width="48" height="48" alt="arrow-left" /> |
|
|
679
|
-
| `<ea-icon-arrow-right />` | <img src="docs/images/icons/arrow-right.png" width="48" height="48" alt="arrow-right" /> |
|
|
680
|
-
| `<ea-icon-arrow-up />` | <img src="docs/images/icons/arrow-up.png" width="48" height="48" alt="arrow-up" /> |
|
|
681
|
-
| `<ea-icon-bell />` | <img src="docs/images/icons/bell.png" width="48" height="48" alt="bell" /> |
|
|
682
|
-
| `<ea-icon-calendar />` | <img src="docs/images/icons/calendar.png" width="48" height="48" alt="calendar" /> |
|
|
683
|
-
| `<ea-icon-camera />` | <img src="docs/images/icons/camera.png" width="48" height="48" alt="camera" /> |
|
|
684
|
-
| `<ea-icon-check />` | <img src="docs/images/icons/check.png" width="48" height="48" alt="check" /> |
|
|
685
|
-
| `<ea-icon-check-circle />` | <img src="docs/images/icons/check-circle.png" width="48" height="48" alt="check-circle" /> |
|
|
686
|
-
| `<ea-icon-chevron-down />` | <img src="docs/images/icons/chevron-down.png" width="48" height="48" alt="chevron-down" /> |
|
|
687
|
-
| `<ea-icon-chevron-left />` | <img src="docs/images/icons/chevron-left.png" width="48" height="48" alt="chevron-left" /> |
|
|
688
|
-
| `<ea-icon-chevron-right />` | <img src="docs/images/icons/chevron-right.png" width="48" height="48" alt="chevron-right" /> |
|
|
689
|
-
| `<ea-icon-chevron-up />` | <img src="docs/images/icons/chevron-up.png" width="48" height="48" alt="chevron-up" /> |
|
|
690
|
-
| `<ea-icon-chevrons-up-down />` | <img src="docs/images/icons/chevrons-up-down.png" width="48" height="48" alt="chevrons-up-down" /> |
|
|
691
|
-
| `<ea-icon-clock />` | <img src="docs/images/icons/clock.png" width="48" height="48" alt="clock" /> |
|
|
692
|
-
| `<ea-icon-copy />` | <img src="docs/images/icons/copy.png" width="48" height="48" alt="copy" /> |
|
|
693
|
-
| `<ea-icon-download />` | <img src="docs/images/icons/download.png" width="48" height="48" alt="download" /> |
|
|
694
|
-
| `<ea-icon-eagami />` | <img src="docs/images/icons/eagami.png" width="48" height="48" alt="eagami" /> |
|
|
695
|
-
| `<ea-icon-external-link />` | <img src="docs/images/icons/external-link.png" width="48" height="48" alt="external-link" /> |
|
|
696
|
-
| `<ea-icon-eye />` | <img src="docs/images/icons/eye.png" width="48" height="48" alt="eye" /> |
|
|
697
|
-
| `<ea-icon-eye-off />` | <img src="docs/images/icons/eye-off.png" width="48" height="48" alt="eye-off" /> |
|
|
698
|
-
| `<ea-icon-facebook />` | <img src="docs/images/icons/facebook.png" width="48" height="48" alt="facebook" /> |
|
|
699
|
-
| `<ea-icon-file />` | <img src="docs/images/icons/file.png" width="48" height="48" alt="file" /> |
|
|
700
|
-
| `<ea-icon-filter />` | <img src="docs/images/icons/filter.png" width="48" height="48" alt="filter" /> |
|
|
701
|
-
| `<ea-icon-github />` | <img src="docs/images/icons/github.png" width="48" height="48" alt="github" /> |
|
|
702
|
-
| `<ea-icon-google />` | <img src="docs/images/icons/google.png" width="48" height="48" alt="google" /> |
|
|
703
|
-
| `<ea-icon-heart />` | <img src="docs/images/icons/heart.png" width="48" height="48" alt="heart" /> |
|
|
704
|
-
| `<ea-icon-image />` | <img src="docs/images/icons/image.png" width="48" height="48" alt="image" /> |
|
|
705
|
-
| `<ea-icon-info />` | <img src="docs/images/icons/info.png" width="48" height="48" alt="info" /> |
|
|
706
|
-
| `<ea-icon-link />` | <img src="docs/images/icons/link.png" width="48" height="48" alt="link" /> |
|
|
707
|
-
| `<ea-icon-loader />` | <img src="docs/images/icons/loader.png" width="48" height="48" alt="loader" /> |
|
|
708
|
-
| `<ea-icon-log-out />` | <img src="docs/images/icons/log-out.png" width="48" height="48" alt="log-out" /> |
|
|
709
|
-
| `<ea-icon-mail />` | <img src="docs/images/icons/mail.png" width="48" height="48" alt="mail" /> |
|
|
710
|
-
| `<ea-icon-menu />` | <img src="docs/images/icons/menu.png" width="48" height="48" alt="menu" /> |
|
|
711
|
-
| `<ea-icon-microsoft />` | <img src="docs/images/icons/microsoft.png" width="48" height="48" alt="microsoft" /> |
|
|
712
|
-
| `<ea-icon-minus />` | <img src="docs/images/icons/minus.png" width="48" height="48" alt="minus" /> |
|
|
713
|
-
| `<ea-icon-more-horizontal />` | <img src="docs/images/icons/more-horizontal.png" width="48" height="48" alt="more-horizontal" /> |
|
|
714
|
-
| `<ea-icon-pencil />` | <img src="docs/images/icons/pencil.png" width="48" height="48" alt="pencil" /> |
|
|
715
|
-
| `<ea-icon-plus />` | <img src="docs/images/icons/plus.png" width="48" height="48" alt="plus" /> |
|
|
716
|
-
| `<ea-icon-rotate-ccw />` | <img src="docs/images/icons/rotate-ccw.png" width="48" height="48" alt="rotate-ccw" /> |
|
|
717
|
-
| `<ea-icon-search />` | <img src="docs/images/icons/search.png" width="48" height="48" alt="search" /> |
|
|
718
|
-
| `<ea-icon-settings />` | <img src="docs/images/icons/settings.png" width="48" height="48" alt="settings" /> |
|
|
719
|
-
| `<ea-icon-star />` | <img src="docs/images/icons/star.png" width="48" height="48" alt="star" /> |
|
|
720
|
-
| `<ea-icon-trash />` | <img src="docs/images/icons/trash.png" width="48" height="48" alt="trash" /> |
|
|
721
|
-
| `<ea-icon-upload />` | <img src="docs/images/icons/upload.png" width="48" height="48" alt="upload" /> |
|
|
722
|
-
| `<ea-icon-user />` | <img src="docs/images/icons/user.png" width="48" height="48" alt="user" /> |
|
|
723
|
-
| `<ea-icon-x />` | <img src="docs/images/icons/x.png" width="48" height="48" alt="x" /> |
|
|
724
|
-
| `<ea-icon-x-circle />` | <img src="docs/images/icons/x-circle.png" width="48" height="48" alt="x-circle" /> |
|
|
725
|
-
| `<ea-icon-x-twitter />` | <img src="docs/images/icons/x-twitter.png" width="48" height="48" alt="x-twitter" /> |
|
|
726
|
-
|
|
727
|
-
</details>
|
|
79
|
+
Full per-component documentation — props, events, examples, and accessibility notes — lives at **[eagami.com/ui](https://eagami.com/ui)**.
|
|
728
80
|
|
|
729
81
|
## Theming
|
|
730
82
|
|
|
731
|
-
All visual properties are controlled through CSS custom properties defined on `:root`. Override any token to
|
|
83
|
+
All visual properties are controlled through CSS custom properties defined on `:root`. Override any token to customise the entire library:
|
|
732
84
|
|
|
733
85
|
```css
|
|
734
86
|
:root {
|
|
@@ -766,12 +118,31 @@ Both files contain the full token set, mandatory design rules, theme setup, usag
|
|
|
766
118
|
| `@angular/core` | `^21.0.0` |
|
|
767
119
|
| `@angular/forms` | `^21.0.0` |
|
|
768
120
|
|
|
121
|
+
## Browser support
|
|
122
|
+
|
|
123
|
+
Components are authored for modern evergreen browsers and follow Angular's default [browserslist](https://github.com/browserslist/browserslist) configuration. Specifically:
|
|
124
|
+
|
|
125
|
+
- **Chrome / Edge** — last 2 stable versions
|
|
126
|
+
- **Firefox** — last 2 stable versions, plus the current ESR
|
|
127
|
+
- **Safari** — last 2 stable versions
|
|
128
|
+
- **Modern mobile browsers** (iOS Safari, Chrome Android)
|
|
129
|
+
|
|
130
|
+
The library is published as ES2022. Internet Explorer and pre-Chromium Edge are not supported.
|
|
131
|
+
|
|
132
|
+
### Runtime requirements
|
|
133
|
+
|
|
134
|
+
| Tool | Minimum |
|
|
135
|
+
|------|---------|
|
|
136
|
+
| Node.js | 20.x (for build/dev tooling) |
|
|
137
|
+
| Angular | 21.0 |
|
|
138
|
+
| TypeScript | 5.5 |
|
|
139
|
+
|
|
769
140
|
## Development
|
|
770
141
|
|
|
771
142
|
```bash
|
|
772
143
|
pnpm install # Install dependencies
|
|
773
|
-
pnpm sandbox # Run sandbox dev app
|
|
774
|
-
pnpm storybook # Run Storybook
|
|
144
|
+
pnpm sandbox # Run sandbox dev app on http://localhost:4200
|
|
145
|
+
pnpm storybook # Run Storybook on http://localhost:6006
|
|
775
146
|
pnpm test # Run tests
|
|
776
147
|
pnpm build # Build the library
|
|
777
148
|
pnpm lint # Lint
|