@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,222 @@
1
+ # fk-dialog
2
+
3
+ An accessible, token-driven dialog / modal component with focus management, scroll locking, and flexible close behavior.
4
+
5
+ ---
6
+
7
+ ## API
8
+
9
+ ### Inputs
10
+
11
+ | Input | Type | Default | Description |
12
+ | ------------------ | -------------------- | -------------- | ----------------------------------------------------------------------------------- |
13
+ | `open` | `boolean` | `false` | Whether the dialog is open |
14
+ | `modal` | `boolean` | `true` | When `true`, locks body scroll while open |
15
+ | `closable` | `boolean` | `true` | Whether the dialog shows close affordances (e.g. close button) |
16
+ | `closeOnEscape` | `boolean` | `true` | Close when Escape key is pressed |
17
+ | `closeOnBackdrop` | `boolean` | `false` | Close when clicking the backdrop |
18
+ | `size` | `DialogSize` | `"md"` | Size variant (`sm`, `md`, `lg`, `xl`, `fullscreen`) |
19
+ | `position` | `DialogPosition` | `"center"` | Position of the dialog (`center`, `top`) |
20
+ | `header` | `string \| null` | `null` | Default header text; used for `aria-labelledby` when no `ariaLabel` is set |
21
+ | `restoreFocus` | `boolean` | `true` | Restore focus to the previously focused element on close |
22
+ | `autoFocus` | `boolean` | `true` | Auto-focus the dialog content on open |
23
+ | `animation` | `DialogAnimation` | `"scale-fade"` | Animation preset (`"none"`, `"scale-fade"`, `"fade"`, `"slide-up"`, `"slide-down"`) |
24
+ | `preventClose` | `boolean` | `false` | When `true`, disables closing entirely |
25
+ | `canClose` | `CanCloseFn \| null` | `null` | Optional guard function, sync or async, that must return `true` to allow close |
26
+ | `fullscreenMobile` | `boolean` | `false` | Expand to fullscreen on small viewports |
27
+ | `flexBody` | `boolean` | `false` | Make the body a flex column container (for wizard/complex layouts) |
28
+ | `className` | `string` | `''` | Additional CSS classes for the host |
29
+ | `id` | `string \| null` | `null` | Optional ID for the host |
30
+ | `ariaLabel` | `string \| null` | `null` | ARIA label when no visible header is used |
31
+ | `ariaDescribedBy` | `string \| null` | `null` | IDs of elements describing the dialog |
32
+
33
+ **`canClose` can be asynchronous.** Return a `boolean` or a `Promise<boolean>`; returning/resolving to `false` will keep the dialog open.
34
+
35
+ ### Outputs
36
+
37
+ | Output | Type | Description |
38
+ | ------------- | --------- | ---------------------------------------------- |
39
+ | `openChange` | `boolean` | Emitted when the `open` state should change |
40
+ | `beforeOpen` | `void` | Emitted just before the dialog becomes visible |
41
+ | `opened` | `void` | Emitted after the dialog is visible |
42
+ | `beforeClose` | `void` | Emitted just before closing logic runs |
43
+ | `closed` | `void` | Emitted after the dialog has closed |
44
+
45
+ ### Content Slots
46
+
47
+ | Slot | Selector | Description |
48
+ | ----------------- | ------------------- | ----------------------------------------------------------------------------- |
49
+ | **Default** | (none) | Dialog body content |
50
+ | **Custom header** | `[fkDialogHeader]` | Replaces the default header text. Close button is still rendered separately |
51
+ | **Footer** | `[libDialogFooter]` | Pinned footer outside the scrollable body, with flex layout and border-top |
52
+ | **Actions** | `[fkDialogActions]` | Inline action row inside the body (scrolls with content), equal-width buttons |
53
+
54
+ ---
55
+
56
+ ## Features
57
+
58
+ - Portalled dialog with backdrop, scroll locking, and focus restoration
59
+ - Configurable size, position, and animation
60
+ - Guardable close behavior (`preventClose`, `canClose`)
61
+ - Escape and backdrop handling
62
+ - Default header via `header` input, or fully custom header via `[fkDialogHeader]` directive
63
+ - Footer slot with built-in flex layout
64
+
65
+ ---
66
+
67
+ ## Quick Start
68
+
69
+ ```html
70
+ <fk-dialog [open]="isOpen" header="Confirm deletion" (openChange)="isOpen = $event">
71
+ <p>Are you sure you want to delete this record?</p>
72
+ <div libDialogFooter>
73
+ <fk-button variant="secondary" (click)="isOpen = false">Cancel</fk-button>
74
+ <fk-button variant="primary" (click)="confirmDelete()">Delete</fk-button>
75
+ </div>
76
+ </fk-dialog>
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Import
82
+
83
+ ```ts
84
+ import { DialogComponent, FkDialogHeaderDirective } from '@frame-kit/ui-ng';
85
+ ```
86
+
87
+ ```ts
88
+ @Component({
89
+ selector: 'app-example',
90
+ imports: [DialogComponent, FkDialogHeaderDirective],
91
+ templateUrl: './example.component.html',
92
+ })
93
+ export class ExampleComponent {}
94
+ ```
95
+
96
+ > `FkDialogHeaderDirective` is only needed if you use a custom header.
97
+
98
+ ---
99
+
100
+ ## Selector
101
+
102
+ ```html
103
+ <fk-dialog></fk-dialog>
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Examples
109
+
110
+ ### Default header
111
+
112
+ The `header` input renders centered text in the header area. When no `ariaLabel` is provided, the header text is linked via `aria-labelledby`.
113
+
114
+ ```html
115
+ <fk-dialog [open]="isOpen" header="Edit record" (openChange)="isOpen = $event">
116
+ <!-- form fields -->
117
+ </fk-dialog>
118
+ ```
119
+
120
+ ### Custom header
121
+
122
+ Use the `[fkDialogHeader]` directive to project fully custom header content. The close button is still rendered separately when `closable` is `true`.
123
+
124
+ ```html
125
+ <fk-dialog [open]="isOpen" (openChange)="isOpen = $event">
126
+ <div fkDialogHeader>
127
+ <fk-icon name="settings" size="sm"></fk-icon>
128
+ <span>Custom Title</span>
129
+ </div>
130
+
131
+ <p>Dialog body content here.</p>
132
+
133
+ <div libDialogFooter>
134
+ <fk-button variant="secondary" (click)="isOpen = false">Cancel</fk-button>
135
+ <fk-button variant="primary" (click)="save()">Save</fk-button>
136
+ </div>
137
+ </fk-dialog>
138
+ ```
139
+
140
+ > When using a custom header, the default `header` text input is ignored. Provide an `ariaLabel` for accessibility since `aria-labelledby` won't be set automatically.
141
+
142
+ ### With async `canClose`
143
+
144
+ ```ts
145
+ canClose = async () => {
146
+ const confirmed = await this.confirmService.open('Unsaved changes, leave?');
147
+ return confirmed;
148
+ };
149
+ ```
150
+
151
+ ```html
152
+ <fk-dialog [open]="isEditing" header="Edit record" [canClose]="canClose" (openChange)="isEditing = $event">
153
+ <!-- form fields -->
154
+ </fk-dialog>
155
+ ```
156
+
157
+ ### Fullscreen on mobile
158
+
159
+ ```html
160
+ <fk-dialog [open]="isOpen" header="Filters" [fullscreenMobile]="true" (openChange)="isOpen = $event">
161
+ <!-- filter controls -->
162
+ </fk-dialog>
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Accessibility
168
+
169
+ - Uses ARIA dialog patterns with `aria-modal` semantics when `modal` is `true`
170
+ - Focus is trapped inside while open (via CDK `A11yModule`), and restored on close when `restoreFocus` is enabled
171
+ - Title is announced via `aria-label` or `aria-labelledby` (`header` + internal title ID)
172
+ - When using a custom header (`[fkDialogHeader]`), set `ariaLabel` explicitly since `aria-labelledby` is not automatically linked
173
+
174
+ ---
175
+
176
+ ## Design Tokens
177
+
178
+ `fk-dialog` uses the following design tokens:
179
+
180
+ ```scss
181
+ // Overlay
182
+ --fk-dialog-overlay-bg
183
+ --fk-dialog-overlay-z-index
184
+
185
+ // Panel
186
+ --fk-dialog-panel-bg
187
+ --fk-dialog-panel-border-radius
188
+ --fk-dialog-panel-shadow
189
+ --fk-dialog-panel-max-height
190
+ --fk-dialog-panel-margin
191
+ --fk-dialog-width-sm
192
+ --fk-dialog-width-md
193
+ --fk-dialog-width-lg
194
+ --fk-dialog-width-xl
195
+
196
+ // Header
197
+ --fk-dialog-header-padding
198
+ --fk-dialog-header-padding-inline
199
+ --fk-dialog-close-size
200
+ --fk-dialog-close-color
201
+ --fk-dialog-close-color-hover
202
+
203
+ // Body
204
+ --fk-dialog-body-padding
205
+
206
+ // Footer
207
+ --fk-dialog-footer-gap
208
+ --fk-dialog-footer-padding
209
+ --fk-dialog-footer-border
210
+ ```
211
+
212
+ Override in your theme to align with your design system.
213
+
214
+ ---
215
+
216
+ ## Behavior Notes
217
+
218
+ - When `modal` is `true`, body scroll is disabled only while at least one dialog is open.
219
+ - `animation="none"` disables exit animations and hides the dialog immediately on close.
220
+ - The header area renders when any of the following are true: a custom header is projected, the `header` input has a value, or `closable` is `true`.
221
+ - `[libDialogFooter]` works with both declarative usage (`<fk-dialog>`) and imperative usage (`DialogService.open()`). The service runs change detection on the content component, then moves footer elements from the body to the panel root.
222
+ - Footer children are flex-stretched to full width by default. Override with custom styles if needed.
@@ -0,0 +1,274 @@
1
+ # fk-drawer
2
+
3
+ An accessible, token-driven slide-out drawer component with focus management, scroll locking, and flexible close behavior.
4
+
5
+ ---
6
+
7
+ ## API
8
+
9
+ ### DrawerComponent
10
+
11
+ #### Inputs
12
+
13
+ | Input | Type | Default | Description |
14
+ | ----------------- | -------------------------- | --------------- | ------------------------------------------------------------------------------ |
15
+ | `open` | `boolean` | `false` | Whether the drawer is open |
16
+ | `closable` | `boolean` | `true` | Whether the drawer shows a close button |
17
+ | `closeOnEscape` | `boolean` | `true` | Close when Escape key is pressed |
18
+ | `closeOnBackdrop` | `boolean` | `true` | Close when clicking the backdrop overlay |
19
+ | `width` | `DrawerWidth` | `"md"` | Width variant (`sm`, `md`, `lg`, `xl`) |
20
+ | `header` | `string \| null` | `null` | Header text; used for `aria-labelledby` when no `ariaLabel` is set |
21
+ | `restoreFocus` | `boolean` | `true` | Restore focus to the previously focused element on close |
22
+ | `autoFocus` | `boolean` | `true` | Auto-focus the drawer content on open |
23
+ | `animation` | `DrawerAnimation` | `"slide-right"` | Animation preset (`"slide-right"`, `"fade"`, `"none"`) |
24
+ | `preventClose` | `boolean` | `false` | When `true`, disables closing entirely |
25
+ | `canClose` | `DrawerCanCloseFn \| null` | `null` | Optional guard function, sync or async, that must return `true` to allow close |
26
+ | `className` | `string` | `''` | Additional CSS classes for the host |
27
+ | `id` | `string \| null` | `null` | Optional ID for the host element |
28
+ | `ariaLabel` | `string \| null` | `null` | ARIA label when no visible header is used |
29
+
30
+ **`canClose` can be asynchronous.** Return a `boolean` or a `Promise<boolean>`; returning/resolving to `false` will keep the drawer open.
31
+
32
+ #### Outputs
33
+
34
+ | Output | Type | Description |
35
+ | ------------- | --------- | ---------------------------------------------- |
36
+ | `openChange` | `boolean` | Emitted when the `open` state should change |
37
+ | `beforeOpen` | `void` | Emitted just before the drawer becomes visible |
38
+ | `opened` | `void` | Emitted after the drawer is visible |
39
+ | `beforeClose` | `void` | Emitted just before closing logic runs |
40
+ | `closed` | `void` | Emitted after the drawer has closed |
41
+
42
+ #### Content Slots
43
+
44
+ | Slot | Selector | Description |
45
+ | ----------- | ------------------ | --------------------------------------------------------------------------- |
46
+ | **Default** | (none) | Drawer body content |
47
+ | **Footer** | `[fkDrawerFooter]` | Footer area, pinned to bottom with border-top separator. Hidden when empty. |
48
+
49
+ ### DrawerService
50
+
51
+ | Method | Signature | Description |
52
+ | ----------- | ----------------------------------------------------------------------- | -------------------------------------------------- |
53
+ | `open` | `open<TResult, TData>(content: Type, config?: DrawerConfig): DrawerRef` | Imperatively opens a drawer with the given content |
54
+ | `closeAll` | `closeAll(): void` | Closes all open drawers |
55
+ | `openCount` | `number` (getter) | Number of currently open drawers |
56
+
57
+ ### DrawerRef
58
+
59
+ | Method / Property | Signature | Description |
60
+ | ----------------- | ------------------------------------------------- | ---------------------------------------- |
61
+ | `close` | `close(result?: TResult): Promise<void>` | Close the drawer with an optional result |
62
+ | `beforeOpen` | `beforeOpen(): Observable<void>` | Emits before the drawer opens |
63
+ | `afterOpened` | `afterOpened(): Observable<void>` | Emits after the drawer is open |
64
+ | `beforeClose` | `beforeClose(): Observable<void>` | Emits before the drawer closes |
65
+ | `afterClosed` | `afterClosed(): Observable<TResult \| undefined>` | Emits the result when the drawer closes |
66
+ | `data` | `TData \| undefined` (getter) | Data passed via config |
67
+ | `setCanClose` | `setCanClose(guard: DrawerCanCloseFn \| null)` | Set or clear the close guard at runtime |
68
+ | `config` | `DrawerConfig<TData>` | The merged configuration object |
69
+
70
+ ### DrawerConfig
71
+
72
+ | Property | Type | Default | Description |
73
+ | ----------------- | ------------------ | --------------- | ---------------------------------------- |
74
+ | `closable` | `boolean` | `true` | Show close button |
75
+ | `closeOnEscape` | `boolean` | `true` | Close on Escape key |
76
+ | `closeOnBackdrop` | `boolean` | `true` | Close on backdrop click |
77
+ | `width` | `DrawerWidth` | `"md"` | Width variant |
78
+ | `animation` | `DrawerAnimation` | `"slide-right"` | Animation preset |
79
+ | `header` | `string \| null` | `null` | Header text |
80
+ | `restoreFocus` | `boolean` | `true` | Restore focus on close |
81
+ | `autoFocus` | `boolean` | `true` | Auto-focus on open |
82
+ | `preventClose` | `boolean` | `false` | Disable closing |
83
+ | `canClose` | `DrawerCanCloseFn` | — | Close guard function |
84
+ | `className` | `string` | `''` | Additional CSS classes |
85
+ | `ariaLabel` | `string \| null` | `null` | ARIA label |
86
+ | `data` | `TData` | — | Arbitrary data for the content component |
87
+
88
+ ---
89
+
90
+ ## Features
91
+
92
+ - Slide-out drawer panel with backdrop overlay and scroll locking
93
+ - Configurable width and animation presets
94
+ - Guardable close behavior (`preventClose`, `canClose`)
95
+ - Escape and backdrop click handling
96
+ - Focus trapping and restoration
97
+ - Imperative API via `DrawerService` for dynamic content
98
+ - Stacked drawer support with auto z-index management
99
+
100
+ ---
101
+
102
+ ## Quick Start
103
+
104
+ ### Imperative (via DrawerService)
105
+
106
+ ```ts
107
+ import { DrawerService } from '@frame-kit/ui-ng';
108
+
109
+ @Component({
110
+ /* ... */
111
+ })
112
+ export class MyComponent {
113
+ private readonly drawerService = inject(DrawerService);
114
+
115
+ openSettings() {
116
+ const ref = this.drawerService.open(SettingsPanelComponent, {
117
+ header: 'Settings',
118
+ width: 'lg',
119
+ });
120
+
121
+ ref.afterClosed().subscribe((result) => {
122
+ console.log('Drawer closed with:', result);
123
+ });
124
+ }
125
+ }
126
+ ```
127
+
128
+ ### Declarative (template-driven)
129
+
130
+ ```html
131
+ <fk-drawer [open]="isOpen" header="Filters" (openChange)="isOpen = $event">
132
+ <p>Filter controls here.</p>
133
+ </fk-drawer>
134
+ ```
135
+
136
+ ---
137
+
138
+ ## Import
139
+
140
+ ```ts
141
+ import { DrawerComponent, DrawerService } from '@frame-kit/ui-ng';
142
+ ```
143
+
144
+ ```ts
145
+ @Component({
146
+ selector: 'app-example',
147
+ imports: [DrawerComponent],
148
+ templateUrl: './example.component.html',
149
+ })
150
+ export class ExampleComponent {}
151
+ ```
152
+
153
+ ---
154
+
155
+ ## Selector
156
+
157
+ ```html
158
+ <fk-drawer></fk-drawer>
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Examples
164
+
165
+ ### Basic drawer
166
+
167
+ ```html
168
+ <fk-drawer [open]="isOpen" header="Record details" (openChange)="isOpen = $event">
169
+ <!-- detail content -->
170
+ </fk-drawer>
171
+ ```
172
+
173
+ ### Custom width
174
+
175
+ ```html
176
+ <fk-drawer [open]="isOpen" header="Wide Panel" width="xl" (openChange)="isOpen = $event">
177
+ <!-- content -->
178
+ </fk-drawer>
179
+ ```
180
+
181
+ ### With footer
182
+
183
+ ```html
184
+ <fk-drawer [open]="isOpen" header="Edit User" (openChange)="isOpen = $event">
185
+ <!-- body content -->
186
+ <p>Form fields here…</p>
187
+
188
+ <!-- footer: pinned to bottom, separated by border -->
189
+ <div fkDrawerFooter>
190
+ <button>Save</button>
191
+ <button>Cancel</button>
192
+ </div>
193
+ </fk-drawer>
194
+ ```
195
+
196
+ ### With close guard
197
+
198
+ ```ts
199
+ canClose = async () => {
200
+ const confirmed = await this.confirmService.open('Unsaved changes, leave?');
201
+ return confirmed;
202
+ };
203
+ ```
204
+
205
+ ```html
206
+ <fk-drawer [open]="isEditing" header="Edit record" [canClose]="canClose" (openChange)="isEditing = $event">
207
+ <!-- form fields -->
208
+ </fk-drawer>
209
+ ```
210
+
211
+ ---
212
+
213
+ ## Accessibility
214
+
215
+ - Uses ARIA dialog pattern with `role="dialog"` and `aria-modal="true"`
216
+ - Focus is trapped inside while open (via CDK `A11yModule`), and restored on close when `restoreFocus` is enabled
217
+ - Title is announced via `aria-label` or `aria-labelledby` (`header` + internal title ID)
218
+ - When no header is provided, set `ariaLabel` explicitly for screen reader accessibility
219
+
220
+ ---
221
+
222
+ ## Design Tokens
223
+
224
+ `fk-drawer` uses the following design tokens:
225
+
226
+ ```scss
227
+ // Overlay
228
+ --fk-drawer-overlay-bg
229
+ --fk-drawer-overlay-z-index
230
+
231
+ // Panel
232
+ --fk-drawer-bg
233
+ --fk-drawer-border-color
234
+ --fk-drawer-shadow
235
+ --fk-drawer-width-sm
236
+ --fk-drawer-width-md
237
+ --fk-drawer-width-lg
238
+ --fk-drawer-width-xl
239
+
240
+ // Header
241
+ --fk-drawer-header-padding
242
+ --fk-drawer-header-border-color
243
+ --fk-drawer-title-font-family
244
+ --fk-drawer-title-font-size
245
+ --fk-drawer-title-font-weight
246
+ --fk-drawer-title-color
247
+
248
+ // Close button
249
+ --fk-drawer-close-size
250
+ --fk-drawer-close-font-size
251
+ --fk-drawer-close-color
252
+ --fk-drawer-close-color-hover
253
+ --fk-drawer-close-bg-hover
254
+ --fk-drawer-close-radius
255
+ --fk-drawer-close-focus-ring
256
+
257
+ // Body
258
+ --fk-drawer-body-padding
259
+
260
+ // Footer
261
+ --fk-drawer-footer-padding
262
+ --fk-drawer-footer-border-color
263
+ ```
264
+
265
+ Override in your theme to align with your design system.
266
+
267
+ ---
268
+
269
+ ## Behavior Notes
270
+
271
+ - Body scroll is disabled while the drawer is open.
272
+ - `animation="none"` disables exit animations and hides the drawer immediately on close.
273
+ - The header area renders when any of the following are true: the `header` input has a value, or `closable` is `true`.
274
+ - The `DrawerService` manages stacked drawers with incrementing z-index values to ensure proper layering.