@rivinia/modal 0.5.0 → 0.5.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 CHANGED
@@ -162,7 +162,29 @@ reference-counted scroll lock restores previous styles; focus trap + focus
162
162
  restore + `aria-labelledby`/`aria-label`; `dir=rtl` works via logical
163
163
  properties; SSR renders closed and opens after hydration; lazy-load the
164
164
  entry (`loadComponent`) to split it into its own chunk (~16.7 kB raw,
165
- ~4.9 kB transfer, measured). Toasts: MEASURED (Chrome, `elementFromPoint`) —
165
+ ~4.9 kB transfer, measured).
166
+
167
+ ## Toasts above an open modal (measured pattern)
168
+
169
+ A toast host outside the dialog can never paint above it — neither a high
170
+ `z-index` nor `popover="manual"` escapes the modal top layer (verified in
171
+ Chrome via `elementFromPoint`). When an error toast must appear over an open
172
+ modal (e.g. a data error inside the form), host the list **inside** the
173
+ dialog content instead: as a descendant of the top-layer element it paints
174
+ above the dialog background with zero extra code and zero coupling:
175
+
176
+ ```html
177
+ <rv-modal-dialog [(open)]="open" [title]="'Edit user'">
178
+ <!-- paints above this dialog; positions are still viewport-anchored -->
179
+ <rv-toast-list [manager]="injectRiviniaToast()" [position]="'top-end'" />
180
+ <form>…</form>
181
+ </rv-modal-dialog>
182
+ ```
183
+
184
+ Notes: positions stay viewport-anchored (`fixed`), so `top-end` means the
185
+ viewport corner in both LTR and RTL (logical properties). Toasts fired
186
+ while no dialog is open still need a page-level list — the two lists share
187
+ the same manager, so nothing is lost or duplicated. Toasts: MEASURED (Chrome, `elementFromPoint`) —
166
188
  neither a high `z-index` nor `popover="manual"` paints above an open modal
167
189
  dialog; toasts queue behind it. No modal→toast dependency by design.
168
190
 
@@ -179,6 +201,14 @@ Core checks `ModalHandle<TResult>.close(result?: TResult)` and
179
201
  - The internal deferred-promise cast to `Promise<ModalResult<TResult>>` —
180
202
  `close()` settles whatever it receives, never validated.
181
203
 
204
+ ## Browser back button (non-goal)
205
+
206
+ Native `<dialog>.showModal()` does not integrate with history: the back
207
+ button neither closes the dialog nor is blocked by it (platform behavior,
208
+ not a Rivinia choice). If your app needs back-to-dismiss, wire it at the
209
+ app layer (router guard / `popstate` → `dismiss()`); the manager's
210
+ `dismissRequested` + guards flow stays the single teardown path.
211
+
182
212
  ## License
183
213
 
184
214
  MIT.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from "@angular/core";
2
- import { Component, DOCUMENT, Directive, Injector, Service, computed, contentChild, effect, inject, input, model, output, signal, viewChild } from "@angular/core";
2
+ import { Component, DOCUMENT, Directive, Injector, Service, ViewEncapsulation, computed, contentChild, effect, inject, input, model, output, signal, viewChild } from "@angular/core";
3
3
  import { NgComponentOutlet, NgTemplateOutlet } from "@angular/common";
4
4
  import { RIVINIA_MODAL_CONTEXT } from "@rivinia/modal";
