@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,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.
|