@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.
Files changed (220) hide show
  1. package/COMPONENTS.md +683 -0
  2. package/DEVELOPMENT_GUIDE.md +1102 -0
  3. package/LICENSE +21 -0
  4. package/README.md +69 -0
  5. package/THEMING.md +130 -0
  6. package/core/headline/README.md +121 -0
  7. package/core/icon/README.md +173 -0
  8. package/core/image/README.md +210 -0
  9. package/core/link/README.md +297 -0
  10. package/core/separator/README.md +145 -0
  11. package/core/text/README.md +240 -0
  12. package/directives/infinite-scroll/README.md +102 -0
  13. package/directives/spotlight/README.md +154 -0
  14. package/directives/tooltip/README.md +147 -0
  15. package/docs/endpoint-link/README.md +142 -0
  16. package/docs/method-badge/README.md +154 -0
  17. package/fesm2022/frame-kit-ui-ng-core-headline.mjs +122 -0
  18. package/fesm2022/frame-kit-ui-ng-core-headline.mjs.map +1 -0
  19. package/fesm2022/frame-kit-ui-ng-core-icon.mjs +189 -0
  20. package/fesm2022/frame-kit-ui-ng-core-icon.mjs.map +1 -0
  21. package/fesm2022/frame-kit-ui-ng-core-image.mjs +123 -0
  22. package/fesm2022/frame-kit-ui-ng-core-image.mjs.map +1 -0
  23. package/fesm2022/frame-kit-ui-ng-core-link.mjs +369 -0
  24. package/fesm2022/frame-kit-ui-ng-core-link.mjs.map +1 -0
  25. package/fesm2022/frame-kit-ui-ng-core-separator.mjs +59 -0
  26. package/fesm2022/frame-kit-ui-ng-core-separator.mjs.map +1 -0
  27. package/fesm2022/frame-kit-ui-ng-core-text.mjs +204 -0
  28. package/fesm2022/frame-kit-ui-ng-core-text.mjs.map +1 -0
  29. package/fesm2022/frame-kit-ui-ng-directives-infinite-scroll.mjs +74 -0
  30. package/fesm2022/frame-kit-ui-ng-directives-infinite-scroll.mjs.map +1 -0
  31. package/fesm2022/frame-kit-ui-ng-directives-spotlight.mjs +76 -0
  32. package/fesm2022/frame-kit-ui-ng-directives-spotlight.mjs.map +1 -0
  33. package/fesm2022/frame-kit-ui-ng-directives-tooltip.mjs +425 -0
  34. package/fesm2022/frame-kit-ui-ng-directives-tooltip.mjs.map +1 -0
  35. package/fesm2022/frame-kit-ui-ng-docs-endpoint-link.mjs +63 -0
  36. package/fesm2022/frame-kit-ui-ng-docs-endpoint-link.mjs.map +1 -0
  37. package/fesm2022/frame-kit-ui-ng-docs-method-badge.mjs +43 -0
  38. package/fesm2022/frame-kit-ui-ng-docs-method-badge.mjs.map +1 -0
  39. package/fesm2022/frame-kit-ui-ng-forms.mjs +3632 -0
  40. package/fesm2022/frame-kit-ui-ng-forms.mjs.map +1 -0
  41. package/fesm2022/frame-kit-ui-ng-layouts-app-shell.mjs +239 -0
  42. package/fesm2022/frame-kit-ui-ng-layouts-app-shell.mjs.map +1 -0
  43. package/fesm2022/frame-kit-ui-ng-layouts-content-split.mjs +132 -0
  44. package/fesm2022/frame-kit-ui-ng-layouts-content-split.mjs.map +1 -0
  45. package/fesm2022/frame-kit-ui-ng-services-overlay-orchestrator.mjs +133 -0
  46. package/fesm2022/frame-kit-ui-ng-services-overlay-orchestrator.mjs.map +1 -0
  47. package/fesm2022/frame-kit-ui-ng-services-spotlight.mjs +60 -0
  48. package/fesm2022/frame-kit-ui-ng-services-spotlight.mjs.map +1 -0
  49. package/fesm2022/frame-kit-ui-ng-services-toast.mjs +166 -0
  50. package/fesm2022/frame-kit-ui-ng-services-toast.mjs.map +1 -0
  51. package/fesm2022/frame-kit-ui-ng-ui-accordion.mjs +214 -0
  52. package/fesm2022/frame-kit-ui-ng-ui-accordion.mjs.map +1 -0
  53. package/fesm2022/frame-kit-ui-ng-ui-alert.mjs +82 -0
  54. package/fesm2022/frame-kit-ui-ng-ui-alert.mjs.map +1 -0
  55. package/fesm2022/frame-kit-ui-ng-ui-avatar-stack.mjs +76 -0
  56. package/fesm2022/frame-kit-ui-ng-ui-avatar-stack.mjs.map +1 -0
  57. package/fesm2022/frame-kit-ui-ng-ui-avatar.mjs +81 -0
  58. package/fesm2022/frame-kit-ui-ng-ui-avatar.mjs.map +1 -0
  59. package/fesm2022/frame-kit-ui-ng-ui-badge.mjs +81 -0
  60. package/fesm2022/frame-kit-ui-ng-ui-badge.mjs.map +1 -0
  61. package/fesm2022/frame-kit-ui-ng-ui-breadcrumb.mjs +68 -0
  62. package/fesm2022/frame-kit-ui-ng-ui-breadcrumb.mjs.map +1 -0
  63. package/fesm2022/frame-kit-ui-ng-ui-button.mjs +108 -0
  64. package/fesm2022/frame-kit-ui-ng-ui-button.mjs.map +1 -0
  65. package/fesm2022/frame-kit-ui-ng-ui-callout.mjs +58 -0
  66. package/fesm2022/frame-kit-ui-ng-ui-callout.mjs.map +1 -0
  67. package/fesm2022/frame-kit-ui-ng-ui-card.mjs +70 -0
  68. package/fesm2022/frame-kit-ui-ng-ui-card.mjs.map +1 -0
  69. package/fesm2022/frame-kit-ui-ng-ui-copyable-field.mjs +113 -0
  70. package/fesm2022/frame-kit-ui-ng-ui-copyable-field.mjs.map +1 -0
  71. package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs +1288 -0
  72. package/fesm2022/frame-kit-ui-ng-ui-data-table.mjs.map +1 -0
  73. package/fesm2022/frame-kit-ui-ng-ui-dialog.mjs +456 -0
  74. package/fesm2022/frame-kit-ui-ng-ui-dialog.mjs.map +1 -0
  75. package/fesm2022/frame-kit-ui-ng-ui-drawer.mjs +398 -0
  76. package/fesm2022/frame-kit-ui-ng-ui-drawer.mjs.map +1 -0
  77. package/fesm2022/frame-kit-ui-ng-ui-dropdown-menu.mjs +398 -0
  78. package/fesm2022/frame-kit-ui-ng-ui-dropdown-menu.mjs.map +1 -0
  79. package/fesm2022/frame-kit-ui-ng-ui-editable-field.mjs +125 -0
  80. package/fesm2022/frame-kit-ui-ng-ui-editable-field.mjs.map +1 -0
  81. package/fesm2022/frame-kit-ui-ng-ui-icon-badge.mjs +113 -0
  82. package/fesm2022/frame-kit-ui-ng-ui-icon-badge.mjs.map +1 -0
  83. package/fesm2022/frame-kit-ui-ng-ui-icon-list.mjs +111 -0
  84. package/fesm2022/frame-kit-ui-ng-ui-icon-list.mjs.map +1 -0
  85. package/fesm2022/frame-kit-ui-ng-ui-inline-edit.mjs +103 -0
  86. package/fesm2022/frame-kit-ui-ng-ui-inline-edit.mjs.map +1 -0
  87. package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs +135 -0
  88. package/fesm2022/frame-kit-ui-ng-ui-list-editor.mjs.map +1 -0
  89. package/fesm2022/frame-kit-ui-ng-ui-loader.mjs +81 -0
  90. package/fesm2022/frame-kit-ui-ng-ui-loader.mjs.map +1 -0
  91. package/fesm2022/frame-kit-ui-ng-ui-menu-item.mjs +79 -0
  92. package/fesm2022/frame-kit-ui-ng-ui-menu-item.mjs.map +1 -0
  93. package/fesm2022/frame-kit-ui-ng-ui-nav-brand.mjs +40 -0
  94. package/fesm2022/frame-kit-ui-ng-ui-nav-brand.mjs.map +1 -0
  95. package/fesm2022/frame-kit-ui-ng-ui-nav-group.mjs +110 -0
  96. package/fesm2022/frame-kit-ui-ng-ui-nav-group.mjs.map +1 -0
  97. package/fesm2022/frame-kit-ui-ng-ui-nav-separator.mjs +91 -0
  98. package/fesm2022/frame-kit-ui-ng-ui-nav-separator.mjs.map +1 -0
  99. package/fesm2022/frame-kit-ui-ng-ui-node-tree-breadcrumb.mjs +86 -0
  100. package/fesm2022/frame-kit-ui-ng-ui-node-tree-breadcrumb.mjs.map +1 -0
  101. package/fesm2022/frame-kit-ui-ng-ui-node-tree.mjs +443 -0
  102. package/fesm2022/frame-kit-ui-ng-ui-node-tree.mjs.map +1 -0
  103. package/fesm2022/frame-kit-ui-ng-ui-note.mjs +56 -0
  104. package/fesm2022/frame-kit-ui-ng-ui-note.mjs.map +1 -0
  105. package/fesm2022/frame-kit-ui-ng-ui-numbered-list.mjs +105 -0
  106. package/fesm2022/frame-kit-ui-ng-ui-numbered-list.mjs.map +1 -0
  107. package/fesm2022/frame-kit-ui-ng-ui-pagination.mjs +110 -0
  108. package/fesm2022/frame-kit-ui-ng-ui-pagination.mjs.map +1 -0
  109. package/fesm2022/frame-kit-ui-ng-ui-progress-bar.mjs +129 -0
  110. package/fesm2022/frame-kit-ui-ng-ui-progress-bar.mjs.map +1 -0
  111. package/fesm2022/frame-kit-ui-ng-ui-sidenav-link.mjs +42 -0
  112. package/fesm2022/frame-kit-ui-ng-ui-sidenav-link.mjs.map +1 -0
  113. package/fesm2022/frame-kit-ui-ng-ui-tabs.mjs +894 -0
  114. package/fesm2022/frame-kit-ui-ng-ui-tabs.mjs.map +1 -0
  115. package/fesm2022/frame-kit-ui-ng-ui-timeline.mjs +81 -0
  116. package/fesm2022/frame-kit-ui-ng-ui-timeline.mjs.map +1 -0
  117. package/fesm2022/frame-kit-ui-ng-ui-toast.mjs +179 -0
  118. package/fesm2022/frame-kit-ui-ng-ui-toast.mjs.map +1 -0
  119. package/fesm2022/frame-kit-ui-ng-ui-user-menu.mjs +143 -0
  120. package/fesm2022/frame-kit-ui-ng-ui-user-menu.mjs.map +1 -0
  121. package/fesm2022/frame-kit-ui-ng-ui-wizard-dialog.mjs +191 -0
  122. package/fesm2022/frame-kit-ui-ng-ui-wizard-dialog.mjs.map +1 -0
  123. package/fesm2022/frame-kit-ui-ng.mjs +58 -0
  124. package/fesm2022/frame-kit-ui-ng.mjs.map +1 -0
  125. package/layouts/app-shell/README.md +357 -0
  126. package/layouts/content-split/README.md +180 -0
  127. package/package.json +253 -0
  128. package/services/overlay-orchestrator/README.md +184 -0
  129. package/services/spotlight/README.md +61 -0
  130. package/services/toast/README.md +118 -0
  131. package/types/frame-kit-ui-ng-core-headline.d.ts +38 -0
  132. package/types/frame-kit-ui-ng-core-icon.d.ts +74 -0
  133. package/types/frame-kit-ui-ng-core-image.d.ts +93 -0
  134. package/types/frame-kit-ui-ng-core-link.d.ts +251 -0
  135. package/types/frame-kit-ui-ng-core-separator.d.ts +28 -0
  136. package/types/frame-kit-ui-ng-core-text.d.ts +186 -0
  137. package/types/frame-kit-ui-ng-directives-infinite-scroll.d.ts +42 -0
  138. package/types/frame-kit-ui-ng-directives-spotlight.d.ts +51 -0
  139. package/types/frame-kit-ui-ng-directives-tooltip.d.ts +70 -0
  140. package/types/frame-kit-ui-ng-docs-endpoint-link.d.ts +43 -0
  141. package/types/frame-kit-ui-ng-docs-method-badge.d.ts +30 -0
  142. package/types/frame-kit-ui-ng-forms.d.ts +1674 -0
  143. package/types/frame-kit-ui-ng-layouts-app-shell.d.ts +75 -0
  144. package/types/frame-kit-ui-ng-layouts-content-split.d.ts +43 -0
  145. package/types/frame-kit-ui-ng-services-overlay-orchestrator.d.ts +96 -0
  146. package/types/frame-kit-ui-ng-services-spotlight.d.ts +32 -0
  147. package/types/frame-kit-ui-ng-services-toast.d.ts +100 -0
  148. package/types/frame-kit-ui-ng-ui-accordion.d.ts +86 -0
  149. package/types/frame-kit-ui-ng-ui-alert.d.ts +34 -0
  150. package/types/frame-kit-ui-ng-ui-avatar-stack.d.ts +38 -0
  151. package/types/frame-kit-ui-ng-ui-avatar.d.ts +36 -0
  152. package/types/frame-kit-ui-ng-ui-badge.d.ts +33 -0
  153. package/types/frame-kit-ui-ng-ui-breadcrumb.d.ts +45 -0
  154. package/types/frame-kit-ui-ng-ui-button.d.ts +48 -0
  155. package/types/frame-kit-ui-ng-ui-callout.d.ts +26 -0
  156. package/types/frame-kit-ui-ng-ui-card.d.ts +30 -0
  157. package/types/frame-kit-ui-ng-ui-copyable-field.d.ts +62 -0
  158. package/types/frame-kit-ui-ng-ui-data-table.d.ts +482 -0
  159. package/types/frame-kit-ui-ng-ui-dialog.d.ts +166 -0
  160. package/types/frame-kit-ui-ng-ui-drawer.d.ts +130 -0
  161. package/types/frame-kit-ui-ng-ui-dropdown-menu.d.ts +77 -0
  162. package/types/frame-kit-ui-ng-ui-editable-field.d.ts +65 -0
  163. package/types/frame-kit-ui-ng-ui-icon-badge.d.ts +45 -0
  164. package/types/frame-kit-ui-ng-ui-icon-list.d.ts +67 -0
  165. package/types/frame-kit-ui-ng-ui-inline-edit.d.ts +44 -0
  166. package/types/frame-kit-ui-ng-ui-list-editor.d.ts +56 -0
  167. package/types/frame-kit-ui-ng-ui-loader.d.ts +32 -0
  168. package/types/frame-kit-ui-ng-ui-menu-item.d.ts +27 -0
  169. package/types/frame-kit-ui-ng-ui-nav-brand.d.ts +25 -0
  170. package/types/frame-kit-ui-ng-ui-nav-group.d.ts +60 -0
  171. package/types/frame-kit-ui-ng-ui-nav-separator.d.ts +33 -0
  172. package/types/frame-kit-ui-ng-ui-node-tree-breadcrumb.d.ts +35 -0
  173. package/types/frame-kit-ui-ng-ui-node-tree.d.ts +135 -0
  174. package/types/frame-kit-ui-ng-ui-note.d.ts +22 -0
  175. package/types/frame-kit-ui-ng-ui-numbered-list.d.ts +52 -0
  176. package/types/frame-kit-ui-ng-ui-pagination.d.ts +49 -0
  177. package/types/frame-kit-ui-ng-ui-progress-bar.d.ts +50 -0
  178. package/types/frame-kit-ui-ng-ui-sidenav-link.d.ts +24 -0
  179. package/types/frame-kit-ui-ng-ui-tabs.d.ts +266 -0
  180. package/types/frame-kit-ui-ng-ui-timeline.d.ts +42 -0
  181. package/types/frame-kit-ui-ng-ui-toast.d.ts +56 -0
  182. package/types/frame-kit-ui-ng-ui-user-menu.d.ts +87 -0
  183. package/types/frame-kit-ui-ng-ui-wizard-dialog.d.ts +116 -0
  184. package/types/frame-kit-ui-ng.d.ts +53 -0
  185. package/ui/accordion/README.md +261 -0
  186. package/ui/alert/README.md +211 -0
  187. package/ui/avatar/README.md +167 -0
  188. package/ui/avatar-stack/README.md +164 -0
  189. package/ui/badge/README.md +162 -0
  190. package/ui/breadcrumb/README.md +240 -0
  191. package/ui/button/README.md +184 -0
  192. package/ui/callout/README.md +159 -0
  193. package/ui/card/README.md +174 -0
  194. package/ui/copyable-field/README.md +235 -0
  195. package/ui/data-table/README.md +408 -0
  196. package/ui/dialog/README.md +222 -0
  197. package/ui/drawer/README.md +274 -0
  198. package/ui/dropdown-menu/README.md +336 -0
  199. package/ui/editable-field/README.md +171 -0
  200. package/ui/icon-badge/README.md +131 -0
  201. package/ui/icon-list/README.md +205 -0
  202. package/ui/inline-edit/README.md +135 -0
  203. package/ui/list-editor/README.md +162 -0
  204. package/ui/loader/README.md +160 -0
  205. package/ui/menu-item/README.md +204 -0
  206. package/ui/nav-brand/README.md +111 -0
  207. package/ui/nav-group/README.md +145 -0
  208. package/ui/nav-separator/README.md +44 -0
  209. package/ui/node-tree/README.md +278 -0
  210. package/ui/node-tree-breadcrumb/README.md +164 -0
  211. package/ui/note/README.md +146 -0
  212. package/ui/numbered-list/README.md +187 -0
  213. package/ui/pagination/README.md +174 -0
  214. package/ui/progress-bar/README.md +223 -0
  215. package/ui/sidenav-link/README.md +214 -0
  216. package/ui/tabs/README.md +204 -0
  217. package/ui/timeline/README.md +285 -0
  218. package/ui/toast/README.md +243 -0
  219. package/ui/user-menu/README.md +260 -0
  220. 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
+ ```