@eagami/ui 0.12.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- ## Why @eagami/ui?
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 all form components (Input, Textarea, Checkbox, Switch, Radio, Dropdown)
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
- ## Components
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
- <img src="docs/images/avatar.png" alt="Avatar component" width="560" />
69
+ ## What's included
144
70
 
145
- </details>
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
- <details>
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 customize the entire library:
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