@frame-kit/ui-ng 0.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/COMPONENTS.md +683 -0
- package/DEVELOPMENT_GUIDE.md +1102 -0
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/THEMING.md +130 -0
- package/core/headline/README.md +121 -0
- package/core/icon/README.md +173 -0
- package/core/image/README.md +210 -0
- package/core/link/README.md +297 -0
- package/core/separator/README.md +145 -0
- package/core/text/README.md +240 -0
- package/directives/infinite-scroll/README.md +102 -0
- package/directives/spotlight/README.md +154 -0
- package/directives/tooltip/README.md +147 -0
- package/docs/endpoint-link/README.md +142 -0
- package/docs/method-badge/README.md +154 -0
- package/fesm2022/frame-kit-ui-ng-core-headline.mjs +122 -0
- package/fesm2022/frame-kit-ui-ng-core-headline.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-core-icon.mjs +189 -0
- package/fesm2022/frame-kit-ui-ng-core-icon.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-core-image.mjs +123 -0
- package/fesm2022/frame-kit-ui-ng-core-image.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-core-link.mjs +369 -0
- package/fesm2022/frame-kit-ui-ng-core-link.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-core-separator.mjs +59 -0
- package/fesm2022/frame-kit-ui-ng-core-separator.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-core-text.mjs +204 -0
- package/fesm2022/frame-kit-ui-ng-core-text.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-directives-infinite-scroll.mjs +74 -0
- package/fesm2022/frame-kit-ui-ng-directives-infinite-scroll.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-directives-spotlight.mjs +76 -0
- package/fesm2022/frame-kit-ui-ng-directives-spotlight.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-directives-tooltip.mjs +425 -0
- package/fesm2022/frame-kit-ui-ng-directives-tooltip.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-docs-endpoint-link.mjs +63 -0
- package/fesm2022/frame-kit-ui-ng-docs-endpoint-link.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-docs-method-badge.mjs +43 -0
- package/fesm2022/frame-kit-ui-ng-docs-method-badge.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-forms.mjs +3632 -0
- package/fesm2022/frame-kit-ui-ng-forms.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-layouts-app-shell.mjs +239 -0
- package/fesm2022/frame-kit-ui-ng-layouts-app-shell.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-layouts-content-split.mjs +132 -0
- package/fesm2022/frame-kit-ui-ng-layouts-content-split.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-services-overlay-orchestrator.mjs +133 -0
- package/fesm2022/frame-kit-ui-ng-services-overlay-orchestrator.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-services-spotlight.mjs +60 -0
- package/fesm2022/frame-kit-ui-ng-services-spotlight.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-services-toast.mjs +166 -0
- package/fesm2022/frame-kit-ui-ng-services-toast.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-accordion.mjs +214 -0
- package/fesm2022/frame-kit-ui-ng-ui-accordion.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-alert.mjs +82 -0
- package/fesm2022/frame-kit-ui-ng-ui-alert.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-avatar-stack.mjs +76 -0
- package/fesm2022/frame-kit-ui-ng-ui-avatar-stack.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-avatar.mjs +81 -0
- package/fesm2022/frame-kit-ui-ng-ui-avatar.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-badge.mjs +81 -0
- package/fesm2022/frame-kit-ui-ng-ui-badge.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-breadcrumb.mjs +68 -0
- package/fesm2022/frame-kit-ui-ng-ui-breadcrumb.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-button.mjs +108 -0
- package/fesm2022/frame-kit-ui-ng-ui-button.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-callout.mjs +58 -0
- package/fesm2022/frame-kit-ui-ng-ui-callout.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-card.mjs +70 -0
- package/fesm2022/frame-kit-ui-ng-ui-card.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-copyable-field.mjs +113 -0
- package/fesm2022/frame-kit-ui-ng-ui-copyable-field.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs +1288 -0
- package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-dialog.mjs +456 -0
- package/fesm2022/frame-kit-ui-ng-ui-dialog.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-drawer.mjs +398 -0
- package/fesm2022/frame-kit-ui-ng-ui-drawer.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-dropdown-menu.mjs +398 -0
- package/fesm2022/frame-kit-ui-ng-ui-dropdown-menu.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-editable-field.mjs +125 -0
- package/fesm2022/frame-kit-ui-ng-ui-editable-field.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-icon-badge.mjs +113 -0
- package/fesm2022/frame-kit-ui-ng-ui-icon-badge.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-icon-list.mjs +111 -0
- package/fesm2022/frame-kit-ui-ng-ui-icon-list.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-inline-edit.mjs +103 -0
- package/fesm2022/frame-kit-ui-ng-ui-inline-edit.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs +135 -0
- package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-loader.mjs +81 -0
- package/fesm2022/frame-kit-ui-ng-ui-loader.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-menu-item.mjs +79 -0
- package/fesm2022/frame-kit-ui-ng-ui-menu-item.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-nav-brand.mjs +40 -0
- package/fesm2022/frame-kit-ui-ng-ui-nav-brand.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-nav-group.mjs +110 -0
- package/fesm2022/frame-kit-ui-ng-ui-nav-group.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-nav-separator.mjs +91 -0
- package/fesm2022/frame-kit-ui-ng-ui-nav-separator.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-node-tree-breadcrumb.mjs +86 -0
- package/fesm2022/frame-kit-ui-ng-ui-node-tree-breadcrumb.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-node-tree.mjs +443 -0
- package/fesm2022/frame-kit-ui-ng-ui-node-tree.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-note.mjs +56 -0
- package/fesm2022/frame-kit-ui-ng-ui-note.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-numbered-list.mjs +105 -0
- package/fesm2022/frame-kit-ui-ng-ui-numbered-list.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-pagination.mjs +110 -0
- package/fesm2022/frame-kit-ui-ng-ui-pagination.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-progress-bar.mjs +129 -0
- package/fesm2022/frame-kit-ui-ng-ui-progress-bar.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-sidenav-link.mjs +42 -0
- package/fesm2022/frame-kit-ui-ng-ui-sidenav-link.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-tabs.mjs +894 -0
- package/fesm2022/frame-kit-ui-ng-ui-tabs.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-timeline.mjs +81 -0
- package/fesm2022/frame-kit-ui-ng-ui-timeline.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-toast.mjs +179 -0
- package/fesm2022/frame-kit-ui-ng-ui-toast.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-user-menu.mjs +143 -0
- package/fesm2022/frame-kit-ui-ng-ui-user-menu.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng-ui-wizard-dialog.mjs +191 -0
- package/fesm2022/frame-kit-ui-ng-ui-wizard-dialog.mjs.map +1 -0
- package/fesm2022/frame-kit-ui-ng.mjs +58 -0
- package/fesm2022/frame-kit-ui-ng.mjs.map +1 -0
- package/layouts/app-shell/README.md +357 -0
- package/layouts/content-split/README.md +180 -0
- package/package.json +253 -0
- package/services/overlay-orchestrator/README.md +184 -0
- package/services/spotlight/README.md +61 -0
- package/services/toast/README.md +118 -0
- package/types/frame-kit-ui-ng-core-headline.d.ts +38 -0
- package/types/frame-kit-ui-ng-core-icon.d.ts +74 -0
- package/types/frame-kit-ui-ng-core-image.d.ts +93 -0
- package/types/frame-kit-ui-ng-core-link.d.ts +251 -0
- package/types/frame-kit-ui-ng-core-separator.d.ts +28 -0
- package/types/frame-kit-ui-ng-core-text.d.ts +186 -0
- package/types/frame-kit-ui-ng-directives-infinite-scroll.d.ts +42 -0
- package/types/frame-kit-ui-ng-directives-spotlight.d.ts +51 -0
- package/types/frame-kit-ui-ng-directives-tooltip.d.ts +70 -0
- package/types/frame-kit-ui-ng-docs-endpoint-link.d.ts +43 -0
- package/types/frame-kit-ui-ng-docs-method-badge.d.ts +30 -0
- package/types/frame-kit-ui-ng-forms.d.ts +1674 -0
- package/types/frame-kit-ui-ng-layouts-app-shell.d.ts +75 -0
- package/types/frame-kit-ui-ng-layouts-content-split.d.ts +43 -0
- package/types/frame-kit-ui-ng-services-overlay-orchestrator.d.ts +96 -0
- package/types/frame-kit-ui-ng-services-spotlight.d.ts +32 -0
- package/types/frame-kit-ui-ng-services-toast.d.ts +100 -0
- package/types/frame-kit-ui-ng-ui-accordion.d.ts +86 -0
- package/types/frame-kit-ui-ng-ui-alert.d.ts +34 -0
- package/types/frame-kit-ui-ng-ui-avatar-stack.d.ts +38 -0
- package/types/frame-kit-ui-ng-ui-avatar.d.ts +36 -0
- package/types/frame-kit-ui-ng-ui-badge.d.ts +33 -0
- package/types/frame-kit-ui-ng-ui-breadcrumb.d.ts +45 -0
- package/types/frame-kit-ui-ng-ui-button.d.ts +48 -0
- package/types/frame-kit-ui-ng-ui-callout.d.ts +26 -0
- package/types/frame-kit-ui-ng-ui-card.d.ts +30 -0
- package/types/frame-kit-ui-ng-ui-copyable-field.d.ts +62 -0
- package/types/frame-kit-ui-ng-ui-data-table.d.ts +482 -0
- package/types/frame-kit-ui-ng-ui-dialog.d.ts +166 -0
- package/types/frame-kit-ui-ng-ui-drawer.d.ts +130 -0
- package/types/frame-kit-ui-ng-ui-dropdown-menu.d.ts +77 -0
- package/types/frame-kit-ui-ng-ui-editable-field.d.ts +65 -0
- package/types/frame-kit-ui-ng-ui-icon-badge.d.ts +45 -0
- package/types/frame-kit-ui-ng-ui-icon-list.d.ts +67 -0
- package/types/frame-kit-ui-ng-ui-inline-edit.d.ts +44 -0
- package/types/frame-kit-ui-ng-ui-list-editor.d.ts +56 -0
- package/types/frame-kit-ui-ng-ui-loader.d.ts +32 -0
- package/types/frame-kit-ui-ng-ui-menu-item.d.ts +27 -0
- package/types/frame-kit-ui-ng-ui-nav-brand.d.ts +25 -0
- package/types/frame-kit-ui-ng-ui-nav-group.d.ts +60 -0
- package/types/frame-kit-ui-ng-ui-nav-separator.d.ts +33 -0
- package/types/frame-kit-ui-ng-ui-node-tree-breadcrumb.d.ts +35 -0
- package/types/frame-kit-ui-ng-ui-node-tree.d.ts +135 -0
- package/types/frame-kit-ui-ng-ui-note.d.ts +22 -0
- package/types/frame-kit-ui-ng-ui-numbered-list.d.ts +52 -0
- package/types/frame-kit-ui-ng-ui-pagination.d.ts +49 -0
- package/types/frame-kit-ui-ng-ui-progress-bar.d.ts +50 -0
- package/types/frame-kit-ui-ng-ui-sidenav-link.d.ts +24 -0
- package/types/frame-kit-ui-ng-ui-tabs.d.ts +266 -0
- package/types/frame-kit-ui-ng-ui-timeline.d.ts +42 -0
- package/types/frame-kit-ui-ng-ui-toast.d.ts +56 -0
- package/types/frame-kit-ui-ng-ui-user-menu.d.ts +87 -0
- package/types/frame-kit-ui-ng-ui-wizard-dialog.d.ts +116 -0
- package/types/frame-kit-ui-ng.d.ts +53 -0
- package/ui/accordion/README.md +261 -0
- package/ui/alert/README.md +211 -0
- package/ui/avatar/README.md +167 -0
- package/ui/avatar-stack/README.md +164 -0
- package/ui/badge/README.md +162 -0
- package/ui/breadcrumb/README.md +240 -0
- package/ui/button/README.md +184 -0
- package/ui/callout/README.md +159 -0
- package/ui/card/README.md +174 -0
- package/ui/copyable-field/README.md +235 -0
- package/ui/data-table/README.md +408 -0
- package/ui/dialog/README.md +222 -0
- package/ui/drawer/README.md +274 -0
- package/ui/dropdown-menu/README.md +336 -0
- package/ui/editable-field/README.md +171 -0
- package/ui/icon-badge/README.md +131 -0
- package/ui/icon-list/README.md +205 -0
- package/ui/inline-edit/README.md +135 -0
- package/ui/list-editor/README.md +162 -0
- package/ui/loader/README.md +160 -0
- package/ui/menu-item/README.md +204 -0
- package/ui/nav-brand/README.md +111 -0
- package/ui/nav-group/README.md +145 -0
- package/ui/nav-separator/README.md +44 -0
- package/ui/node-tree/README.md +278 -0
- package/ui/node-tree-breadcrumb/README.md +164 -0
- package/ui/note/README.md +146 -0
- package/ui/numbered-list/README.md +187 -0
- package/ui/pagination/README.md +174 -0
- package/ui/progress-bar/README.md +223 -0
- package/ui/sidenav-link/README.md +214 -0
- package/ui/tabs/README.md +204 -0
- package/ui/timeline/README.md +285 -0
- package/ui/toast/README.md +243 -0
- package/ui/user-menu/README.md +260 -0
- package/ui/wizard-dialog/README.md +283 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# Toast System
|
|
2
|
+
|
|
3
|
+
A token-driven toast notification system with a signal-based service, default severity toasts, and support for fully custom toast components.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### 1. Add the container to your app root (once)
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<router-outlet /> <fk-toast-container position="top-right" />
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### 2. Show toasts from anywhere
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
private readonly toast = inject(ToastService);
|
|
19
|
+
|
|
20
|
+
this.toast.success("Saved successfully");
|
|
21
|
+
this.toast.error("Failed to save", "Please try again.");
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Components
|
|
27
|
+
|
|
28
|
+
### `fk-toast` — Individual Toast
|
|
29
|
+
|
|
30
|
+
Renders a single toast notification with severity icon, summary, optional detail, and dismiss button. Typically rendered by the container — not placed manually.
|
|
31
|
+
|
|
32
|
+
#### Inputs
|
|
33
|
+
|
|
34
|
+
| Input | Type | Default | Description |
|
|
35
|
+
| ------------- | ---------------- | -------- | ------------------------------------------------ |
|
|
36
|
+
| `severity` | `ToastSeverity` | `"info"` | Severity (`success`, `error`, `warning`, `info`) |
|
|
37
|
+
| `summary` | `string` | `""` | Primary message |
|
|
38
|
+
| `detail` | `string` | — | Optional secondary detail |
|
|
39
|
+
| `dismissible` | `boolean` | `true` | Whether to show a dismiss button |
|
|
40
|
+
| `className` | `string` | `""` | Additional CSS classes |
|
|
41
|
+
| `id` | `string \| null` | `null` | Optional ID |
|
|
42
|
+
|
|
43
|
+
#### Outputs
|
|
44
|
+
|
|
45
|
+
| Output | Type | Description |
|
|
46
|
+
| --------- | ------ | ------------------------------- |
|
|
47
|
+
| `dismiss` | `void` | Emitted when dismiss is clicked |
|
|
48
|
+
|
|
49
|
+
### `fk-toast-container` — Toast Stack
|
|
50
|
+
|
|
51
|
+
Positioned container that renders toasts from `ToastService`. Place once in the app root.
|
|
52
|
+
|
|
53
|
+
#### Inputs
|
|
54
|
+
|
|
55
|
+
| Input | Type | Default | Description |
|
|
56
|
+
| ----------- | ---------------- | ------------- | ------------------------------------------------------------------------------------------------ |
|
|
57
|
+
| `position` | `ToastPosition` | `"top-right"` | Position (`top-right`, `top-center`, `top-left`, `bottom-right`, `bottom-center`, `bottom-left`) |
|
|
58
|
+
| `className` | `string` | `""` | Additional CSS classes |
|
|
59
|
+
| `id` | `string \| null` | `null` | Optional ID |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## ToastService API
|
|
64
|
+
|
|
65
|
+
| Method | Description |
|
|
66
|
+
| -------------------------------------------------- | ------------------------------------- |
|
|
67
|
+
| `success(summary, detail?)` | Show a success toast |
|
|
68
|
+
| `error(summary, detail?)` | Show an error toast (longer duration) |
|
|
69
|
+
| `warning(summary, detail?)` | Show a warning toast |
|
|
70
|
+
| `info(summary, detail?)` | Show an info toast |
|
|
71
|
+
| `show({ severity, summary, detail?, duration? })` | Show with full options |
|
|
72
|
+
| `open(Component, { severity?, data?, duration? })` | Show a custom component toast |
|
|
73
|
+
| `dismiss(id)` | Dismiss a specific toast |
|
|
74
|
+
| `clear()` | Clear all toasts |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Import
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { ToastContainerComponent, ToastService } from '@frame-kit/ui-ng';
|
|
82
|
+
|
|
83
|
+
// For custom component toasts:
|
|
84
|
+
import { TOAST_DATA, TOAST_REF, ToastRef } from '@frame-kit/ui-ng';
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Features
|
|
90
|
+
|
|
91
|
+
- Built-in inline SVG icons per severity — no icon registry required
|
|
92
|
+
- Optional global icon overrides via `provideToastConfig()`
|
|
93
|
+
- Signal-based service with auto-dismiss and reference counting
|
|
94
|
+
- Six position variants for the container
|
|
95
|
+
- Custom component toasts via `open()` — render any component inside the toast shell
|
|
96
|
+
- Severity-driven color accents via design tokens
|
|
97
|
+
- Dark mode support
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Configuration
|
|
102
|
+
|
|
103
|
+
### Global config (optional)
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { provideToastConfig } from '@frame-kit/ui-ng';
|
|
107
|
+
|
|
108
|
+
// In app.config.ts providers:
|
|
109
|
+
provideToastConfig({
|
|
110
|
+
defaultDuration: 4000,
|
|
111
|
+
errorDuration: 10000,
|
|
112
|
+
icons: {
|
|
113
|
+
success: 'circle-check-outline',
|
|
114
|
+
error: 'circle-xmark-outline',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
When icon names are provided and found in `IconRegistryService`, they replace the built-in SVGs. If not found, the built-in SVGs are used as fallback.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Custom Component Toasts
|
|
124
|
+
|
|
125
|
+
For toasts that need buttons, custom layouts, or interactive content, pass a component to `open()`:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
@Component({
|
|
129
|
+
standalone: true,
|
|
130
|
+
imports: [ButtonComponent],
|
|
131
|
+
template: `
|
|
132
|
+
<div style="padding: 1rem;">
|
|
133
|
+
<p>{{ data.message }}</p>
|
|
134
|
+
<div style="display: flex; gap: 0.5rem; margin-top: 0.75rem;">
|
|
135
|
+
<fk-button variant="primary" size="sm" (click)="retry()">Retry</fk-button>
|
|
136
|
+
<fk-button variant="outline" size="sm" (click)="ref.dismiss()">Dismiss</fk-button>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
`,
|
|
140
|
+
})
|
|
141
|
+
export class RetryToastComponent {
|
|
142
|
+
readonly data = inject(TOAST_DATA) as { message: string; retryFn: () => void };
|
|
143
|
+
readonly ref = inject(TOAST_REF);
|
|
144
|
+
|
|
145
|
+
retry(): void {
|
|
146
|
+
this.ref.dismiss();
|
|
147
|
+
this.data.retryFn();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// Call site
|
|
154
|
+
this.toastService.open(RetryToastComponent, {
|
|
155
|
+
severity: 'error',
|
|
156
|
+
data: { message: 'Failed to save', retryFn: () => this.save() },
|
|
157
|
+
duration: 0, // no auto-dismiss
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The container provides a severity-accented wrapper (border, background, shadow). The component controls all content inside.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Accessibility
|
|
166
|
+
|
|
167
|
+
- Default toasts use `role="alert"` for error/warning, `role="status"` for success/info
|
|
168
|
+
- Dismiss buttons have `aria-label="Dismiss"`
|
|
169
|
+
- Focus ring uses `--fk-focus-ring` token
|
|
170
|
+
- Container uses `pointer-events: none` so it doesn't block page interaction
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Design Tokens
|
|
175
|
+
|
|
176
|
+
### Toast
|
|
177
|
+
|
|
178
|
+
```scss
|
|
179
|
+
// Layout
|
|
180
|
+
--fk-toast-gap // → --fk-rhythm-3
|
|
181
|
+
--fk-toast-padding // → --fk-rhythm-4
|
|
182
|
+
--fk-toast-border-color // → --fk-color-border
|
|
183
|
+
--fk-toast-border-radius // → --fk-radius-lg
|
|
184
|
+
--fk-toast-bg // → --fk-color-surface
|
|
185
|
+
--fk-toast-shadow
|
|
186
|
+
|
|
187
|
+
// Icon
|
|
188
|
+
--fk-toast-icon-size
|
|
189
|
+
|
|
190
|
+
// Severity accents
|
|
191
|
+
--fk-toast-success-accent // → --fk-color-success
|
|
192
|
+
--fk-toast-success-color
|
|
193
|
+
--fk-toast-error-accent // → --fk-color-danger
|
|
194
|
+
--fk-toast-error-color
|
|
195
|
+
--fk-toast-warning-accent // → --fk-color-warning
|
|
196
|
+
--fk-toast-warning-color
|
|
197
|
+
--fk-toast-info-accent // → --fk-color-primary
|
|
198
|
+
--fk-toast-info-color
|
|
199
|
+
|
|
200
|
+
// Typography
|
|
201
|
+
--fk-toast-summary-font-size // → --fk-typography-body-font-size
|
|
202
|
+
--fk-toast-summary-font-weight // → --fk-font-weight-semibold
|
|
203
|
+
--fk-toast-summary-color // → --fk-color-text
|
|
204
|
+
--fk-toast-detail-font-size // → --fk-typography-small-font-size
|
|
205
|
+
--fk-toast-detail-color // → --fk-color-muted
|
|
206
|
+
--fk-toast-body-gap // → --fk-rhythm-1
|
|
207
|
+
|
|
208
|
+
// Dismiss
|
|
209
|
+
--fk-toast-dismiss-size
|
|
210
|
+
--fk-toast-dismiss-color // → --fk-color-muted
|
|
211
|
+
--fk-toast-dismiss-hover-color // → --fk-color-text
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Container
|
|
215
|
+
|
|
216
|
+
```scss
|
|
217
|
+
--fk-toast-container-z-index // default: 9500
|
|
218
|
+
--fk-toast-container-gap // → --fk-rhythm-3
|
|
219
|
+
--fk-toast-container-padding // → --fk-rhythm-4
|
|
220
|
+
--fk-toast-container-max-width // default: 24rem
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Customizing
|
|
224
|
+
|
|
225
|
+
```css
|
|
226
|
+
:root {
|
|
227
|
+
--fk-toast-border-radius: 0.75rem;
|
|
228
|
+
--fk-toast-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
229
|
+
--fk-toast-container-max-width: 30rem;
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Behavior Notes
|
|
236
|
+
|
|
237
|
+
- Default toast duration: 5s (success/warning/info), 8s (error)
|
|
238
|
+
- Set `duration: 0` to disable auto-dismiss for a specific toast
|
|
239
|
+
- Toast z-index (9500) is below the loading overlay (10000)
|
|
240
|
+
- Container `pointer-events: none` with `pointer-events: auto` on individual toasts
|
|
241
|
+
- Bottom positions stack in reverse order (newest at bottom)
|
|
242
|
+
- Custom component toasts are created imperatively via `createComponent` — same pattern as `DialogService`
|
|
243
|
+
- `TOAST_REF.dismiss()` removes the toast from the stack and cleans up the component
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# fk-user-menu
|
|
2
|
+
|
|
3
|
+
A token-driven user menu molecule that composes an avatar trigger with a dropdown panel of configurable menu items, supporting keyboard navigation, status indicators, and multiple display variants.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## API
|
|
8
|
+
|
|
9
|
+
### Inputs
|
|
10
|
+
|
|
11
|
+
| Input | Type | Default | Description |
|
|
12
|
+
| ------------- | ----------------------------------------------------------- | -------------- | ------------------------------------------------------------------------------ |
|
|
13
|
+
| name | `string` | — | **Required.** User's display name |
|
|
14
|
+
| email | `string` \| `null` | `null` | User's email address |
|
|
15
|
+
| avatarUrl | `string` \| `null` | `null` | URL to the user's avatar image |
|
|
16
|
+
| initials | `string` \| `null` | `null` | Custom initials — auto-derived from `name` if absent |
|
|
17
|
+
| userId | `string` \| `null` | `null` | Optional user identifier |
|
|
18
|
+
| status | `"online"` \| `"offline"` \| `"away"` \| `"busy"` \| `null` | `null` | Presence status passed to the avatar |
|
|
19
|
+
| showStatus | `boolean` | `false` | Show the status indicator on the avatar |
|
|
20
|
+
| menuItems | `MenuItem[]` | `[]` | Configurable list of menu actions |
|
|
21
|
+
| placement | `"bottom-start"` \| `"bottom-end"` | `"bottom-end"` | Preferred panel alignment — auto-flips and shifts to stay within the viewport |
|
|
22
|
+
| size | `"sm"` \| `"md"` \| `"lg"` | `"md"` | Avatar size |
|
|
23
|
+
| variant | `"dropdown"` \| `"popover"` | `"dropdown"` | `"popover"` adds a user header inside the panel |
|
|
24
|
+
| showName | `boolean` | `false` | Show user name next to the avatar in the trigger |
|
|
25
|
+
| showEmail | `boolean` | `false` | Show email next to the avatar in the trigger |
|
|
26
|
+
| showChevron | `boolean` | `true` | Show a chevron indicator on the trigger |
|
|
27
|
+
| infoPlacement | `"start"` \| `"end"` | `"end"` | Position name/email relative to the avatar — `"start"` places text on the left |
|
|
28
|
+
| badge | `string` \| `null` | `null` | Badge label (e.g. "Admin", "Pro") |
|
|
29
|
+
| disabled | `boolean` | `false` | Disable the trigger |
|
|
30
|
+
| loading | `boolean` | `false` | Disable the trigger during loading |
|
|
31
|
+
| className | `string` | `""` | Additional CSS classes merged with hook classes |
|
|
32
|
+
| id | `string` \| `null` | `null` | Sets the host `id` attribute |
|
|
33
|
+
| ariaLabel | `string` \| `null` | `null` | Custom `aria-label` (defaults to "User menu for {name}") |
|
|
34
|
+
|
|
35
|
+
### Outputs
|
|
36
|
+
|
|
37
|
+
| Output | Payload | Description |
|
|
38
|
+
| ------------- | ---------- | ----------------------------------------------------------- |
|
|
39
|
+
| avatarClick | `void` | Emitted when the trigger is clicked |
|
|
40
|
+
| menuOpen | `void` | Emitted when the dropdown opens |
|
|
41
|
+
| menuClose | `void` | Emitted when the dropdown closes |
|
|
42
|
+
| menuItemClick | `MenuItem` | Emitted when any menu item is selected |
|
|
43
|
+
| logoutClick | `void` | Emitted when a menu item with `value: "logout"` is selected |
|
|
44
|
+
|
|
45
|
+
### MenuItem Type
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
interface MenuItem {
|
|
49
|
+
label: string;
|
|
50
|
+
value: string;
|
|
51
|
+
icon?: string;
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
danger?: boolean;
|
|
54
|
+
separator?: boolean;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
When `separator` is `true`, the item renders as a horizontal divider instead of a button.
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Features
|
|
63
|
+
|
|
64
|
+
- Composes `fk-avatar` for the trigger display
|
|
65
|
+
- Configurable menu items with icons, danger styling, disabled state, and separators
|
|
66
|
+
- Two variants: `dropdown` (items only) and `popover` (user header + items)
|
|
67
|
+
- Optional name, email, badge, and chevron in the trigger with configurable info placement (`start` or `end`)
|
|
68
|
+
- Viewport-aware positioning — panel auto-flips vertically and shifts horizontally to avoid clipping
|
|
69
|
+
- Closes on outside click, Escape, or Tab
|
|
70
|
+
- Full keyboard navigation with ArrowUp/Down, Home/End, Enter/Space
|
|
71
|
+
- Token-driven styling for trigger, panel, items, badge, and separator
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Quick Start
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<fk-user-menu name="Jane Doe" [menuItems]="menuItems" (menuItemClick)="onMenuItem($event)" (logoutClick)="onLogout()" />
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
menuItems: MenuItem[] = [
|
|
83
|
+
{ label: "Profile", value: "profile", icon: "user" },
|
|
84
|
+
{ label: "Settings", value: "settings", icon: "gear-outline" },
|
|
85
|
+
{ separator: true, label: "", value: "sep" },
|
|
86
|
+
{ label: "Logout", value: "logout", danger: true },
|
|
87
|
+
];
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Import
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { UserMenuComponent } from '@frame-kit/ui-ng';
|
|
96
|
+
import type { MenuItem } from '@frame-kit/ui-ng';
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
@Component({
|
|
101
|
+
selector: 'app-header',
|
|
102
|
+
imports: [UserMenuComponent],
|
|
103
|
+
templateUrl: './header.component.html',
|
|
104
|
+
})
|
|
105
|
+
export class HeaderComponent {}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Selector
|
|
111
|
+
|
|
112
|
+
```html
|
|
113
|
+
<fk-user-menu />
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Examples
|
|
119
|
+
|
|
120
|
+
### Minimal
|
|
121
|
+
|
|
122
|
+
```html
|
|
123
|
+
<fk-user-menu name="Jane Doe" [menuItems]="menuItems" />
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### With Name, Email, and Badge
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<fk-user-menu name="Jane Doe" email="jane@acme.com" avatarUrl="/assets/jane.jpg" [showName]="true" [showEmail]="true" badge="Admin" [menuItems]="menuItems" />
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Popover Variant
|
|
133
|
+
|
|
134
|
+
Shows a user header (name + email) inside the dropdown panel.
|
|
135
|
+
|
|
136
|
+
```html
|
|
137
|
+
<fk-user-menu name="Jane Doe" email="jane@acme.com" variant="popover" [menuItems]="menuItems" />
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Info on the Left
|
|
141
|
+
|
|
142
|
+
Places the name and email to the left of the avatar, right-aligned against it.
|
|
143
|
+
|
|
144
|
+
```html
|
|
145
|
+
<fk-user-menu name="Jane Doe" email="jane@acme.com" [showName]="true" [showEmail]="true" infoPlacement="start" [menuItems]="menuItems" />
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### With Status Indicator
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<fk-user-menu name="Jane Doe" [showStatus]="true" status="online" [menuItems]="menuItems" />
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### In a Dashboard Header
|
|
155
|
+
|
|
156
|
+
```html
|
|
157
|
+
<header class="dashboard-header">
|
|
158
|
+
<span class="dashboard-header__start">
|
|
159
|
+
<fk-nav-brand label="Acme" />
|
|
160
|
+
</span>
|
|
161
|
+
|
|
162
|
+
<span class="dashboard-header__end">
|
|
163
|
+
<fk-user-menu [name]="currentUser.name" [email]="currentUser.email" [avatarUrl]="currentUser.avatar" [showStatus]="true" [status]="currentUser.status" variant="popover" placement="bottom-end" [menuItems]="userMenuItems" (menuItemClick)="handleMenuItem($event)" (logoutClick)="logout()" />
|
|
164
|
+
</span>
|
|
165
|
+
</header>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Accessibility
|
|
171
|
+
|
|
172
|
+
- Trigger is a native `<button>` with `aria-haspopup="menu"` and `aria-expanded`
|
|
173
|
+
- Panel has `role="menu"` with an `aria-label`
|
|
174
|
+
- Each item has `role="menuitem"` and `aria-disabled` when applicable
|
|
175
|
+
- Separators have `role="separator"`
|
|
176
|
+
- Keyboard support:
|
|
177
|
+
- **Enter / Space** — open menu or select focused item
|
|
178
|
+
- **Escape** — close menu
|
|
179
|
+
- **ArrowDown / ArrowUp** — move focus between items (skips disabled)
|
|
180
|
+
- **Home / End** — jump to first / last item
|
|
181
|
+
- **Tab** — close menu and move focus naturally
|
|
182
|
+
- Focus ring applied via `--fk-user-menu-focus-ring` token on both trigger and items
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Design Tokens
|
|
187
|
+
|
|
188
|
+
### Component Tokens
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
--fk-user-menu-trigger-gap
|
|
192
|
+
--fk-user-menu-trigger-padding
|
|
193
|
+
--fk-user-menu-trigger-radius
|
|
194
|
+
--fk-user-menu-trigger-bg
|
|
195
|
+
--fk-user-menu-trigger-bg-hover
|
|
196
|
+
--fk-user-menu-focus-ring
|
|
197
|
+
--fk-user-menu-opacity-disabled
|
|
198
|
+
--fk-user-menu-name-font-family
|
|
199
|
+
--fk-user-menu-name-font-size
|
|
200
|
+
--fk-user-menu-name-font-weight
|
|
201
|
+
--fk-user-menu-name-color
|
|
202
|
+
--fk-user-menu-email-font-family
|
|
203
|
+
--fk-user-menu-email-font-size
|
|
204
|
+
--fk-user-menu-email-color
|
|
205
|
+
--fk-user-menu-chevron-color
|
|
206
|
+
--fk-user-menu-badge-radius
|
|
207
|
+
--fk-user-menu-badge-bg
|
|
208
|
+
--fk-user-menu-badge-color
|
|
209
|
+
--fk-user-menu-badge-font-family
|
|
210
|
+
--fk-user-menu-badge-font-size
|
|
211
|
+
--fk-user-menu-badge-font-weight
|
|
212
|
+
--fk-user-menu-panel-z
|
|
213
|
+
--fk-user-menu-panel-min-width
|
|
214
|
+
--fk-user-menu-panel-padding
|
|
215
|
+
--fk-user-menu-panel-radius
|
|
216
|
+
--fk-user-menu-panel-bg
|
|
217
|
+
--fk-user-menu-panel-border
|
|
218
|
+
--fk-user-menu-panel-shadow
|
|
219
|
+
--fk-user-menu-item-gap
|
|
220
|
+
--fk-user-menu-item-padding
|
|
221
|
+
--fk-user-menu-item-radius
|
|
222
|
+
--fk-user-menu-item-font-family
|
|
223
|
+
--fk-user-menu-item-font-size
|
|
224
|
+
--fk-user-menu-item-color
|
|
225
|
+
--fk-user-menu-item-bg-hover
|
|
226
|
+
--fk-user-menu-item-danger-color
|
|
227
|
+
--fk-user-menu-item-danger-bg-hover
|
|
228
|
+
--fk-user-menu-separator-color
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Each component token falls back to a semantic token, then a raw value. For example:
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
--fk-user-menu-panel-bg → --fk-color-surface → #ffffff
|
|
235
|
+
--fk-user-menu-item-color → --fk-color-text → #1f2d3d
|
|
236
|
+
--fk-user-menu-item-bg-hover → --fk-color-surface-muted → #f7f9fb
|
|
237
|
+
--fk-user-menu-panel-radius → --fk-radius-lg → 0.75rem
|
|
238
|
+
--fk-user-menu-item-danger-color → --fk-color-danger → #e02424
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Customizing Tokens
|
|
242
|
+
|
|
243
|
+
Override tokens at any scope:
|
|
244
|
+
|
|
245
|
+
```css
|
|
246
|
+
:root {
|
|
247
|
+
--fk-user-menu-panel-radius: 0.5rem;
|
|
248
|
+
--fk-user-menu-panel-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
249
|
+
--fk-user-menu-badge-bg: #7c3aed;
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Or scope to a specific context:
|
|
254
|
+
|
|
255
|
+
```css
|
|
256
|
+
.compact-nav fk-user-menu {
|
|
257
|
+
--fk-user-menu-trigger-padding: 0.125rem;
|
|
258
|
+
--fk-user-menu-panel-min-width: 10rem;
|
|
259
|
+
}
|
|
260
|
+
```
|