@filip.mazev/modal 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +249 -16
- package/fesm2022/filip.mazev-modal.mjs +40 -22
- package/fesm2022/filip.mazev-modal.mjs.map +1 -1
- package/package.json +1 -1
- package/types/filip.mazev-modal.d.ts +18 -17
package/README.md
CHANGED
|
@@ -1,25 +1,258 @@
|
|
|
1
|
-
# @filip.mazev/modal
|
|
2
1
|
|
|
3
|
-
|
|
2
|
+
# Blocks - Modal Library
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
## @filip.mazev/modal
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
**Blocks** is a powerful Angular component library. Its flagship feature is a highly customizable, service-driven **Modal** system that supports dynamic content, various positions, mobile-optimized swipe gestures, and robust theming.
|
|
8
7
|
|
|
9
|
-
##
|
|
8
|
+
## Features
|
|
10
9
|
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
10
|
+
* Service-Driven: Open and close modals from anywhere in your application using GenericModalService.
|
|
11
|
+
* Flexible Layouts: Supports center, left, and right positioning.
|
|
12
|
+
* Mobile Optimized: Native-feeling swipe-to-close gestures for mobile devices.
|
|
13
|
+
* Dynamic Data: Pass data to modal components with full type safety.
|
|
14
|
+
* Confirmation Flows: Built-in support for "Confirm Close" prompts to prevent accidental data loss.
|
|
15
|
+
* Theming: Deeply integrated Scss theming system using CSS variables.
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
## Installation
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Install the package via npm:
|
|
19
|
+
Please install both @filip.mazev/blocks-core and @filip.mazev/modal for propert functionality and full customization.
|
|
23
20
|
|
|
24
21
|
```bash
|
|
25
|
-
npm
|
|
22
|
+
npm i @filip.mazev/blocks-core@latest @filip.mazev/modal@latest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 1. Theme Configuration
|
|
26
|
+
|
|
27
|
+
To enable the library's stylization, import the theme provider in your global styles (styles.scss):
|
|
28
|
+
|
|
29
|
+
```scss
|
|
30
|
+
@use '@filip.mazev/blocks-core/src/lib/styles/index' as blocks;
|
|
31
|
+
@use '@filip.mazev/modal/lib/styles/index' as modal;
|
|
32
|
+
|
|
33
|
+
@layer base {
|
|
34
|
+
:root {
|
|
35
|
+
@include blocks.core-theme($default-light-theme-config);
|
|
36
|
+
|
|
37
|
+
@include modal.modal-theme((
|
|
38
|
+
'modal-mobile-swipe-line-color': #cfcfcf,
|
|
39
|
+
));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
[data-theme='dark'] {
|
|
43
|
+
@include core-theme($default-dark-theme-config);
|
|
44
|
+
@include modal.modal-theme((
|
|
45
|
+
'modal-mobile-swipe-line-color': #444444,
|
|
46
|
+
));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
You can also provide your own theme, please make sure that you follow the naming convention of the existing themes such as `default-light-theme-config` (found in `@filip.mazev/blocks-core/src/lib/styles/themes/default-theme`) for proper functionality.
|
|
52
|
+
|
|
53
|
+
Other themes are also available such as:
|
|
54
|
+
|
|
55
|
+
* `$orange-company-light-theme-config`
|
|
56
|
+
* `$orange-company-dark-theme-config`
|
|
57
|
+
|
|
58
|
+
### 2. Register the Service
|
|
59
|
+
|
|
60
|
+
In your root component (usually `app.component.ts` or `app.ts`), register the `ViewContainerRef` and `Renderer2` so the service knows where to attach modals:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { Component, inject, Renderer2, signal, ViewContainerRef } from '@angular/core';
|
|
64
|
+
import { RouterOutlet } from '@angular/router';
|
|
65
|
+
import { GenericModalService } from '@filip.mazev/modal';
|
|
66
|
+
|
|
67
|
+
@Component({
|
|
68
|
+
selector: 'app-root',
|
|
69
|
+
imports: [
|
|
70
|
+
RouterOutlet
|
|
71
|
+
],
|
|
72
|
+
templateUrl: './app.html',
|
|
73
|
+
styleUrl: './app.scss'
|
|
74
|
+
})
|
|
75
|
+
export class App {
|
|
76
|
+
protected readonly title = signal('Your App Name');
|
|
77
|
+
|
|
78
|
+
private viewContainerRef = inject(ViewContainerRef);
|
|
79
|
+
private renderer2 = inject(Renderer2);
|
|
80
|
+
|
|
81
|
+
private modals = inject(GenericModalService);
|
|
82
|
+
|
|
83
|
+
constructor() {
|
|
84
|
+
this.modals.register(this.viewContainerRef, this.renderer2);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Usage
|
|
90
|
+
|
|
91
|
+
### 1. Create a Modal Component
|
|
92
|
+
|
|
93
|
+
Your modal content components must extend `GenericModal<TData, TResult>`:
|
|
94
|
+
|
|
95
|
+
Typescript:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
import { GenericModal, GENERIC_MODAL_DATA, ModalHeaderDirective, ModalFooterDirective } from '@filip.mazev/modal';
|
|
99
|
+
|
|
100
|
+
@Component({
|
|
101
|
+
selector: 'app-my-modal-component',
|
|
102
|
+
imports: [
|
|
103
|
+
ModalHeaderDirective, // optional (only if defining custom header)
|
|
104
|
+
ModalFooterDirective // optional (only if defining custom footer)
|
|
105
|
+
],
|
|
106
|
+
templateUrl: './my-modal-component.html',
|
|
107
|
+
styleUrl: './my-modal-component.scss',
|
|
108
|
+
})
|
|
109
|
+
export class MyModalComponent extends GenericModal<MyData, MyResult> {
|
|
110
|
+
protected data = inject<MyData>(GENERIC_MODAL_DATA);
|
|
111
|
+
|
|
112
|
+
constructor() {
|
|
113
|
+
super();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
override afterModalGet(): void {
|
|
117
|
+
// This is called after the modal service has returned the instance of the generated modal to this component. You can access this.modal only after this
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
override onDestroy(): void {
|
|
121
|
+
// Perform onDestroy logic here as this method is called on ngOnDestroy on GenericModal
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
HTML (Template):
|
|
127
|
+
|
|
128
|
+
```HTML
|
|
129
|
+
<div *modalHeader>
|
|
130
|
+
Example Header
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div>
|
|
134
|
+
Lorem ipsum dolor sit, amet consectetur adipisicing elit. A, iste voluptatum accusamus facere explicabo impedit exercitationem dolore...
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div *modalFooter>
|
|
138
|
+
Example Footer
|
|
139
|
+
</div>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### About `GenericModalRef<D, R>`
|
|
143
|
+
|
|
144
|
+
Accessible via this.modal inside any component that extends GenericModal. This reference provides programmatic control over the active modal instance, access to its configuration, and observable streams for its lifecycle events.
|
|
145
|
+
|
|
146
|
+
#### Methods
|
|
147
|
+
|
|
148
|
+
* `close(state?, result?, forceClose?)`: Closes the modal instance.
|
|
149
|
+
* `state` (ModalCloseMode): The state of the closing action (e.g., 'confirm' or 'cancel'). Defaults to 'cancel'.
|
|
150
|
+
* `result` (R): Optional data to return to the component that opened the modal.
|
|
151
|
+
* `forceClose` (boolean): If true, bypasses any confirmCloseConfig checks or guards. Defaults to false.
|
|
152
|
+
* `modalState$()`: Returns an `Observable<GenericModalState>`. Emits the current lifecycle state of the modal (OPENING, OPEN, CLOSING, CLOSED).
|
|
153
|
+
* `backdropClick()`: Returns an `Observable<MouseEvent>`. Emits an event whenever the user clicks on the modal's backdrop.
|
|
154
|
+
* `afterClosed()`: Returns an `Observable<IGenericCloseResult<R>>`. Emits the final result object (containing the state and data) once the modal has fully closed and animations have finished.
|
|
155
|
+
|
|
156
|
+
#### Properties
|
|
157
|
+
|
|
158
|
+
* `modalConfig: (GenericModalConfig<D> | undefined)` Access to the configuration object used to open this modal. Useful for retrieving custom options or identifying the modal.
|
|
159
|
+
* `componentRef: (ComponentRef<C>)` The Angular ComponentRef of the content component (your component) inside the modal.
|
|
160
|
+
* `modalContainerRef: (ComponentRef<GenericModalComponent>)` The Angular ComponentRef of the wrapper container (the shell responsible for the backdrop, animations, and layout).
|
|
161
|
+
* `modalContainerElement: (HTMLElement)` The native HTML element of the modal container.
|
|
162
|
+
* `selfIdentifier: ({ constructor: Function })` An object identifying the constructor of the component, used internally for instance tracking.
|
|
163
|
+
|
|
164
|
+
#### `IGenericCloseResult`
|
|
165
|
+
|
|
166
|
+
The structure of the object returned when a modal closes, accessible via the observable from afterClosed(). Contains:
|
|
167
|
+
|
|
168
|
+
* `data` |`R`|: (optional) The data payload returned by the modal (e.g., the form result or selected item). This is undefined if no data was passed during closure.
|
|
169
|
+
* `state` |`ModalCloseMode`|: (required) Indicates how the modal was closed. Common values include 'confirm' (successful action) or 'cancel' (dismissed via backdrop, close button, or cancel action).
|
|
170
|
+
|
|
171
|
+
### 2. Opening the Modal
|
|
172
|
+
|
|
173
|
+
Use the GenericModalService to launch your component:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
private modals = inject(GenericModalService);
|
|
177
|
+
|
|
178
|
+
...
|
|
179
|
+
|
|
180
|
+
const modalRef = this.modals.open<MyData, MyResult>(MyModalComponent, {
|
|
181
|
+
data: { id: 1 }, // Must be of the type specified in MyData
|
|
182
|
+
style: {
|
|
183
|
+
position: 'right', // Slide in from the right (left and center are also available options)
|
|
184
|
+
handleMobile: true, // True by default, means that on smaller screens the modal will automatically go into a bottom sheet view
|
|
185
|
+
},
|
|
186
|
+
bannerText: 'Modal Title Here'
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
modalRef.afterClosed().subscribe(result: IGenericCloseResult<MyData> => {
|
|
190
|
+
// result.state can be 'confirm' or 'cancel'
|
|
191
|
+
console.log('Modal closed with action:', result.state);
|
|
192
|
+
|
|
193
|
+
// result.data is of type `MyData` |`` undefined` since no data is returned on 'cancel'
|
|
194
|
+
if(result.data) {
|
|
195
|
+
console.log('Modal Result value:', result.data);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Configuration Options
|
|
201
|
+
|
|
202
|
+
### `IGenericModalConfig`
|
|
203
|
+
|
|
204
|
+
Controls the behavior and content of the modal container:
|
|
205
|
+
|
|
206
|
+
* `open` |`boolean`|: (optional) Whether the modal should be open or not, will default to true.
|
|
207
|
+
* `afterClose` |``Function``|: (optional) The function to run after the modal closes.
|
|
208
|
+
* `confirmCloseConfig` |``IGenericConfirmCloseConfig<ConfirmComponentData, ConfirmComponent>``|: (optional) The configuration for the confirm close modal (e.g., a "Discard changes?" prompt), will default to `{ confirmClose: false }`. `ConfirmComponentData and ConfirmComponent` need to be specified.
|
|
209
|
+
* `disableClose` |`boolean`|: (optional) Whether the modal should be closable or not, will default to false. This applies to the close button, escape key, and backdrop.
|
|
210
|
+
* `disableCloseOnBackdropClick` |`boolean`|: (optional) Whether the modal shouldn't be closable specifically when the user clicks on the backdrop, will default to false.
|
|
211
|
+
* `disableCloseOnNavigation` |`boolean`|: (optional) Whether the modal should remain open when the user navigates away from the current page, will default to false.
|
|
212
|
+
* `enableExtremeOverflowHandling` |`boolean`|: (optional) Whether the modal should enable extreme overflow handling for complex scrolling scenarios (may cause issues with keypress registration), will default to false.
|
|
213
|
+
* `webkitOnlyOverflowMobileHandling` |`boolean`|: (optional) Whether the modal should only handle overflow for webkit browsers on mobile or for all browsers, will default to true. Webkite sometimes handles `overflow: hidden` poorly, this will ensure that scrolling is disabled totally for everything that is not within the modal while it is open.
|
|
214
|
+
* `data` |`TData`|: (optional) The data to pass to the component of the modal. The component needs to use the @Inject(GENERIC_MODAL_DATA) or `data = inject<string>(GENERIC_MODAL_DATA);` (modern syntax) decorator to receive this.
|
|
215
|
+
* `style` |`IGenericModalStyleConfig`|: (optional) The visual style configuration for the modal (position, backdrop, etc.), will default to an empty object.
|
|
216
|
+
* `bannerText` |`string`|: (optional) The text to display in the header banner of the modal.
|
|
217
|
+
* `bannerTextAnnotatedString` |`string`|: (optional) An annotated string (supporting bold styles) to display in the banner, will default to an empty string.
|
|
218
|
+
* `contentClasses` |`string`|: (optional) Custom CSS classes to apply directly to the content container of the modal.
|
|
219
|
+
* `contentStyles` |`string`|: (optional) Inline CSS styles to apply directly to the content container of the modal.
|
|
220
|
+
* `disableConsoleWarnings` |`boolean`|: (optional) Whether to suppress library warnings in the console, will default to false.
|
|
221
|
+
* `disableConsoleInfo` |`boolean`|: (optional) Whether to suppress library info logs in the console, will default to false.
|
|
222
|
+
* `id` |`string`|: (optional) The unique identifier of the modal, will default to a random string if not provided.
|
|
223
|
+
|
|
224
|
+
### `IGenericModalStyleConfig`
|
|
225
|
+
|
|
226
|
+
Controls the visual appearance:
|
|
227
|
+
|
|
228
|
+
* `position` |`ModalPoistion`|: (optional) The position of the modal (can be 'center', 'left', or 'right'), will default to 'center'.
|
|
229
|
+
* `handleMobile` |`boolean`|: (optional) Whether the modal should automatically switch to a mobile configuration (swipeable sheet) when the screen width drops below a certain breakpoint.
|
|
230
|
+
* `animate` |`boolean`|: (optional) Whether the modal should have open/close animations or not, will default to true.
|
|
231
|
+
* `hasBackdrop` |`boolean`|: (optional) Whether the modal should have a dimmed backdrop or not, will default to true.
|
|
232
|
+
* `closeDelay` |`number`|: (optional) The delay in milliseconds before the modal actually closes after the close action is triggered, will default to `GENERIC_MODAL_DEFAULT_ANIM_DURATION` = 175.
|
|
233
|
+
* `showCloseButton` |`boolean`|: (optional) Whether the modal should show a close button or not, will default to true.
|
|
234
|
+
* `mobileConfig` |`IGenericSwipeableModalConfig`|: (optional) The configuration for the swipeable modal (swipe limits, height), will default to an empty object.
|
|
235
|
+
* `contentWrapper` |`boolean`|: (optional) Whether the content should be wrapped in a default-styled container (providing padding/background) or not, will default to true.
|
|
236
|
+
* `wrapperClasses` |`string`|: (optional) Custom CSS classes to apply to the wrapper of the modal.
|
|
237
|
+
* `wrapperStyles` |`string`|: (optional) Inline CSS styles to apply to the wrapper of the modal.
|
|
238
|
+
* `overrideFullHeight` |`boolean`|: (optional) Whether the modal should override the default full-height restriction or not, will default to false.
|
|
239
|
+
|
|
240
|
+
### `IGenericConfirmCloseConfig`
|
|
241
|
+
|
|
242
|
+
Configuration for the confirmation modal triggered when a user attempts to close the parent modal (e.g., "Unsaved Changes"):
|
|
243
|
+
|
|
244
|
+
* `confirmModalComponent` |`ComponentType<ConfirmComponent>`|: (required) The component class to use for the confirmation modal.
|
|
245
|
+
* `confirmClose` |`boolean`|: (required) Whether the confirmation flow should be active. If false, the modal closes immediately without confirmation.
|
|
246
|
+
* `confirmOnSubmit` |`boolean`|: (optional) Whether the confirmation should also trigger when the modal is closed via a "submit" (success) action. Defaults to false (meaning confirmation is only required for 'cancel' or backdrop closure).
|
|
247
|
+
* `style` |`IGenericModalStyleConfig`|: (optional) The visual style configuration for the confirmation modal instance.
|
|
248
|
+
* `data` |`ConfirmComponentData`|: (optional) The data to pass to the confirmation component. The component needs to use the @Inject(GENERIC_MODAL_DATA) decorator to receive this.
|
|
249
|
+
* `bannerText` |`string`|: (optional) The text to display in the header banner of the confirmation modal.
|
|
250
|
+
* `bypassSelfCheck` |`boolean`|: (optional) Whether the modal should bypass the internal check that ensures the confirmation is attached to the specific closing modal. Defaults to false.
|
|
251
|
+
|
|
252
|
+
### `IGenericSwipeableModalConfig`
|
|
253
|
+
|
|
254
|
+
Configuration for the mobile-optimized swipeable modal (bottom sheet):
|
|
255
|
+
|
|
256
|
+
* `upSwipeLimit` |`number`|: (optional) The resistance factor for swiping upwards beyond the fully open state. Determines the maximum distance the modal can be over-scrolled upwards. A higher number results in a smaller allowed distance (calculated as windowHeight / upSwipeLimit).
|
|
257
|
+
* `downSwipeLimit` |`number`|: (optional) The threshold factor for swiping downwards to close the modal. Determines how far the user must swipe down before the modal closes automatically. (calculated as windowHeight / downSwipeLimit).
|
|
258
|
+
* `customHeight` |`number`|: (optional) A specific maximum height (in pixels) for the swipeable modal. If provided, this overrides the default dynamic height behavior.
|