@rivinia/modal 0.4.0 → 0.5.0

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
@@ -8,7 +8,7 @@ Headless modal manager for Angular 22+. Stack/Queue strategies, typed
8
8
  zero styles, zero router dependency. A future `@rivinia/modal/ui` entry point
9
9
  will render this state; Core never imports UI.
10
10
 
11
- - Version: **0.4.0**
11
+ - Version: **0.5.0**
12
12
  - Requires: **Angular `^22.0.0`**, `tslib`
13
13
 
14
14
  ## Install
@@ -86,6 +86,86 @@ Closing a parent cascades to descendants (`dismissed: parent-closed`) unless
86
86
  `descendants: 'prevent-parent-close'` blocks it. Swapping strategies with live
87
87
  modals throws — close everything first.
88
88
 
89
+ ## Ready-made UI (`@rivinia/modal/ui`)
90
+
91
+ Optional secondary entry point. Zero new runtime dependencies (platform
92
+ `<dialog>` + Angular only), no design system, no CSS framework. Headless
93
+ consumers never load it (proven: core FESM contains zero UI markers).
94
+
95
+ ```ts
96
+ import { RiviniaModalDialog } from '@rivinia/modal/ui'; // UI-only
97
+ import { RiviniaModalHost } from '@rivinia/modal/ui'; // managed adapter
98
+ ```
99
+
100
+ **Mode A — UI-only** (no controller; owns its `open` state):
101
+
102
+ ```html
103
+ <rv-modal-dialog [(open)]="open" [title]="'Delete?'" [size]="'sm'" (confirmed)="remove()">
104
+ <p>Delete {{ user.name }}?</p>
105
+ </rv-modal-dialog>
106
+ ```
107
+
108
+ **Mode B — headless + custom UI:** keep using `@rivinia/modal` alone.
109
+ Nothing here loads, no styles leak.
110
+
111
+ **Mode C — headless + ready-made UI** (single source of truth stays Core):
112
+
113
+ ```html
114
+ <rv-modal-host [modal]="injectRiviniaModal()" />
115
+ ```
116
+
117
+ Intents (X, Escape, backdrop) route through `requestDismiss` (guards run);
118
+ exits play, then the host calls `confirmClosed()` (match `closingTimeout`
119
+ to the animation duration; default 300 ms covers the 150 ms default).
120
+
121
+ Custom chrome (no X button, custom header/footer, own actions in content):
122
+
123
+ ```html
124
+ <rv-modal-dialog [(open)]="open">
125
+ <div rv-modal-header rvModalHeader>My header, no X</div>
126
+ <p>Body.</p>
127
+ <div rv-modal-footer rvModalFooter><button (click)="save()">Save</button></div>
128
+ </rv-modal-dialog>
129
+ ```
130
+
131
+ No header at all: omit the title (no custom header either). Header rules:
132
+ title + optional `description` (wired as `aria-describedby`), top-aligned
133
+ with a shrink-proof X; an empty heading collapses (no dead space); a custom
134
+ header renders inside the same padded row. Focus goes to the title when
135
+ there is no close button, to the dialog otherwise. No footer:
136
+ omit the footer slot (renders nothing). Positions: `center` (default),
137
+ `top/bottom`, `-start/-end` variants (RTL-aware), `side-start/side-end`
138
+ full-height panels, `fullscreen`. Under 640px viewports, center/top/bottom
139
+ shapes become bottom sheets automatically (top-only radius, slide-up
140
+ entrance); panels and fullscreen keep their shape.
141
+ Sizes `sm/md/lg/xl/full/auto` are ceilings via `--rv-modal-width-*` vars.
142
+
143
+ Theming (no theme service; consumer owns it):
144
+
145
+ ```css
146
+ :root {
147
+ --rv-modal-bg: #1c1c1e;
148
+ --rv-modal-fg: #f5f5f7;
149
+ }
150
+ @media (prefers-color-scheme: dark) {
151
+ .rv-modal {
152
+ /* built-in dark defaults already apply; override vars to brand it */
153
+ }
154
+ }
155
+ ```
156
+
157
+ Plus: `prefers-reduced-motion` disables animation; `animation: 'none'`
158
+ opt-out; `backdrop: 'close' | 'static' | 'disabled'`; Escape/backdrop/X
159
+ policies stay independent (no `disableClose` bundle); long content scrolls
160
+ inside (`rv-modal-body`); `scrollbar-gutter: stable` while open;
161
+ reference-counted scroll lock restores previous styles; focus trap + focus
162
+ restore + `aria-labelledby`/`aria-label`; `dir=rtl` works via logical
163
+ properties; SSR renders closed and opens after hydration; lazy-load the
164
+ entry (`loadComponent`) to split it into its own chunk (~16.7 kB raw,
165
+ ~4.9 kB transfer, measured). Toasts: MEASURED (Chrome, `elementFromPoint`) —
166
+ neither a high `z-index` nor `popover="manual"` paints above an open modal
167
+ dialog; toasts queue behind it. No modal→toast dependency by design.
168
+
89
169
  ## Type holes (honest, by design)
90
170
 
91
171
  Core checks `ModalHandle<TResult>.close(result?: TResult)` and