5
5
  var RiviniaModalScrollLock = class RiviniaModalScrollLock {
@@ -505,7 +505,8 @@ var RiviniaModalDialog = class RiviniaModalDialog {
505
505
  </dialog>
506
506
  `,
507
507
  isInline: true,
508
- styles: [".rv-modal{color-scheme:light dark;--rv-modal-bg: #ffffff;--rv-modal-fg: #111111;--rv-modal-muted: #555555;--rv-modal-border: #e0e0e0;--rv-modal-radius: 12px;--rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, .28);--rv-modal-backdrop: rgba(0, 0, 0, .5);--rv-modal-pad: 20px;--rv-modal-gap: 12px;--rv-modal-width-sm: 24rem;--rv-modal-width-md: 32rem;--rv-modal-width-lg: 48rem;--rv-modal-width-xl: 64rem;--rv-modal-max-height: min(86dvh, 100%);--rv-modal-duration: .15s;--rv-modal-duration-in: var(--rv-modal-duration);--rv-modal-duration-out: .12s;--rv-modal-easing: ease-out;--rv-modal-easing-in: var(--rv-modal-easing);--rv-modal-easing-out: ease-in;--rv-modal-radius-sheet: 20px;--rv-modal-width-panel: 24rem;padding:0;border:1px solid var(--rv-modal-border);border-radius:var(--rv-modal-radius);background:var(--rv-modal-bg);color:var(--rv-modal-fg);box-shadow:var(--rv-modal-shadow);max-height:var(--rv-modal-max-height);width:var(--rv-modal-width-md);max-width:calc(100dvw - 2rem)}@media(prefers-color-scheme:dark){.rv-modal{--rv-modal-bg: #161616;--rv-modal-fg: #f2f2f2;--rv-modal-muted: #a8a8a8;--rv-modal-border: #333333;--rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, .6)}}.rv-modal::backdrop{background:var(--rv-modal-backdrop)}.rv-modal[data-size=sm]{width:var(--rv-modal-width-sm)}.rv-modal[data-size=lg]{width:var(--rv-modal-width-lg)}.rv-modal[data-size=xl]{width:var(--rv-modal-width-xl)}.rv-modal[data-size=full]{width:calc(100dvw - 2rem)}.rv-modal[data-size=auto]{width:auto}.rv-modal[data-position=top]{margin-block-start:8dvh}.rv-modal[data-position=bottom]{margin-block-start:auto;margin-block-end:8dvh}.rv-modal[data-position=top-start],.rv-modal[data-position=center-start]{margin-inline-start:1rem;margin-inline-end:auto}.rv-modal[data-position=top-end],.rv-modal[data-position=center-end]{margin-inline-start:auto;margin-inline-end:1rem}.rv-modal[data-position=bottom-start]{margin-block-start:auto;margin-inline-start:1rem}.rv-modal[data-position=bottom-end]{margin-block-start:auto;margin-inline-end:1rem}.rv-modal[data-position=fullscreen]{inset:0;width:100dvw;height:100dvh;max-width:none;max-height:none;border-radius:0}.rv-modal[data-position=side-start],.rv-modal[data-position=side-end]{height:100dvh;max-height:none;width:var(--rv-modal-width-panel);margin-block:0}.rv-modal[data-position=side-start]{margin-inline-start:0;margin-inline-end:auto;border-start-start-radius:0;border-end-start-radius:0}.rv-modal[data-position=side-end]{margin-inline-start:auto;margin-inline-end:0;border-start-end-radius:0;border-end-end-radius:0}@media(max-width:640px){.rv-modal[data-position=center],.rv-modal[data-position=top],.rv-modal[data-position=bottom],.rv-modal[data-position=bottom-start],.rv-modal[data-position=bottom-end]{margin-block-start:auto;margin-block-end:0;margin-inline:0;width:100dvw;max-width:none;border-end-end-radius:0;border-end-start-radius:0;border-start-start-radius:var(--rv-modal-radius-sheet);border-start-end-radius:var(--rv-modal-radius-sheet)}.rv-modal[data-position=center][data-state=open],.rv-modal[data-position=top][data-state=open],.rv-modal[data-position=bottom][data-state=open],.rv-modal[data-position=bottom-start][data-state=open],.rv-modal[data-position=bottom-end][data-state=open]{animation-name:rv-modal-in-bottom}}.rv-modal[data-animation]:not([data-animation=none])[data-state=open]{animation:var(--rv-modal-animation-in, rv-modal-in) var(--rv-modal-duration-in) var(--rv-modal-easing-in)}.rv-modal[data-animation=scale][data-state=open]{--rv-modal-animation-in: rv-modal-in-scale}.rv-modal[data-animation=slide-top][data-state=open]{--rv-modal-animation-in: rv-modal-in-top}.rv-modal[data-animation=slide-bottom][data-state=open]{--rv-modal-animation-in: rv-modal-in-bottom}.rv-modal[data-animation=slide-start][data-state=open]{--rv-modal-animation-in: rv-modal-in-start}.rv-modal[data-animation=slide-end][data-state=open],[dir=rtl] .rv-modal[data-animation=slide-start][data-state=open]{--rv-modal-animation-in: rv-modal-in-end}[dir=rtl] .rv-modal[data-animation=slide-end][data-state=open]{--rv-modal-animation-in: rv-modal-in-start}.rv-modal[data-state=closing]{animation:rv-modal-out var(--rv-modal-duration-out) var(--rv-modal-easing-out) forwards}@keyframes rv-modal-in{0%{opacity:0}}@keyframes rv-modal-in-scale{0%{opacity:0;transform:translateY(8px) scale(.98)}}@keyframes rv-modal-in-top{0%{opacity:0;transform:translateY(-24px)}}@keyframes rv-modal-in-bottom{0%{opacity:0;transform:translateY(24px)}}@keyframes rv-modal-in-start{0%{opacity:0;transform:translate(-24px)}}@keyframes rv-modal-in-end{0%{opacity:0;transform:translate(24px)}}@keyframes rv-modal-out{to{opacity:0;transform:translateY(8px) scale(.98)}}@media(prefers-reduced-motion:reduce){.rv-modal[data-animation]{animation:none}}.rv-modal-header{display:flex;align-items:flex-start;gap:var(--rv-modal-gap);padding:var(--rv-modal-pad) var(--rv-modal-pad) 0}.rv-modal-header-custom>:first-child{flex:1;min-width:0}.rv-modal-heading:empty{display:none}.rv-modal-title{margin:0;font-size:1.125rem;flex:1}.rv-modal-heading{flex:1;display:flex;flex-direction:column;gap:4px}.rv-modal-description{margin:0;font-size:.875rem;color:var(--rv-modal-muted)}.rv-modal-close{margin-inline-start:auto;flex:none;border:1px solid var(--rv-modal-border);border-radius:8px;background:transparent;color:inherit;font-size:1.25rem;line-height:1;padding:4px 10px;cursor:pointer}.rv-modal-close:focus-visible{outline:2px solid currentColor;outline-offset:2px}.rv-modal-body{padding:var(--rv-modal-pad);overflow:auto;max-height:inherit}.rv-modal-footer{display:flex;gap:var(--rv-modal-gap);justify-content:flex-end;padding:0 var(--rv-modal-pad) var(--rv-modal-pad)}.rv-modal-footer:empty{display:none}\n"]
508
+ styles: [".rv-modal{color-scheme:light dark;--rv-modal-bg: #ffffff;--rv-modal-fg: #111111;--rv-modal-muted: #555555;--rv-modal-border: #e0e0e0;--rv-modal-radius: 12px;--rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, .28);--rv-modal-backdrop: rgba(0, 0, 0, .5);--rv-modal-pad: 20px;--rv-modal-gap: 12px;--rv-modal-width-sm: 24rem;--rv-modal-width-md: 32rem;--rv-modal-width-lg: 48rem;--rv-modal-width-xl: 64rem;--rv-modal-max-height: min(86dvh, 100%);--rv-modal-duration: .15s;--rv-modal-duration-in: var(--rv-modal-duration);--rv-modal-duration-out: .12s;--rv-modal-easing: ease-out;--rv-modal-easing-in: var(--rv-modal-easing);--rv-modal-easing-out: ease-in;--rv-modal-radius-sheet: 20px;--rv-modal-width-panel: 24rem;padding:0;border:1px solid var(--rv-modal-border);border-radius:var(--rv-modal-radius);background:var(--rv-modal-bg);color:var(--rv-modal-fg);box-shadow:var(--rv-modal-shadow);max-height:var(--rv-modal-max-height);width:var(--rv-modal-width-md);max-width:calc(100dvw - 2rem)}@media(prefers-color-scheme:dark){.rv-modal{--rv-modal-bg: #161616;--rv-modal-fg: #f2f2f2;--rv-modal-muted: #a8a8a8;--rv-modal-border: #333333;--rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, .6)}}.rv-modal::backdrop{background:var(--rv-modal-backdrop)}.rv-modal[data-size=sm]{width:var(--rv-modal-width-sm)}.rv-modal[data-size=lg]{width:var(--rv-modal-width-lg)}.rv-modal[data-size=xl]{width:var(--rv-modal-width-xl)}.rv-modal[data-size=full]{width:calc(100dvw - 2rem)}.rv-modal[data-size=auto]{width:auto}.rv-modal[data-position=top]{margin-block-start:8dvh}.rv-modal[data-position=bottom]{margin-block-start:auto;margin-block-end:8dvh}.rv-modal[data-position=top-start],.rv-modal[data-position=center-start]{margin-inline-start:1rem;margin-inline-end:auto}.rv-modal[data-position=top-end],.rv-modal[data-position=center-end]{margin-inline-start:auto;margin-inline-end:1rem}.rv-modal[data-position=bottom-start]{margin-block-start:auto;margin-inline-start:1rem}.rv-modal[data-position=bottom-end]{margin-block-start:auto;margin-inline-end:1rem}.rv-modal[data-position=fullscreen]{inset:0;width:100dvw;height:100dvh;max-width:none;max-height:none;border-radius:0}.rv-modal[data-position=side-start],.rv-modal[data-position=side-end]{height:100dvh;max-height:none;width:var(--rv-modal-width-panel);margin-block:0}.rv-modal[data-position=side-start]{margin-inline-start:0;margin-inline-end:auto;border-start-start-radius:0;border-end-start-radius:0}.rv-modal[data-position=side-end]{margin-inline-start:auto;margin-inline-end:0;border-start-end-radius:0;border-end-end-radius:0}@media(max-width:640px){.rv-modal[data-position=center],.rv-modal[data-position=top],.rv-modal[data-position=bottom],.rv-modal[data-position=bottom-start],.rv-modal[data-position=bottom-end]{margin-block-start:auto;margin-block-end:0;margin-inline:0;width:100dvw;max-width:none;border-end-end-radius:0;border-end-start-radius:0;border-start-start-radius:var(--rv-modal-radius-sheet);border-start-end-radius:var(--rv-modal-radius-sheet)}.rv-modal[data-position=center][data-state=open],.rv-modal[data-position=top][data-state=open],.rv-modal[data-position=bottom][data-state=open],.rv-modal[data-position=bottom-start][data-state=open],.rv-modal[data-position=bottom-end][data-state=open]{animation-name:rv-modal-in-bottom}}.rv-modal[data-animation]:not([data-animation=none])[data-state=open]{animation:var(--rv-modal-animation-in, rv-modal-in) var(--rv-modal-duration-in) var(--rv-modal-easing-in)}.rv-modal[data-animation=scale][data-state=open]{--rv-modal-animation-in: rv-modal-in-scale}.rv-modal[data-animation=slide-top][data-state=open]{--rv-modal-animation-in: rv-modal-in-top}.rv-modal[data-animation=slide-bottom][data-state=open]{--rv-modal-animation-in: rv-modal-in-bottom}.rv-modal[data-animation=slide-start][data-state=open]{--rv-modal-animation-in: rv-modal-in-start}.rv-modal[data-animation=slide-end][data-state=open],[dir=rtl] .rv-modal[data-animation=slide-start][data-state=open]{--rv-modal-animation-in: rv-modal-in-end}[dir=rtl] .rv-modal[data-animation=slide-end][data-state=open]{--rv-modal-animation-in: rv-modal-in-start}.rv-modal[data-state=closing]{animation:rv-modal-out var(--rv-modal-duration-out) var(--rv-modal-easing-out) forwards}@keyframes rv-modal-in{0%{opacity:0}}@keyframes rv-modal-in-scale{0%{opacity:0;transform:translateY(8px) scale(.98)}}@keyframes rv-modal-in-top{0%{opacity:0;transform:translateY(-24px)}}@keyframes rv-modal-in-bottom{0%{opacity:0;transform:translateY(24px)}}@keyframes rv-modal-in-start{0%{opacity:0;transform:translate(-24px)}}@keyframes rv-modal-in-end{0%{opacity:0;transform:translate(24px)}}@keyframes rv-modal-out{to{opacity:0;transform:translateY(8px) scale(.98)}}@media(prefers-reduced-motion:reduce){.rv-modal[data-animation]{animation:none}}.rv-modal-header{display:flex;align-items:flex-start;gap:var(--rv-modal-gap);padding:var(--rv-modal-pad) var(--rv-modal-pad) 0}.rv-modal-header-custom>:first-child{flex:1;min-width:0}.rv-modal-heading:empty{display:none}.rv-modal-title{margin:0;font-size:1.125rem;flex:1}.rv-modal-heading{flex:1;display:flex;flex-direction:column;gap:4px}.rv-modal-description{margin:0;font-size:.875rem;color:var(--rv-modal-muted)}.rv-modal-close{margin-inline-start:auto;flex:none;border:1px solid var(--rv-modal-border);border-radius:8px;background:transparent;color:inherit;font-size:1.25rem;line-height:1;padding:4px 10px;cursor:pointer}.rv-modal-close:focus-visible{outline:2px solid currentColor;outline-offset:2px}.rv-modal-body{padding:var(--rv-modal-pad);overflow:auto;max-height:inherit}.rv-modal-footer{display:flex;gap:var(--rv-modal-gap);justify-content:flex-end;padding:0 var(--rv-modal-pad) var(--rv-modal-pad)}.rv-modal-footer:empty{display:none}\n"],
509
+ encapsulation: i0.ViewEncapsulation.None
509
510
  });
510
511
  };
511
512
  i0.ɵɵngDeclareClassMetadata({
@@ -518,6 +519,7 @@ i0.ɵɵngDeclareClassMetadata({
518
519
  args: [{
519
520
  selector: "rv-modal-dialog",
520
521
  standalone: true,
522
+ encapsulation: ViewEncapsulation.None,
521
523
  template: `
522
524
  <dialog
523
525
  #dialog
@@ -1 +1 @@
1
- {"version":3,"file":"rivinia-modal-ui.mjs","names":[],"sources":["../../../projects/modal/ui/src/lib/modal-scroll-lock.ts","../../../projects/modal/ui/src/lib/modal-dialog.ts","../../../projects/modal/ui/src/lib/modal-host.ts"],"sourcesContent":["import { DOCUMENT, Service, inject } from '@angular/core';\n\n/**\n * Reference-counted background scroll lock. Multiple overlays share one lock:\n * closing one modal never unlocks the page while another still needs it.\n * Restores the exact previous `overflow` value (never blanks app-owned\n * styles). All DOM access happens inside methods — never at module\n * evaluation — and every method is a no-op without a document (SSR).\n */\n@Service()\nexport class RiviniaModalScrollLock {\n private readonly _doc = inject(DOCUMENT, { optional: true });\n private _locks = 0;\n private _previousOverflow: string | null = null;\n\n /** Number of active locks (diagnostics/tests). */\n get active(): number {\n return this._locks;\n }\n\n acquire(): void {\n const doc = this.document;\n if (!doc) return;\n this._locks += 1;\n if (this._locks > 1) return;\n const body = doc.body;\n this._previousOverflow = body.style.overflow || null;\n body.style.overflow = 'hidden';\n // Reserve the scrollbar gutter where supported so content does not jump.\n // Overlay scrollbars ignore it; that is documented, not promised.\n doc.documentElement.style.setProperty('scrollbar-gutter', 'stable');\n }\n\n release(): void {\n const doc = this.document;\n if (!doc || this._locks === 0) {\n this._locks = 0;\n return;\n }\n this._locks -= 1;\n if (this._locks > 0) return;\n const body = doc.body;\n if (this._previousOverflow === null) body.style.removeProperty('overflow');\n else body.style.overflow = this._previousOverflow;\n this._previousOverflow = null;\n doc.documentElement.style.removeProperty('scrollbar-gutter');\n }\n\n private get document(): Document | null {\n try {\n return this._doc ?? (typeof document === 'undefined' ? null : document);\n } catch {\n return null;\n }\n }\n}\n","import {\n Component,\n Directive,\n DOCUMENT,\n ElementRef,\n computed,\n contentChild,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { RiviniaModalScrollLock } from './modal-scroll-lock';\nimport type {\n RiviniaModalAnimation,\n RiviniaModalBackdrop,\n RiviniaModalPosition,\n RiviniaModalSize,\n} from './ui-types';\n\nconst EXIT_FALLBACK_MS = 200;\n\n/**\n * Marker for custom header content. Put it on the element carrying\n * `rv-modal-header` — its presence (not just the attribute) tells the\n * dialog to hide the default title + close button:\n *\n * ```html\n * <div rv-modal-header rvModalHeader>My header</div>\n * ```\n */\n@Directive({ selector: '[rvModalHeader]', standalone: true })\nexport class RvModalHeader {}\n\n/**\n * Marker for custom footer content. Put it on the element carrying\n * `rv-modal-footer`. Without it the footer region never renders.\n */\n@Directive({ selector: '[rvModalFooter]', standalone: true })\nexport class RvModalFooter {}\n\n/**\n * Ready-made modal dialog on the native `<dialog>` element (top layer,\n * `::backdrop`, inert background, Escape `cancel` event — all platform\n * behavior, zero overlay dependencies).\n *\n * UI-only by design: it owns its own `open` state and never imports the\n * headless controller. Pair it with `@rivinia/modal` through\n * {@link RiviniaModalHost} (or your own adapter) when you want managed\n * lifecycle, guards and typed results.\n *\n * Projection: `[rv-modal-header]` replaces the default header (title +\n * close button); default `<ng-content>` is the body; `[rv-modal-footer]`\n * is optional and renders nothing when absent.\n */\n@Component({\n selector: 'rv-modal-dialog',\n standalone: true,\n template: `\n <dialog\n #dialog\n tabindex=\"-1\"\n class=\"rv-modal\"\n [attr.data-size]=\"size()\"\n [attr.data-position]=\"position()\"\n [attr.data-animation]=\"animation()\"\n [attr.data-state]=\"state()\"\n [attr.aria-label]=\"computedLabel()\"\n [attr.aria-labelledby]=\"title() && !ariaLabel() ? titleId : null\"\n [attr.aria-describedby]=\"description() ? descriptionId : null\"\n (cancel)=\"onCancel($event)\"\n (click)=\"onBackdropClick($event)\"\n (keydown)=\"onKeydown($event)\"\n >\n @if (hasCustomHeader()) {\n <div class=\"rv-modal-header rv-modal-header-custom\">\n <ng-content select=\"[rv-modal-header]\"></ng-content>\n </div>\n } @else if (title() || showCloseButton()) {\n <div class=\"rv-modal-header\">\n <div class=\"rv-modal-heading\">\n @if (title()) {\n <h2 class=\"rv-modal-title\" [id]=\"titleId\">{{ title() }}</h2>\n }\n @if (description()) {\n <p class=\"rv-modal-description\" [id]=\"descriptionId\">{{ description() }}</p>\n }\n </div>\n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"rv-modal-close\"\n (click)=\"onCloseButton()\"\n aria-label=\"Close dialog\"\n >\n <span aria-hidden=\"true\">&times;</span>\n </button>\n }\n </div>\n }\n <div class=\"rv-modal-body\">\n <ng-content></ng-content>\n </div>\n @if (hasCustomFooter()) {\n <div class=\"rv-modal-footer\">\n <ng-content select=\"[rv-modal-footer]\"></ng-content>\n </div>\n }\n </dialog>\n `,\n styles: [\n `\n .rv-modal {\n color-scheme: light dark;\n --rv-modal-bg: #ffffff;\n --rv-modal-fg: #111111;\n --rv-modal-muted: #555555;\n --rv-modal-border: #e0e0e0;\n --rv-modal-radius: 12px;\n --rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, 0.28);\n --rv-modal-backdrop: rgba(0, 0, 0, 0.5);\n --rv-modal-pad: 20px;\n --rv-modal-gap: 12px;\n --rv-modal-width-sm: 24rem;\n --rv-modal-width-md: 32rem;\n --rv-modal-width-lg: 48rem;\n --rv-modal-width-xl: 64rem;\n --rv-modal-max-height: min(86dvh, 100%);\n --rv-modal-duration: 150ms;\n --rv-modal-duration-in: var(--rv-modal-duration);\n --rv-modal-duration-out: 120ms;\n --rv-modal-easing: ease-out;\n --rv-modal-easing-in: var(--rv-modal-easing);\n --rv-modal-easing-out: ease-in;\n --rv-modal-radius-sheet: 20px;\n --rv-modal-width-panel: 24rem;\n padding: 0;\n border: 1px solid var(--rv-modal-border);\n border-radius: var(--rv-modal-radius);\n background: var(--rv-modal-bg);\n color: var(--rv-modal-fg);\n box-shadow: var(--rv-modal-shadow);\n max-height: var(--rv-modal-max-height);\n width: var(--rv-modal-width-md);\n max-width: calc(100dvw - 2rem);\n }\n @media (prefers-color-scheme: dark) {\n .rv-modal {\n --rv-modal-bg: #161616;\n --rv-modal-fg: #f2f2f2;\n --rv-modal-muted: #a8a8a8;\n --rv-modal-border: #333333;\n --rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, 0.6);\n }\n }\n .rv-modal::backdrop {\n background: var(--rv-modal-backdrop);\n }\n .rv-modal[data-size='sm'] {\n width: var(--rv-modal-width-sm);\n }\n .rv-modal[data-size='lg'] {\n width: var(--rv-modal-width-lg);\n }\n .rv-modal[data-size='xl'] {\n width: var(--rv-modal-width-xl);\n }\n .rv-modal[data-size='full'] {\n width: calc(100dvw - 2rem);\n }\n .rv-modal[data-size='auto'] {\n width: auto;\n }\n .rv-modal[data-position='top'] {\n margin-block-start: 8dvh;\n }\n .rv-modal[data-position='bottom'] {\n margin-block-start: auto;\n margin-block-end: 8dvh;\n }\n .rv-modal[data-position='top-start'],\n .rv-modal[data-position='center-start'] {\n margin-inline-start: 1rem;\n margin-inline-end: auto;\n }\n .rv-modal[data-position='top-end'],\n .rv-modal[data-position='center-end'] {\n margin-inline-start: auto;\n margin-inline-end: 1rem;\n }\n .rv-modal[data-position='bottom-start'] {\n margin-block-start: auto;\n margin-inline-start: 1rem;\n }\n .rv-modal[data-position='bottom-end'] {\n margin-block-start: auto;\n margin-inline-end: 1rem;\n }\n .rv-modal[data-position='fullscreen'] {\n inset: 0;\n width: 100dvw;\n height: 100dvh;\n height: 100dvh;\n max-width: none;\n max-height: none;\n border-radius: 0;\n }\n .rv-modal[data-position='side-start'],\n .rv-modal[data-position='side-end'] {\n height: 100dvh;\n max-height: none;\n width: var(--rv-modal-width-panel);\n margin-block: 0;\n }\n .rv-modal[data-position='side-start'] {\n margin-inline-start: 0;\n margin-inline-end: auto;\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n .rv-modal[data-position='side-end'] {\n margin-inline-start: auto;\n margin-inline-end: 0;\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n @media (max-width: 640px) {\n .rv-modal[data-position='center'],\n .rv-modal[data-position='top'],\n .rv-modal[data-position='bottom'],\n .rv-modal[data-position='bottom-start'],\n .rv-modal[data-position='bottom-end'] {\n margin-block-start: auto;\n margin-block-end: 0;\n margin-inline: 0;\n width: 100dvw;\n max-width: none;\n border-end-end-radius: 0;\n border-end-start-radius: 0;\n border-start-start-radius: var(--rv-modal-radius-sheet);\n border-start-end-radius: var(--rv-modal-radius-sheet);\n }\n .rv-modal[data-position='center'][data-state='open'],\n .rv-modal[data-position='top'][data-state='open'],\n .rv-modal[data-position='bottom'][data-state='open'],\n .rv-modal[data-position='bottom-start'][data-state='open'],\n .rv-modal[data-position='bottom-end'][data-state='open'] {\n animation-name: rv-modal-in-bottom;\n }\n }\n .rv-modal[data-animation]:not([data-animation='none'])[data-state='open'] {\n animation: var(--rv-modal-animation-in, rv-modal-in) var(--rv-modal-duration-in)\n var(--rv-modal-easing-in);\n }\n .rv-modal[data-animation='scale'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-scale;\n }\n .rv-modal[data-animation='slide-top'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-top;\n }\n .rv-modal[data-animation='slide-bottom'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-bottom;\n }\n .rv-modal[data-animation='slide-start'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-start;\n }\n .rv-modal[data-animation='slide-end'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-end;\n }\n [dir='rtl'] .rv-modal[data-animation='slide-start'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-end;\n }\n [dir='rtl'] .rv-modal[data-animation='slide-end'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-start;\n }\n .rv-modal[data-state='closing'] {\n animation: rv-modal-out var(--rv-modal-duration-out) var(--rv-modal-easing-out) forwards;\n }\n @keyframes rv-modal-in {\n from {\n opacity: 0;\n }\n }\n @keyframes rv-modal-in-scale {\n from {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n }\n @keyframes rv-modal-in-top {\n from {\n opacity: 0;\n transform: translateY(-24px);\n }\n }\n @keyframes rv-modal-in-bottom {\n from {\n opacity: 0;\n transform: translateY(24px);\n }\n }\n @keyframes rv-modal-in-start {\n from {\n opacity: 0;\n transform: translateX(-24px);\n }\n }\n @keyframes rv-modal-in-end {\n from {\n opacity: 0;\n transform: translateX(24px);\n }\n }\n @keyframes rv-modal-out {\n to {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .rv-modal[data-animation] {\n animation: none;\n }\n }\n .rv-modal-header {\n display: flex;\n align-items: flex-start;\n gap: var(--rv-modal-gap);\n padding: var(--rv-modal-pad) var(--rv-modal-pad) 0;\n }\n .rv-modal-header-custom > :first-child {\n flex: 1;\n min-width: 0;\n }\n .rv-modal-heading:empty {\n display: none;\n }\n .rv-modal-title {\n margin: 0;\n font-size: 1.125rem;\n flex: 1;\n }\n .rv-modal-heading {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n .rv-modal-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--rv-modal-muted);\n }\n .rv-modal-close {\n margin-inline-start: auto;\n flex: none;\n border: 1px solid var(--rv-modal-border);\n border-radius: 8px;\n background: transparent;\n color: inherit;\n font-size: 1.25rem;\n line-height: 1;\n padding: 4px 10px;\n cursor: pointer;\n }\n .rv-modal-close:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n }\n .rv-modal-body {\n padding: var(--rv-modal-pad);\n overflow: auto;\n max-height: inherit;\n }\n .rv-modal-footer {\n display: flex;\n gap: var(--rv-modal-gap);\n justify-content: flex-end;\n padding: 0 var(--rv-modal-pad) var(--rv-modal-pad);\n }\n .rv-modal-footer:empty {\n display: none;\n }\n `,\n ],\n})\nexport class RiviniaModalDialog {\n /** Two-way open state. UI-only mode owns this; the host drives it in managed mode. */\n readonly open = model<boolean>(false);\n\n readonly title = input<string>('');\n /**\n * Supporting text under the title (shadcn-style description). Rendered in\n * the default header only, and wired as the dialog's `aria-describedby`\n * for free accessible naming. Empty = no description element at all.\n */\n readonly description = input<string>('');\n /** Explicit accessible name. When set, `aria-label` wins over the title reference. */\n readonly ariaLabel = input<string>('');\n readonly size = input<RiviniaModalSize>('md');\n readonly position = input<RiviniaModalPosition>('center');\n readonly animation = input<RiviniaModalAnimation>('scale');\n readonly closeOnEscape = input<boolean>(true);\n readonly backdrop = input<RiviniaModalBackdrop>('close');\n readonly showCloseButton = input<boolean>(true);\n /**\n * Managed mode (for {@link RiviniaModalHost}): UI intents (X button,\n * Escape, backdrop) emit `dismissRequested` INSTEAD of dismissing, so the\n * manager runs guards first and settles results. Drive the exit with the\n * `closing` input; acknowledge teardown with `exitDone`.\n * UI-only mode (`false`, default) dismisses locally.\n */\n readonly managed = input<boolean>(false);\n /**\n * Managed-mode exit trigger. Set `true` when the manager reports this\n * instance `closing`: the dialog plays its exit animation, then emits\n * `exitDone` (call `confirmClosed()` there). Ignored in UI-only mode.\n */\n readonly closing = input<boolean>(false);\n\n /** Settled with a value (primary/confirm actions call `close(value)`). */\n readonly confirmed = output<unknown>();\n /** Settled without a value (X button, backdrop, Escape, `dismiss()`). */\n readonly dismissed = output<string | undefined>();\n /** Explicit cancellation (`cancel()`). Kept distinct from dismissal. */\n readonly cancelled = output<string | undefined>();\n /**\n * Managed-mode intent (X button / Escape / backdrop). Emitted INSTEAD of\n * dismissing — the host routes it to the manager first. Never emitted in\n * UI-only mode.\n */\n readonly dismissRequested = output<'button' | 'escape' | 'backdrop'>();\n /** Managed-mode exit completion. Acknowledge with `confirmClosed()`. */\n readonly exitDone = output<void>();\n\n private readonly dialog = viewChild<ElementRef<HTMLDialogElement>>('dialog');\n private readonly headerSlot = contentChild(RvModalHeader);\n private readonly footerSlot = contentChild(RvModalFooter);\n private readonly doc = inject(DOCUMENT, { optional: true });\n private readonly scrollLock = inject(RiviniaModalScrollLock, { optional: true });\n private readonly titleId = `rv-modal-${++dialogSeq}`;\n private readonly descriptionId = `rv-modal-desc-${dialogSeq}`;\n private readonly phase = signal<'closed' | 'open' | 'closing'>('closed');\n private readonly invoker: { current: Element | null } = { current: null };\n private exitTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Template state for animation styling. Never rendered open on the server. */\n readonly state = computed(() => this.phase());\n readonly hasCustomHeader = computed(() => this.headerSlot() !== undefined);\n readonly hasCustomFooter = computed(() => this.footerSlot() !== undefined);\n readonly computedLabel = computed(() => this.ariaLabel() || null);\n\n constructor() {\n effect(() => {\n if (this.open()) this.show();\n // External close acts only while fully open: during 'closing' the\n // exit animation owns teardown (its timer finalizes). This guard is\n // what keeps `finish()` from cutting the animation via `open.set(false)`.\n else if (this.phase() === 'open') this.hide();\n });\n effect(() => {\n // Managed exit: the manager moved this instance to `closing`.\n if (this.managed() && this.closing() && this.phase() === 'open') {\n this.playExit(() => this.exitDone.emit());\n }\n });\n }\n\n /** Confirm with a value. No-op while closing/closed. */\n confirm(value?: unknown): boolean {\n if (this.phase() !== 'open') return false;\n this.finish('confirmed', value);\n return true;\n }\n\n /** Backwards-compatible close: confirms when given a value, dismisses otherwise. */\n close(value?: unknown): boolean {\n return value === undefined ? this.dismiss() : this.confirm(value);\n }\n\n /** Dismiss without a value (X button, backdrop, Escape route here). */\n dismiss(reason?: string): boolean {\n if (this.phase() !== 'open') return false;\n this.finish('dismissed', undefined, reason);\n return true;\n }\n\n /** Explicit cancellation. */\n cancel(reason?: string): boolean {\n if (this.phase() !== 'open') return false;\n this.finish('cancelled', undefined, reason);\n return true;\n }\n\n protected onCloseButton(): void {\n if (this.managed()) {\n if (this.phase() === 'open') this.dismissRequested.emit('button');\n return;\n }\n this.dismiss('close-button');\n }\n\n protected onCancel(event: Event): void {\n if (!this.closeOnEscape()) {\n event.preventDefault();\n return;\n }\n // Native `cancel` already closed nothing yet — route through our pipeline\n // so scroll-lock, focus restore and outputs stay consistent.\n event.preventDefault();\n if (this.managed()) {\n if (this.phase() === 'open') this.dismissRequested.emit('escape');\n return;\n }\n this.dismiss('escape');\n }\n\n protected onBackdropClick(event: MouseEvent): void {\n const el = this.dialog()?.nativeElement;\n if (!el || event.target !== el) return; // inside clicks never count\n if (this.backdrop() !== 'close') return;\n if (this.managed()) {\n if (this.phase() === 'open') this.dismissRequested.emit('backdrop');\n return;\n }\n this.dismiss('backdrop');\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Tab') return;\n const el = this.dialog()?.nativeElement;\n if (!el) return;\n const items = focusables(el);\n if (items.length === 0) {\n event.preventDefault();\n return;\n }\n const first = items[0];\n const last = items[items.length - 1];\n const active = (this.doc ?? document).activeElement;\n if (event.shiftKey && (active === first || !el.contains(active))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n }\n\n private get live(): boolean {\n return typeof window !== 'undefined' && !!this.doc;\n }\n\n private show(): void {\n if (!this.live) return; // SSR: stay closed until client hydration opens us\n const el = this.dialog()?.nativeElement;\n if (!el || this.phase() !== 'closed') return;\n try {\n this.invoker.current = this.doc?.activeElement ?? null;\n } catch {\n this.invoker.current = null;\n }\n this.scrollLock?.acquire();\n this.phase.set('open');\n if (!el.open) {\n try {\n el.showModal();\n } catch {\n // Already open (e.g. double effect run): continue — state is ours.\n }\n }\n focusFirst(el, this.showCloseButton());\n }\n\n private hide(): void {\n if (this.phase() === 'closed') return;\n this.teardown(false);\n }\n\n private finish(\n kind: 'confirmed' | 'dismissed' | 'cancelled',\n value?: unknown,\n reason?: string,\n ): void {\n this.teardown(true);\n if (kind === 'confirmed') this.confirmed.emit(value);\n else if (kind === 'dismissed') this.dismissed.emit(reason);\n else this.cancelled.emit(reason);\n if (this.open()) this.open.set(false);\n }\n\n private teardown(animate: boolean): void {\n if (!animate) {\n if (this.exitTimer) {\n clearTimeout(this.exitTimer);\n this.exitTimer = null;\n }\n this.finalize(this.dialog()?.nativeElement ?? null);\n return;\n }\n this.playExit(() => {});\n }\n\n /** Plays the exit animation (when warranted), then runs `done`. Idempotent. */\n private playExit(done: () => void): void {\n if (this.phase() !== 'open') {\n done();\n return;\n }\n if (this.exitTimer) {\n clearTimeout(this.exitTimer);\n this.exitTimer = null;\n }\n const el = this.dialog()?.nativeElement ?? null;\n const animated = this.animation() !== 'none' && this.prefersMotion() && !!el?.open;\n this.phase.set(animated ? 'closing' : 'closed');\n if (!animated) {\n this.finalize(el);\n done();\n return;\n }\n // Honor consumer-overridden durations instead of a fixed fallback, so a\n // longer `--rv-modal-duration-out` is never cut short.\n this.exitTimer = setTimeout(() => {\n this.finalize(el);\n done();\n }, this.exitDurationMs(el));\n }\n\n private exitDurationMs(el: HTMLDialogElement | null): number {\n try {\n const raw = el ? getComputedStyle(el).animationDuration : '';\n const seconds = raw\n .split(',')\n .map((part) => parseFloat(part))\n .filter((n) => Number.isFinite(n));\n if (seconds.length > 0) return Math.max(0, Math.max(...seconds) * 1000) + 50;\n } catch {\n // Non-CSS environments (tests): fall through to the fallback.\n }\n return EXIT_FALLBACK_MS;\n }\n\n private finalize(el: HTMLDialogElement | null): void {\n this.exitTimer = null;\n try {\n el?.close();\n } catch {\n // Already closed natively — ours to reconcile, not to throw.\n }\n this.phase.set('closed');\n this.scrollLock?.release();\n const invoker = this.invoker.current as HTMLElement | null;\n this.invoker.current = null;\n try {\n invoker?.focus?.();\n } catch {\n // Invoker gone (navigated away) — nothing to restore to.\n }\n }\n\n private prefersMotion(): boolean {\n try {\n return (\n typeof window !== 'undefined' &&\n !window.matchMedia('(prefers-reduced-motion: reduce)').matches\n );\n } catch {\n return true;\n }\n }\n}\n\nlet dialogSeq = 0;\n\nfunction focusables(root: HTMLElement): HTMLElement[] {\n // No visibility filtering on purpose: jsdom reports zero rects (unit\n // tests), and `disabled` is already excluded by the selector. Hidden\n // focusables inside a visible dialog are a consumer edge, not ours.\n const selector =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), ' +\n 'textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n return Array.from(root.querySelectorAll<HTMLElement>(selector));\n}\n\nfunction focusFirst(dialog: HTMLDialogElement, closeVisible: boolean): void {\n try {\n const auto = dialog.querySelector<HTMLElement>('[autofocus]');\n if (auto) {\n auto.focus({ preventScroll: true });\n return;\n }\n // Atlassian rule: no close button → focus the title; otherwise the\n // dialog itself (its tabindex=\"-1\" makes it focusable).\n if (!closeVisible) {\n const title = dialog.querySelector<HTMLElement>('.rv-modal-title');\n if (title) {\n title.setAttribute('tabindex', '-1');\n title.focus({ preventScroll: true });\n return;\n }\n }\n dialog.focus({ preventScroll: true });\n } catch {\n // Focus is best-effort (e.g. during teardown races).\n }\n}\n","import { Component, Injector, computed, input } from '@angular/core';\nimport type { Signal } from '@angular/core';\nimport { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { RIVINIA_MODAL_CONTEXT } from '@rivinia/modal';\nimport type {\n ModalContext,\n ModalDismissOrigin,\n ModalInstance,\n ModalTemplateContext,\n} from '@rivinia/modal';\nimport { RiviniaModalDialog } from './modal-dialog';\nimport type { RiviniaModalSize } from './ui-types';\n\n/**\n * Managed adapter: renders every `visible()` instance of the headless\n * `RiviniaModal` inside a {@link RiviniaModalDialog} and routes all UI\n * intents through the manager first (guards run; results settle in Core —\n * the single source of truth). The dialog never settles anything itself in\n * this mode; listen to `ModalHandle.result`, not dialog outputs.\n *\n * Exit coordination: when Core reports an instance `closing`, the dialog\n * plays its exit animation and the host acknowledges with `confirmClosed()`\n * (idempotent — safe if `closingTimeout` auto-finalized first). Match\n * `closingTimeout` to the animation duration so exits stay visible.\n *\n * Title resolution: `titleOf` per instance (default: `metadata.title` →\n * `ref` → `''`). Content descriptors render as-is: templates via\n * `ngTemplateOutlet` with `{$implicit: data, modal}`, components via\n * `NgComponentOutlet` with `inputs` + a per-instance\n * `RIVINIA_MODAL_CONTEXT` injector (the lab-proven pattern).\n *\n * The manager arrives via `[modal]` input (D06 input-composition: the UI\n * entry never instantiates Core itself, so UI-only consumers pay nothing).\n * The input is typed as {@link RiviniaModalHostManager} — the structural\n * slice the host actually drives — so the full manager (or a test double)\n * satisfies it from any module realm:\n *\n * ```html\n * <rv-modal-host [modal]=\"injectRiviniaModal()\" />\n * ```\n */\nexport interface RiviniaModalHostManager {\n readonly visible: Signal<readonly ModalInstance<unknown>[]>;\n requestDismiss(id: string, origin: ModalDismissOrigin): Promise<boolean>;\n confirmClosed(id: string): boolean;\n close(id: string, value?: unknown): boolean;\n dismiss(id: string, reason?: string): boolean;\n}\n\n@Component({\n selector: 'rv-modal-host',\n standalone: true,\n imports: [RiviniaModalDialog, NgComponentOutlet, NgTemplateOutlet],\n template: `\n @for (instance of visible(); track instance.id) {\n <rv-modal-dialog\n [open]=\"true\"\n [managed]=\"true\"\n [closing]=\"instance.status === 'closing'\"\n [title]=\"titleOfInstance(instance)\"\n [size]=\"size()\"\n [showCloseButton]=\"showCloseButton()\"\n [closeOnEscape]=\"instance.dismiss.closeOnEscape ?? true\"\n [backdrop]=\"instance.dismiss.backdrop ?? 'close'\"\n (dismissRequested)=\"onIntent(instance.id, $event)\"\n (exitDone)=\"onExitDone(instance.id)\"\n >\n @if (instance.content.kind === 'template') {\n <ng-container\n *ngTemplateOutlet=\"instance.content.template; context: templateContext(instance)\"\n ></ng-container>\n } @else {\n <ng-container\n *ngComponentOutlet=\"\n instance.content.component;\n inputs: instance.content.inputs;\n injector: contextInjector(instance)\n \"\n ></ng-container>\n }\n </rv-modal-dialog>\n }\n `,\n})\nexport class RiviniaModalHost {\n /**\n * The headless manager to render. Typed as {@link RiviniaModalHostManager}\n * (structural) — pass `injectRiviniaModal()` from your app code.\n */\n readonly modal = input.required<RiviniaModalHostManager>();\n\n /** Dialog size for every managed instance. @default 'md' */\n readonly size = input<RiviniaModalSize>('md');\n /** Render the header close button on every managed instance. @default true */\n readonly showCloseButton = input<boolean>(true);\n /** Resolve a title per instance. Default: `metadata.title` → `ref` → `''`. */\n readonly titleOf = input<(instance: ModalInstance<unknown>) => string | undefined>();\n\n protected readonly visible = computed(() => this.modal().visible());\n\n protected titleOfInstance(instance: ModalInstance<unknown>): string {\n try {\n const custom = this.titleOf()?.(instance);\n if (custom !== undefined) return custom;\n } catch {\n // A throwing resolver must never break rendering — fall through.\n }\n const meta = instance.metadata?.['title'];\n if (typeof meta === 'string' && meta.length > 0) return meta;\n return instance.ref ?? '';\n }\n\n protected templateContext(instance: ModalInstance<unknown>): ModalTemplateContext<unknown> {\n return { $implicit: instance.data, modal: this.modalContext(instance) };\n }\n\n protected contextInjector(instance: ModalInstance<unknown>): Injector {\n const modal = this.modal();\n return Injector.create({\n providers: [\n {\n provide: RIVINIA_MODAL_CONTEXT,\n useValue: {\n id: instance.id,\n data: instance.data,\n parentId: instance.parentId,\n close: (result?: unknown) => modal.close(instance.id, result),\n dismiss: (reason?: string) => modal.dismiss(instance.id, reason),\n } satisfies ModalContext<unknown>,\n },\n ],\n });\n }\n\n protected async onIntent(id: string, origin: 'button' | 'escape' | 'backdrop'): Promise<void> {\n try {\n await this.modal().requestDismiss(id, origin);\n } catch {\n // requestDismiss never rejects (deny-safe by contract) — defensive only.\n }\n // Granted → status flips to `closing` → dialog exit → `exitDone`.\n // Denied → nothing moves; the dialog never left `open`. No manual toggle.\n }\n\n protected onExitDone(id: string): void {\n this.modal().confirmClosed(id);\n }\n\n private modalContext(instance: ModalInstance<unknown>): ModalContext<unknown> {\n const modal = this.modal();\n const id = instance.id;\n return {\n id,\n data: instance.data,\n parentId: instance.parentId,\n close: (result?: unknown) => modal.close(id, result),\n dismiss: (reason?: string) => modal.dismiss(id, reason),\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rivinia-modal-ui.mjs","names":[],"sources":["../../../projects/modal/ui/src/lib/modal-scroll-lock.ts","../../../projects/modal/ui/src/lib/modal-dialog.ts","../../../projects/modal/ui/src/lib/modal-host.ts"],"sourcesContent":["import { DOCUMENT, Service, inject } from '@angular/core';\n\n/**\n * Reference-counted background scroll lock. Multiple overlays share one lock:\n * closing one modal never unlocks the page while another still needs it.\n * Restores the exact previous `overflow` value (never blanks app-owned\n * styles). All DOM access happens inside methods — never at module\n * evaluation — and every method is a no-op without a document (SSR).\n */\n@Service()\nexport class RiviniaModalScrollLock {\n private readonly _doc = inject(DOCUMENT, { optional: true });\n private _locks = 0;\n private _previousOverflow: string | null = null;\n\n /** Number of active locks (diagnostics/tests). */\n get active(): number {\n return this._locks;\n }\n\n acquire(): void {\n const doc = this.document;\n if (!doc) return;\n this._locks += 1;\n if (this._locks > 1) return;\n const body = doc.body;\n this._previousOverflow = body.style.overflow || null;\n body.style.overflow = 'hidden';\n // Reserve the scrollbar gutter where supported so content does not jump.\n // Overlay scrollbars ignore it; that is documented, not promised.\n doc.documentElement.style.setProperty('scrollbar-gutter', 'stable');\n }\n\n release(): void {\n const doc = this.document;\n if (!doc || this._locks === 0) {\n this._locks = 0;\n return;\n }\n this._locks -= 1;\n if (this._locks > 0) return;\n const body = doc.body;\n if (this._previousOverflow === null) body.style.removeProperty('overflow');\n else body.style.overflow = this._previousOverflow;\n this._previousOverflow = null;\n doc.documentElement.style.removeProperty('scrollbar-gutter');\n }\n\n private get document(): Document | null {\n try {\n return this._doc ?? (typeof document === 'undefined' ? null : document);\n } catch {\n return null;\n }\n }\n}\n","import {\n Component,\n Directive,\n DOCUMENT,\n ElementRef,\n ViewEncapsulation,\n computed,\n contentChild,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { RiviniaModalScrollLock } from './modal-scroll-lock';\nimport type {\n RiviniaModalAnimation,\n RiviniaModalBackdrop,\n RiviniaModalPosition,\n RiviniaModalSize,\n} from './ui-types';\n\nconst EXIT_FALLBACK_MS = 200;\n\n/**\n * Marker for custom header content. Put it on the element carrying\n * `rv-modal-header` — its presence (not just the attribute) tells the\n * dialog to hide the default title + close button:\n *\n * ```html\n * <div rv-modal-header rvModalHeader>My header</div>\n * ```\n */\n@Directive({ selector: '[rvModalHeader]', standalone: true })\nexport class RvModalHeader {}\n\n/**\n * Marker for custom footer content. Put it on the element carrying\n * `rv-modal-footer`. Without it the footer region never renders.\n */\n@Directive({ selector: '[rvModalFooter]', standalone: true })\nexport class RvModalFooter {}\n\n/**\n * Ready-made modal dialog on the native `<dialog>` element (top layer,\n * `::backdrop`, inert background, Escape `cancel` event — all platform\n * behavior, zero overlay dependencies).\n *\n * UI-only by design: it owns its own `open` state and never imports the\n * headless controller. Pair it with `@rivinia/modal` through\n * {@link RiviniaModalHost} (or your own adapter) when you want managed\n * lifecycle, guards and typed results.\n *\n * Projection: `[rv-modal-header]` replaces the default header (title +\n * close button); default `<ng-content>` is the body; `[rv-modal-footer]`\n * is optional and renders nothing when absent.\n */\n@Component({\n selector: 'rv-modal-dialog',\n standalone: true,\n // Unencapsulated like rv-menu: custom projected headers/footers belong to\n // the consumer's template, which emulated selectors cannot reach. Every\n // rule is scoped under `.rv-modal`, so nothing leaks.\n encapsulation: ViewEncapsulation.None,\n template: `\n <dialog\n #dialog\n tabindex=\"-1\"\n class=\"rv-modal\"\n [attr.data-size]=\"size()\"\n [attr.data-position]=\"position()\"\n [attr.data-animation]=\"animation()\"\n [attr.data-state]=\"state()\"\n [attr.aria-label]=\"computedLabel()\"\n [attr.aria-labelledby]=\"title() && !ariaLabel() ? titleId : null\"\n [attr.aria-describedby]=\"description() ? descriptionId : null\"\n (cancel)=\"onCancel($event)\"\n (click)=\"onBackdropClick($event)\"\n (keydown)=\"onKeydown($event)\"\n >\n @if (hasCustomHeader()) {\n <div class=\"rv-modal-header rv-modal-header-custom\">\n <ng-content select=\"[rv-modal-header]\"></ng-content>\n </div>\n } @else if (title() || showCloseButton()) {\n <div class=\"rv-modal-header\">\n <div class=\"rv-modal-heading\">\n @if (title()) {\n <h2 class=\"rv-modal-title\" [id]=\"titleId\">{{ title() }}</h2>\n }\n @if (description()) {\n <p class=\"rv-modal-description\" [id]=\"descriptionId\">{{ description() }}</p>\n }\n </div>\n @if (showCloseButton()) {\n <button\n type=\"button\"\n class=\"rv-modal-close\"\n (click)=\"onCloseButton()\"\n aria-label=\"Close dialog\"\n >\n <span aria-hidden=\"true\">&times;</span>\n </button>\n }\n </div>\n }\n <div class=\"rv-modal-body\">\n <ng-content></ng-content>\n </div>\n @if (hasCustomFooter()) {\n <div class=\"rv-modal-footer\">\n <ng-content select=\"[rv-modal-footer]\"></ng-content>\n </div>\n }\n </dialog>\n `,\n styles: [\n `\n .rv-modal {\n color-scheme: light dark;\n --rv-modal-bg: #ffffff;\n --rv-modal-fg: #111111;\n --rv-modal-muted: #555555;\n --rv-modal-border: #e0e0e0;\n --rv-modal-radius: 12px;\n --rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, 0.28);\n --rv-modal-backdrop: rgba(0, 0, 0, 0.5);\n --rv-modal-pad: 20px;\n --rv-modal-gap: 12px;\n --rv-modal-width-sm: 24rem;\n --rv-modal-width-md: 32rem;\n --rv-modal-width-lg: 48rem;\n --rv-modal-width-xl: 64rem;\n --rv-modal-max-height: min(86dvh, 100%);\n --rv-modal-duration: 150ms;\n --rv-modal-duration-in: var(--rv-modal-duration);\n --rv-modal-duration-out: 120ms;\n --rv-modal-easing: ease-out;\n --rv-modal-easing-in: var(--rv-modal-easing);\n --rv-modal-easing-out: ease-in;\n --rv-modal-radius-sheet: 20px;\n --rv-modal-width-panel: 24rem;\n padding: 0;\n border: 1px solid var(--rv-modal-border);\n border-radius: var(--rv-modal-radius);\n background: var(--rv-modal-bg);\n color: var(--rv-modal-fg);\n box-shadow: var(--rv-modal-shadow);\n max-height: var(--rv-modal-max-height);\n width: var(--rv-modal-width-md);\n max-width: calc(100dvw - 2rem);\n }\n @media (prefers-color-scheme: dark) {\n .rv-modal {\n --rv-modal-bg: #161616;\n --rv-modal-fg: #f2f2f2;\n --rv-modal-muted: #a8a8a8;\n --rv-modal-border: #333333;\n --rv-modal-shadow: 0 24px 64px rgba(0, 0, 0, 0.6);\n }\n }\n .rv-modal::backdrop {\n background: var(--rv-modal-backdrop);\n }\n .rv-modal[data-size='sm'] {\n width: var(--rv-modal-width-sm);\n }\n .rv-modal[data-size='lg'] {\n width: var(--rv-modal-width-lg);\n }\n .rv-modal[data-size='xl'] {\n width: var(--rv-modal-width-xl);\n }\n .rv-modal[data-size='full'] {\n width: calc(100dvw - 2rem);\n }\n .rv-modal[data-size='auto'] {\n width: auto;\n }\n .rv-modal[data-position='top'] {\n margin-block-start: 8dvh;\n }\n .rv-modal[data-position='bottom'] {\n margin-block-start: auto;\n margin-block-end: 8dvh;\n }\n .rv-modal[data-position='top-start'],\n .rv-modal[data-position='center-start'] {\n margin-inline-start: 1rem;\n margin-inline-end: auto;\n }\n .rv-modal[data-position='top-end'],\n .rv-modal[data-position='center-end'] {\n margin-inline-start: auto;\n margin-inline-end: 1rem;\n }\n .rv-modal[data-position='bottom-start'] {\n margin-block-start: auto;\n margin-inline-start: 1rem;\n }\n .rv-modal[data-position='bottom-end'] {\n margin-block-start: auto;\n margin-inline-end: 1rem;\n }\n .rv-modal[data-position='fullscreen'] {\n inset: 0;\n width: 100dvw;\n height: 100dvh;\n height: 100dvh;\n max-width: none;\n max-height: none;\n border-radius: 0;\n }\n .rv-modal[data-position='side-start'],\n .rv-modal[data-position='side-end'] {\n height: 100dvh;\n max-height: none;\n width: var(--rv-modal-width-panel);\n margin-block: 0;\n }\n .rv-modal[data-position='side-start'] {\n margin-inline-start: 0;\n margin-inline-end: auto;\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n }\n .rv-modal[data-position='side-end'] {\n margin-inline-start: auto;\n margin-inline-end: 0;\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n }\n @media (max-width: 640px) {\n .rv-modal[data-position='center'],\n .rv-modal[data-position='top'],\n .rv-modal[data-position='bottom'],\n .rv-modal[data-position='bottom-start'],\n .rv-modal[data-position='bottom-end'] {\n margin-block-start: auto;\n margin-block-end: 0;\n margin-inline: 0;\n width: 100dvw;\n max-width: none;\n border-end-end-radius: 0;\n border-end-start-radius: 0;\n border-start-start-radius: var(--rv-modal-radius-sheet);\n border-start-end-radius: var(--rv-modal-radius-sheet);\n }\n .rv-modal[data-position='center'][data-state='open'],\n .rv-modal[data-position='top'][data-state='open'],\n .rv-modal[data-position='bottom'][data-state='open'],\n .rv-modal[data-position='bottom-start'][data-state='open'],\n .rv-modal[data-position='bottom-end'][data-state='open'] {\n animation-name: rv-modal-in-bottom;\n }\n }\n .rv-modal[data-animation]:not([data-animation='none'])[data-state='open'] {\n animation: var(--rv-modal-animation-in, rv-modal-in) var(--rv-modal-duration-in)\n var(--rv-modal-easing-in);\n }\n .rv-modal[data-animation='scale'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-scale;\n }\n .rv-modal[data-animation='slide-top'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-top;\n }\n .rv-modal[data-animation='slide-bottom'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-bottom;\n }\n .rv-modal[data-animation='slide-start'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-start;\n }\n .rv-modal[data-animation='slide-end'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-end;\n }\n [dir='rtl'] .rv-modal[data-animation='slide-start'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-end;\n }\n [dir='rtl'] .rv-modal[data-animation='slide-end'][data-state='open'] {\n --rv-modal-animation-in: rv-modal-in-start;\n }\n .rv-modal[data-state='closing'] {\n animation: rv-modal-out var(--rv-modal-duration-out) var(--rv-modal-easing-out) forwards;\n }\n @keyframes rv-modal-in {\n from {\n opacity: 0;\n }\n }\n @keyframes rv-modal-in-scale {\n from {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n }\n @keyframes rv-modal-in-top {\n from {\n opacity: 0;\n transform: translateY(-24px);\n }\n }\n @keyframes rv-modal-in-bottom {\n from {\n opacity: 0;\n transform: translateY(24px);\n }\n }\n @keyframes rv-modal-in-start {\n from {\n opacity: 0;\n transform: translateX(-24px);\n }\n }\n @keyframes rv-modal-in-end {\n from {\n opacity: 0;\n transform: translateX(24px);\n }\n }\n @keyframes rv-modal-out {\n to {\n opacity: 0;\n transform: translateY(8px) scale(0.98);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .rv-modal[data-animation] {\n animation: none;\n }\n }\n .rv-modal-header {\n display: flex;\n align-items: flex-start;\n gap: var(--rv-modal-gap);\n padding: var(--rv-modal-pad) var(--rv-modal-pad) 0;\n }\n .rv-modal-header-custom > :first-child {\n flex: 1;\n min-width: 0;\n }\n .rv-modal-heading:empty {\n display: none;\n }\n .rv-modal-title {\n margin: 0;\n font-size: 1.125rem;\n flex: 1;\n }\n .rv-modal-heading {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n .rv-modal-description {\n margin: 0;\n font-size: 0.875rem;\n color: var(--rv-modal-muted);\n }\n .rv-modal-close {\n margin-inline-start: auto;\n flex: none;\n border: 1px solid var(--rv-modal-border);\n border-radius: 8px;\n background: transparent;\n color: inherit;\n font-size: 1.25rem;\n line-height: 1;\n padding: 4px 10px;\n cursor: pointer;\n }\n .rv-modal-close:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n }\n .rv-modal-body {\n padding: var(--rv-modal-pad);\n overflow: auto;\n max-height: inherit;\n }\n .rv-modal-footer {\n display: flex;\n gap: var(--rv-modal-gap);\n justify-content: flex-end;\n padding: 0 var(--rv-modal-pad) var(--rv-modal-pad);\n }\n .rv-modal-footer:empty {\n display: none;\n }\n `,\n ],\n})\nexport class RiviniaModalDialog {\n /** Two-way open state. UI-only mode owns this; the host drives it in managed mode. */\n readonly open = model<boolean>(false);\n\n readonly title = input<string>('');\n /**\n * Supporting text under the title (shadcn-style description). Rendered in\n * the default header only, and wired as the dialog's `aria-describedby`\n * for free accessible naming. Empty = no description element at all.\n */\n readonly description = input<string>('');\n /** Explicit accessible name. When set, `aria-label` wins over the title reference. */\n readonly ariaLabel = input<string>('');\n readonly size = input<RiviniaModalSize>('md');\n readonly position = input<RiviniaModalPosition>('center');\n readonly animation = input<RiviniaModalAnimation>('scale');\n readonly closeOnEscape = input<boolean>(true);\n readonly backdrop = input<RiviniaModalBackdrop>('close');\n readonly showCloseButton = input<boolean>(true);\n /**\n * Managed mode (for {@link RiviniaModalHost}): UI intents (X button,\n * Escape, backdrop) emit `dismissRequested` INSTEAD of dismissing, so the\n * manager runs guards first and settles results. Drive the exit with the\n * `closing` input; acknowledge teardown with `exitDone`.\n * UI-only mode (`false`, default) dismisses locally.\n */\n readonly managed = input<boolean>(false);\n /**\n * Managed-mode exit trigger. Set `true` when the manager reports this\n * instance `closing`: the dialog plays its exit animation, then emits\n * `exitDone` (call `confirmClosed()` there). Ignored in UI-only mode.\n */\n readonly closing = input<boolean>(false);\n\n /** Settled with a value (primary/confirm actions call `close(value)`). */\n readonly confirmed = output<unknown>();\n /** Settled without a value (X button, backdrop, Escape, `dismiss()`). */\n readonly dismissed = output<string | undefined>();\n /** Explicit cancellation (`cancel()`). Kept distinct from dismissal. */\n readonly cancelled = output<string | undefined>();\n /**\n * Managed-mode intent (X button / Escape / backdrop). Emitted INSTEAD of\n * dismissing — the host routes it to the manager first. Never emitted in\n * UI-only mode.\n */\n readonly dismissRequested = output<'button' | 'escape' | 'backdrop'>();\n /** Managed-mode exit completion. Acknowledge with `confirmClosed()`. */\n readonly exitDone = output<void>();\n\n private readonly dialog = viewChild<ElementRef<HTMLDialogElement>>('dialog');\n private readonly headerSlot = contentChild(RvModalHeader);\n private readonly footerSlot = contentChild(RvModalFooter);\n private readonly doc = inject(DOCUMENT, { optional: true });\n private readonly scrollLock = inject(RiviniaModalScrollLock, { optional: true });\n private readonly titleId = `rv-modal-${++dialogSeq}`;\n private readonly descriptionId = `rv-modal-desc-${dialogSeq}`;\n private readonly phase = signal<'closed' | 'open' | 'closing'>('closed');\n private readonly invoker: { current: Element | null } = { current: null };\n private exitTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** Template state for animation styling. Never rendered open on the server. */\n readonly state = computed(() => this.phase());\n readonly hasCustomHeader = computed(() => this.headerSlot() !== undefined);\n readonly hasCustomFooter = computed(() => this.footerSlot() !== undefined);\n readonly computedLabel = computed(() => this.ariaLabel() || null);\n\n constructor() {\n effect(() => {\n if (this.open()) this.show();\n // External close acts only while fully open: during 'closing' the\n // exit animation owns teardown (its timer finalizes). This guard is\n // what keeps `finish()` from cutting the animation via `open.set(false)`.\n else if (this.phase() === 'open') this.hide();\n });\n effect(() => {\n // Managed exit: the manager moved this instance to `closing`.\n if (this.managed() && this.closing() && this.phase() === 'open') {\n this.playExit(() => this.exitDone.emit());\n }\n });\n }\n\n /** Confirm with a value. No-op while closing/closed. */\n confirm(value?: unknown): boolean {\n if (this.phase() !== 'open') return false;\n this.finish('confirmed', value);\n return true;\n }\n\n /** Backwards-compatible close: confirms when given a value, dismisses otherwise. */\n close(value?: unknown): boolean {\n return value === undefined ? this.dismiss() : this.confirm(value);\n }\n\n /** Dismiss without a value (X button, backdrop, Escape route here). */\n dismiss(reason?: string): boolean {\n if (this.phase() !== 'open') return false;\n this.finish('dismissed', undefined, reason);\n return true;\n }\n\n /** Explicit cancellation. */\n cancel(reason?: string): boolean {\n if (this.phase() !== 'open') return false;\n this.finish('cancelled', undefined, reason);\n return true;\n }\n\n protected onCloseButton(): void {\n if (this.managed()) {\n if (this.phase() === 'open') this.dismissRequested.emit('button');\n return;\n }\n this.dismiss('close-button');\n }\n\n protected onCancel(event: Event): void {\n if (!this.closeOnEscape()) {\n event.preventDefault();\n return;\n }\n // Native `cancel` already closed nothing yet — route through our pipeline\n // so scroll-lock, focus restore and outputs stay consistent.\n event.preventDefault();\n if (this.managed()) {\n if (this.phase() === 'open') this.dismissRequested.emit('escape');\n return;\n }\n this.dismiss('escape');\n }\n\n protected onBackdropClick(event: MouseEvent): void {\n const el = this.dialog()?.nativeElement;\n if (!el || event.target !== el) return; // inside clicks never count\n if (this.backdrop() !== 'close') return;\n if (this.managed()) {\n if (this.phase() === 'open') this.dismissRequested.emit('backdrop');\n return;\n }\n this.dismiss('backdrop');\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Tab') return;\n const el = this.dialog()?.nativeElement;\n if (!el) return;\n const items = focusables(el);\n if (items.length === 0) {\n event.preventDefault();\n return;\n }\n const first = items[0];\n const last = items[items.length - 1];\n const active = (this.doc ?? document).activeElement;\n if (event.shiftKey && (active === first || !el.contains(active))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n }\n\n private get live(): boolean {\n return typeof window !== 'undefined' && !!this.doc;\n }\n\n private show(): void {\n if (!this.live) return; // SSR: stay closed until client hydration opens us\n const el = this.dialog()?.nativeElement;\n if (!el || this.phase() !== 'closed') return;\n try {\n this.invoker.current = this.doc?.activeElement ?? null;\n } catch {\n this.invoker.current = null;\n }\n this.scrollLock?.acquire();\n this.phase.set('open');\n if (!el.open) {\n try {\n el.showModal();\n } catch {\n // Already open (e.g. double effect run): continue — state is ours.\n }\n }\n focusFirst(el, this.showCloseButton());\n }\n\n private hide(): void {\n if (this.phase() === 'closed') return;\n this.teardown(false);\n }\n\n private finish(\n kind: 'confirmed' | 'dismissed' | 'cancelled',\n value?: unknown,\n reason?: string,\n ): void {\n this.teardown(true);\n if (kind === 'confirmed') this.confirmed.emit(value);\n else if (kind === 'dismissed') this.dismissed.emit(reason);\n else this.cancelled.emit(reason);\n if (this.open()) this.open.set(false);\n }\n\n private teardown(animate: boolean): void {\n if (!animate) {\n if (this.exitTimer) {\n clearTimeout(this.exitTimer);\n this.exitTimer = null;\n }\n this.finalize(this.dialog()?.nativeElement ?? null);\n return;\n }\n this.playExit(() => {});\n }\n\n /** Plays the exit animation (when warranted), then runs `done`. Idempotent. */\n private playExit(done: () => void): void {\n if (this.phase() !== 'open') {\n done();\n return;\n }\n if (this.exitTimer) {\n clearTimeout(this.exitTimer);\n this.exitTimer = null;\n }\n const el = this.dialog()?.nativeElement ?? null;\n const animated = this.animation() !== 'none' && this.prefersMotion() && !!el?.open;\n this.phase.set(animated ? 'closing' : 'closed');\n if (!animated) {\n this.finalize(el);\n done();\n return;\n }\n // Honor consumer-overridden durations instead of a fixed fallback, so a\n // longer `--rv-modal-duration-out` is never cut short.\n this.exitTimer = setTimeout(() => {\n this.finalize(el);\n done();\n }, this.exitDurationMs(el));\n }\n\n private exitDurationMs(el: HTMLDialogElement | null): number {\n try {\n const raw = el ? getComputedStyle(el).animationDuration : '';\n const seconds = raw\n .split(',')\n .map((part) => parseFloat(part))\n .filter((n) => Number.isFinite(n));\n if (seconds.length > 0) return Math.max(0, Math.max(...seconds) * 1000) + 50;\n } catch {\n // Non-CSS environments (tests): fall through to the fallback.\n }\n return EXIT_FALLBACK_MS;\n }\n\n private finalize(el: HTMLDialogElement | null): void {\n this.exitTimer = null;\n try {\n el?.close();\n } catch {\n // Already closed natively — ours to reconcile, not to throw.\n }\n this.phase.set('closed');\n this.scrollLock?.release();\n const invoker = this.invoker.current as HTMLElement | null;\n this.invoker.current = null;\n try {\n invoker?.focus?.();\n } catch {\n // Invoker gone (navigated away) — nothing to restore to.\n }\n }\n\n private prefersMotion(): boolean {\n try {\n return (\n typeof window !== 'undefined' &&\n !window.matchMedia('(prefers-reduced-motion: reduce)').matches\n );\n } catch {\n return true;\n }\n }\n}\n\nlet dialogSeq = 0;\n\nfunction focusables(root: HTMLElement): HTMLElement[] {\n // No visibility filtering on purpose: jsdom reports zero rects (unit\n // tests), and `disabled` is already excluded by the selector. Hidden\n // focusables inside a visible dialog are a consumer edge, not ours.\n const selector =\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), ' +\n 'textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n return Array.from(root.querySelectorAll<HTMLElement>(selector));\n}\n\nfunction focusFirst(dialog: HTMLDialogElement, closeVisible: boolean): void {\n try {\n const auto = dialog.querySelector<HTMLElement>('[autofocus]');\n if (auto) {\n auto.focus({ preventScroll: true });\n return;\n }\n // Atlassian rule: no close button → focus the title; otherwise the\n // dialog itself (its tabindex=\"-1\" makes it focusable).\n if (!closeVisible) {\n const title = dialog.querySelector<HTMLElement>('.rv-modal-title');\n if (title) {\n title.setAttribute('tabindex', '-1');\n title.focus({ preventScroll: true });\n return;\n }\n }\n dialog.focus({ preventScroll: true });\n } catch {\n // Focus is best-effort (e.g. during teardown races).\n }\n}\n","import { Component, Injector, computed, input } from '@angular/core';\nimport type { Signal } from '@angular/core';\nimport { NgComponentOutlet, NgTemplateOutlet } from '@angular/common';\nimport { RIVINIA_MODAL_CONTEXT } from '@rivinia/modal';\nimport type {\n ModalContext,\n ModalDismissOrigin,\n ModalInstance,\n ModalTemplateContext,\n} from '@rivinia/modal';\nimport { RiviniaModalDialog } from './modal-dialog';\nimport type { RiviniaModalSize } from './ui-types';\n\n/**\n * Managed adapter: renders every `visible()` instance of the headless\n * `RiviniaModal` inside a {@link RiviniaModalDialog} and routes all UI\n * intents through the manager first (guards run; results settle in Core —\n * the single source of truth). The dialog never settles anything itself in\n * this mode; listen to `ModalHandle.result`, not dialog outputs.\n *\n * Exit coordination: when Core reports an instance `closing`, the dialog\n * plays its exit animation and the host acknowledges with `confirmClosed()`\n * (idempotent — safe if `closingTimeout` auto-finalized first). Match\n * `closingTimeout` to the animation duration so exits stay visible.\n *\n * Title resolution: `titleOf` per instance (default: `metadata.title` →\n * `ref` → `''`). Content descriptors render as-is: templates via\n * `ngTemplateOutlet` with `{$implicit: data, modal}`, components via\n * `NgComponentOutlet` with `inputs` + a per-instance\n * `RIVINIA_MODAL_CONTEXT` injector (the lab-proven pattern).\n *\n * The manager arrives via `[modal]` input (D06 input-composition: the UI\n * entry never instantiates Core itself, so UI-only consumers pay nothing).\n * The input is typed as {@link RiviniaModalHostManager} — the structural\n * slice the host actually drives — so the full manager (or a test double)\n * satisfies it from any module realm:\n *\n * ```html\n * <rv-modal-host [modal]=\"injectRiviniaModal()\" />\n * ```\n */\nexport interface RiviniaModalHostManager {\n readonly visible: Signal<readonly ModalInstance<unknown>[]>;\n requestDismiss(id: string, origin: ModalDismissOrigin): Promise<boolean>;\n confirmClosed(id: string): boolean;\n close(id: string, value?: unknown): boolean;\n dismiss(id: string, reason?: string): boolean;\n}\n\n@Component({\n selector: 'rv-modal-host',\n standalone: true,\n imports: [RiviniaModalDialog, NgComponentOutlet, NgTemplateOutlet],\n template: `\n @for (instance of visible(); track instance.id) {\n <rv-modal-dialog\n [open]=\"true\"\n [managed]=\"true\"\n [closing]=\"instance.status === 'closing'\"\n [title]=\"titleOfInstance(instance)\"\n [size]=\"size()\"\n [showCloseButton]=\"showCloseButton()\"\n [closeOnEscape]=\"instance.dismiss.closeOnEscape ?? true\"\n [backdrop]=\"instance.dismiss.backdrop ?? 'close'\"\n (dismissRequested)=\"onIntent(instance.id, $event)\"\n (exitDone)=\"onExitDone(instance.id)\"\n >\n @if (instance.content.kind === 'template') {\n <ng-container\n *ngTemplateOutlet=\"instance.content.template; context: templateContext(instance)\"\n ></ng-container>\n } @else {\n <ng-container\n *ngComponentOutlet=\"\n instance.content.component;\n inputs: instance.content.inputs;\n injector: contextInjector(instance)\n \"\n ></ng-container>\n }\n </rv-modal-dialog>\n }\n `,\n})\nexport class RiviniaModalHost {\n /**\n * The headless manager to render. Typed as {@link RiviniaModalHostManager}\n * (structural) — pass `injectRiviniaModal()` from your app code.\n */\n readonly modal = input.required<RiviniaModalHostManager>();\n\n /** Dialog size for every managed instance. @default 'md' */\n readonly size = input<RiviniaModalSize>('md');\n /** Render the header close button on every managed instance. @default true */\n readonly showCloseButton = input<boolean>(true);\n /** Resolve a title per instance. Default: `metadata.title` → `ref` → `''`. */\n readonly titleOf = input<(instance: ModalInstance<unknown>) => string | undefined>();\n\n protected readonly visible = computed(() => this.modal().visible());\n\n protected titleOfInstance(instance: ModalInstance<unknown>): string {\n try {\n const custom = this.titleOf()?.(instance);\n if (custom !== undefined) return custom;\n } catch {\n // A throwing resolver must never break rendering — fall through.\n }\n const meta = instance.metadata?.['title'];\n if (typeof meta === 'string' && meta.length > 0) return meta;\n return instance.ref ?? '';\n }\n\n protected templateContext(instance: ModalInstance<unknown>): ModalTemplateContext<unknown> {\n return { $implicit: instance.data, modal: this.modalContext(instance) };\n }\n\n protected contextInjector(instance: ModalInstance<unknown>): Injector {\n const modal = this.modal();\n return Injector.create({\n providers: [\n {\n provide: RIVINIA_MODAL_CONTEXT,\n useValue: {\n id: instance.id,\n data: instance.data,\n parentId: instance.parentId,\n close: (result?: unknown) => modal.close(instance.id, result),\n dismiss: (reason?: string) => modal.dismiss(instance.id, reason),\n } satisfies ModalContext<unknown>,\n },\n ],\n });\n }\n\n protected async onIntent(id: string, origin: 'button' | 'escape' | 'backdrop'): Promise<void> {\n try {\n await this.modal().requestDismiss(id, origin);\n } catch {\n // requestDismiss never rejects (deny-safe by contract) — defensive only.\n }\n // Granted → status flips to `closing` → dialog exit → `exitDone`.\n // Denied → nothing moves; the dialog never left `open`. No manual toggle.\n }\n\n protected onExitDone(id: string): void {\n this.modal().confirmClosed(id);\n }\n\n private modalContext(instance: ModalInstance<unknown>): ModalContext<unknown> {\n const modal = this.modal();\n const id = instance.id;\n return {\n id,\n data: instance.data,\n parentId: instance.parentId,\n close: (result?: unknown) => modal.close(id, result),\n dismiss: (reason?: string) => modal.dismiss(id, reason),\n };\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rivinia/modal",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Headless modal manager for Angular: stack/queue strategies, typed results, guards, ownership.",
5
5
  "keywords": [
6
6
  "angular",
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "license": "MIT",
13
13
  "peerDependencies": {
14
+ "@angular/common": "^22.0.0",
14
15
  "@angular/core": "^22.0.0"
15
16
  },
16
17
  "sideEffects": false,