@rivinia/modal 0.5.3 → 0.6.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/README.md +130 -6
- package/fesm2022/rivinia-modal-ui.mjs +156 -9
- package/fesm2022/rivinia-modal-ui.mjs.map +1 -1
- package/fesm2022/rivinia-modal.mjs +6 -2
- package/fesm2022/rivinia-modal.mjs.map +1 -1
- package/package.json +2 -1
- package/schematics/ng-add/index.cjs +31 -1
- package/types/rivinia-modal-ui.d.ts +112 -8
- package/types/rivinia-modal.d.ts +48 -2
|
@@ -1,12 +1,6 @@
|
|
|
1
|
+
import { ModalDismissOrigin, ModalInstance, ModalTemplateContext, RiviniaModalSize } from "@rivinia/modal";
|
|
1
2
|
import * as i0 from "@angular/core";
|
|
2
3
|
import { Injector, Signal } from "@angular/core";
|
|
3
|
-
import { ModalDismissOrigin, ModalInstance, ModalTemplateContext } from "@rivinia/modal";
|
|
4
|
-
/**
|
|
5
|
-
* Responsive size presets. Dimensions are ceilings, not mandates: every
|
|
6
|
-
* preset is a CSS custom property (`--rv-modal-width-*`) the consumer can
|
|
7
|
-
* override without touching library source. `auto` sizes to content.
|
|
8
|
-
*/
|
|
9
|
-
type RiviniaModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'auto';
|
|
10
4
|
/**
|
|
11
5
|
* Placement in the viewport. `start`/`end` are logical (RTL-aware).
|
|
12
6
|
* `fullscreen` covers the viewport (safe-area aware). `side-start` /
|
|
@@ -94,6 +88,27 @@ export declare class RiviniaModalDialog {
|
|
|
94
88
|
readonly animation: import("@angular/core").InputSignal<RiviniaModalAnimation>;
|
|
95
89
|
readonly closeOnEscape: import("@angular/core").InputSignal<boolean>;
|
|
96
90
|
readonly backdrop: import("@angular/core").InputSignal<RiviniaModalBackdrop>;
|
|
91
|
+
/**
|
|
92
|
+
* True while the viewport is being resized.
|
|
93
|
+
*
|
|
94
|
+
* The dialog's size is derived from the viewport, so during a resize every
|
|
95
|
+
* frame is a new target; animating towards a moving target lags behind the
|
|
96
|
+
* pointer. The transition is switched off for the duration, and the dialog
|
|
97
|
+
* snaps — which is what the eye expects from a resize.
|
|
98
|
+
*/
|
|
99
|
+
protected readonly resizing: import("@angular/core").WritableSignal<boolean>;
|
|
100
|
+
/**
|
|
101
|
+
* Track the viewport resize.
|
|
102
|
+
*
|
|
103
|
+
* matchMedia('(resolution: …)') is the reliable signal: a plain
|
|
104
|
+
* resize listener fires for every scroll-driven layout change too, and
|
|
105
|
+
* the resolution query only changes when the device pixel ratio or the
|
|
106
|
+
* viewport size really changed.
|
|
107
|
+
*/
|
|
108
|
+
private readonly viewportQuery;
|
|
109
|
+
private readonly stopResizeWatch;
|
|
110
|
+
private settleTimer;
|
|
111
|
+
ngOnDestroy(): void;
|
|
97
112
|
readonly showCloseButton: import("@angular/core").InputSignal<boolean>;
|
|
98
113
|
/**
|
|
99
114
|
* Managed mode (for {@link RiviniaModalHost}): UI intents (X button,
|
|
@@ -279,7 +294,86 @@ export declare class RiviniaModalHost {
|
|
|
279
294
|
readonly showCloseButton: import("@angular/core").InputSignal<boolean>;
|
|
280
295
|
/** Resolve a title per instance. Default: `metadata.title` → `ref` → `''`. */
|
|
281
296
|
readonly titleOf: import("@angular/core").InputSignal<((instance: ModalInstance<unknown>) => string | undefined) | undefined>;
|
|
282
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Whether an instance is still loading.
|
|
299
|
+
*
|
|
300
|
+
* A dialog that opens before its data arrives has nothing to show yet, and
|
|
301
|
+
* an empty box reads as a broken dialog. While this returns true for an
|
|
302
|
+
* instance, the host renders a loader INSTEAD of the instance's content.
|
|
303
|
+
*
|
|
304
|
+
* It is per instance, because a host can have several dialogs open and
|
|
305
|
+
* they load independently.
|
|
306
|
+
*
|
|
307
|
+
* ```html
|
|
308
|
+
* <rv-modal-host
|
|
309
|
+
* [modal]="modal"
|
|
310
|
+
* [loadingOf]="(instance) => instance.data?.loading === true"
|
|
311
|
+
* />
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
readonly loadingOf: import("@angular/core").InputSignal<((instance: ModalInstance<unknown>) => boolean) | undefined>;
|
|
315
|
+
/** Text of the loader. @default 'Loading…' */
|
|
316
|
+
readonly loadingLabel: import("@angular/core").InputSignal<string>;
|
|
317
|
+
/**
|
|
318
|
+
* The rendered stack.
|
|
319
|
+
*
|
|
320
|
+
* It is a signal the host owns rather than a computed over the manager, so
|
|
321
|
+
* the update can be wrapped in a view transition: the browser then paints
|
|
322
|
+
* the old stack and the new one as one continuous move instead of
|
|
323
|
+
* flickering between them.
|
|
324
|
+
*/
|
|
325
|
+
protected readonly visible: import("@angular/core").WritableSignal<readonly ModalInstance<unknown>[]>;
|
|
326
|
+
/** Push the manager's current stack into the rendered one. */
|
|
327
|
+
private readonly syncStack;
|
|
328
|
+
/**
|
|
329
|
+
* Smooth the stack change with a view transition.
|
|
330
|
+
*
|
|
331
|
+
* Opening a dialog on top of another one used to FLICKER: the top layer
|
|
332
|
+
* re-promotes the lower dialog, and the browser paints the change in
|
|
333
|
+
* separate frames. A view transition makes it one continuous move.
|
|
334
|
+
*
|
|
335
|
+
* It is optional by design: where the API is missing, the change simply
|
|
336
|
+
* happens without it — a missing nicety must not break the dialog.
|
|
337
|
+
*/
|
|
338
|
+
private readonly transition;
|
|
339
|
+
/** The last stack signature, so a change can be detected. */
|
|
340
|
+
private lastStackKey;
|
|
341
|
+
/**
|
|
342
|
+
* Run a view transition when the visible stack changed.
|
|
343
|
+
*/
|
|
344
|
+
protected withTransition(change: () => void): void;
|
|
345
|
+
/** Whether an instance hides the ones below it. */
|
|
346
|
+
protected readonly covering: Signal<string | null>;
|
|
347
|
+
/**
|
|
348
|
+
* Whether this instance is loading.
|
|
349
|
+
*
|
|
350
|
+
* A throwing resolver must not break the dialog, so it falls back to "not
|
|
351
|
+
* loading" — the content renders, which is the safe default.
|
|
352
|
+
*/
|
|
353
|
+
protected isLoading(instance: ModalInstance<unknown>): boolean;
|
|
354
|
+
/**
|
|
355
|
+
* The name of the component that opened this dialog.
|
|
356
|
+
*
|
|
357
|
+
* Rendered as `data-caller` on the dialog, so the DevTools inspector shows
|
|
358
|
+
* WHICH component opened it — the thing you want when a dialog appears and
|
|
359
|
+
* you need to find its source.
|
|
360
|
+
*/
|
|
361
|
+
protected callerName(instance: ModalInstance<unknown>): string | null;
|
|
362
|
+
/**
|
|
363
|
+
* The size of an instance.
|
|
364
|
+
*
|
|
365
|
+
* The host's `size` is the default; an instance may override it, so a small
|
|
366
|
+
* confirm can sit on top of a wide form without a second host.
|
|
367
|
+
*/
|
|
368
|
+
protected sizeOf(instance: ModalInstance<unknown>): RiviniaModalSize;
|
|
369
|
+
/**
|
|
370
|
+
* Whether an instance hides the ones below it.
|
|
371
|
+
*
|
|
372
|
+
* A stack renders every dialog, so the ones below stay visible behind the
|
|
373
|
+
* top one. When the top one covers the others, the ones below are not
|
|
374
|
+
* rendered at all — and they come back when it closes.
|
|
375
|
+
*/
|
|
376
|
+
protected isCovered(instance: ModalInstance<unknown>): boolean;
|
|
283
377
|
protected titleOfInstance(instance: ModalInstance<unknown>): string;
|
|
284
378
|
protected templateContext(instance: ModalInstance<unknown>): ModalTemplateContext<unknown>;
|
|
285
379
|
protected contextInjector(instance: ModalInstance<unknown>): Injector;
|
|
@@ -308,6 +402,16 @@ export declare class RiviniaModalHost {
|
|
|
308
402
|
"required": false;
|
|
309
403
|
"isSignal": true;
|
|
310
404
|
};
|
|
405
|
+
"loadingOf": {
|
|
406
|
+
"alias": "loadingOf";
|
|
407
|
+
"required": false;
|
|
408
|
+
"isSignal": true;
|
|
409
|
+
};
|
|
410
|
+
"loadingLabel": {
|
|
411
|
+
"alias": "loadingLabel";
|
|
412
|
+
"required": false;
|
|
413
|
+
"isSignal": true;
|
|
414
|
+
};
|
|
311
415
|
}, {}, never, never, true, never>;
|
|
312
416
|
}
|
|
313
417
|
/**
|
package/types/rivinia-modal.d.ts
CHANGED
|
@@ -60,6 +60,14 @@ type ModalResult<T> = {
|
|
|
60
60
|
};
|
|
61
61
|
/** Lifecycle state of one modal instance. Single source of truth: the manager. */
|
|
62
62
|
type ModalStatus = 'queued' | 'active' | 'closing' | 'closed';
|
|
63
|
+
/**
|
|
64
|
+
* The size of a dialog.
|
|
65
|
+
*
|
|
66
|
+
* It lives in the CORE, not only in the UI, because the size is decided when
|
|
67
|
+
* the dialog is OPENED — `openModal({ size })` — and the core owns that call.
|
|
68
|
+
* The UI entry re-exports the same union, so there is one vocabulary.
|
|
69
|
+
*/
|
|
70
|
+
type RiviniaModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'auto';
|
|
63
71
|
/** Origin of a dismissal intent. Guards see it; forced paths bypass guards. */
|
|
64
72
|
type ModalDismissOrigin = 'escape' | 'backdrop' | 'button' | 'program' | 'system';
|
|
65
73
|
/** Content a modal renders. Core stores the descriptor; UI interprets it. */
|
|
@@ -128,6 +136,7 @@ interface ModalInstance<TData = unknown> {
|
|
|
128
136
|
/** Stable key for a modal definition (e.g. `'confirm-delete'`). */
|
|
129
137
|
readonly ref: string | null;
|
|
130
138
|
/** Request origin label for diagnostics (e.g. component/feature name). */
|
|
139
|
+
/** The name of the component that opened this dialog, when known. */
|
|
131
140
|
readonly caller: string | null;
|
|
132
141
|
readonly parentId: string | null;
|
|
133
142
|
readonly data: TData;
|
|
@@ -151,7 +160,6 @@ interface ModalHandle<TResult = unknown> {
|
|
|
151
160
|
interface ModalOpenOptions<TData = unknown> {
|
|
152
161
|
readonly data?: TData;
|
|
153
162
|
readonly ref?: string;
|
|
154
|
-
readonly caller?: string;
|
|
155
163
|
readonly parentId?: string;
|
|
156
164
|
/**
|
|
157
165
|
* Lifecycle owner. Destruction settles active modals as `owner-destroyed`
|
|
@@ -160,6 +168,26 @@ interface ModalOpenOptions<TData = unknown> {
|
|
|
160
168
|
readonly owner?: DestroyRef;
|
|
161
169
|
/** Named preset from global config (explicit options always win). */
|
|
162
170
|
readonly preset?: string;
|
|
171
|
+
/**
|
|
172
|
+
* Size for THIS dialog.
|
|
173
|
+
*
|
|
174
|
+
* The host's `size` is the default for every instance; this overrides it for
|
|
175
|
+
* one. Without it, a host can only ever show one size — so a small confirm
|
|
176
|
+
* over a wide form has to be opened by a different host.
|
|
177
|
+
*/
|
|
178
|
+
readonly size?: RiviniaModalSize;
|
|
179
|
+
/**
|
|
180
|
+
* Hide the dialogs underneath this one.
|
|
181
|
+
*
|
|
182
|
+
* A stack shows every dialog, so the ones below stay visible behind the
|
|
183
|
+
* top one. That is right for a wizard, and wrong for a flow where the
|
|
184
|
+
* detail view REPLACES the list view: the list behind keeps peeking out and
|
|
185
|
+
* the two fight for attention.
|
|
186
|
+
*
|
|
187
|
+
* With this set, the instances below are not rendered while this one is up,
|
|
188
|
+
* and they come back when it closes.
|
|
189
|
+
*/
|
|
190
|
+
readonly coversOthers?: boolean;
|
|
163
191
|
readonly dismiss?: Partial<ModalDismissPolicy>;
|
|
164
192
|
readonly guards?: readonly ModalGuard[];
|
|
165
193
|
readonly metadata?: Record<string, unknown>;
|
|
@@ -169,6 +197,24 @@ interface ModalOpenOptions<TData = unknown> {
|
|
|
169
197
|
* fail silently at render. See `ModalContent` inputs.
|
|
170
198
|
*/
|
|
171
199
|
readonly inputs?: Record<string, unknown>;
|
|
200
|
+
/**
|
|
201
|
+
* The component that opened the dialog.
|
|
202
|
+
*
|
|
203
|
+
* `openModal` is usually called from an event handler, which is NOT an
|
|
204
|
+
* injection context, so the manager cannot discover the caller on its own.
|
|
205
|
+
* Naming it makes the opener attributable: the dialog carries a
|
|
206
|
+
* `data-caller` attribute, which shows up in the DevTools inspector and
|
|
207
|
+
* points at the component that opened it.
|
|
208
|
+
*
|
|
209
|
+
* ```ts
|
|
210
|
+
* export class UsersScreen {
|
|
211
|
+
* open() { this.modal.openModal(this.tpl, { caller: UsersScreen }); }
|
|
212
|
+
* }
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* A plain string works too, when the name is all that is known.
|
|
216
|
+
*/
|
|
217
|
+
readonly caller?: string | Type<unknown>;
|
|
172
218
|
}
|
|
173
219
|
/** Partial changes for `update()` (content shape itself is immutable). */
|
|
174
220
|
interface ModalUpdate<TData = unknown> {
|
|
@@ -368,4 +414,4 @@ export declare class RiviniaModal {
|
|
|
368
414
|
export declare function provideRiviniaModal(config?: RiviniaModalConfig): EnvironmentProviders;
|
|
369
415
|
/** Shorthand for `inject(RiviniaModal)`. */
|
|
370
416
|
export declare function injectRiviniaModal(): RiviniaModal;
|
|
371
|
-
export type { DescendantPolicy, ModalContent, ModalContext, ModalDiagnostic, ModalDismissOrigin, ModalDismissPolicy, ModalGuard, ModalHandle, ModalInstance, ModalOpenOptions, ModalOverflowPolicy, ModalPreset, ModalResult, ModalStatus, ModalStrategy, ModalTemplateContext, ModalUpdate, RiviniaModalConfig };
|
|
417
|
+
export type { DescendantPolicy, ModalContent, ModalContext, ModalDiagnostic, ModalDismissOrigin, ModalDismissPolicy, ModalGuard, ModalHandle, ModalInstance, ModalOpenOptions, ModalOverflowPolicy, ModalPreset, ModalResult, ModalStatus, ModalStrategy, ModalTemplateContext, ModalUpdate, RiviniaModalConfig, RiviniaModalSize };
|