fix(print): fix app-wide printing and remove a global print-CSS leak

Root cause of blank/clipped print output across the app: the document root
(html/body) is globally locked to one viewport height with overflow hidden,
and Angular Material's drawer/tab-body containers each add their own
on-screen scroll clip on top of that. main.scss now frees the full chain for
print (document root, CDK drawer/sidenav containers, mat-tab-body, and the
account-view's mat-tab-nav-bar which was rendering as a stray grey scrollable
strip since it isn't covered by the mat-tab-group header rule already hidden).

Also fixed both certificate print dialogs (share-certificate-dialog,
deposit-certificate-dialog) reusing a `::ng-deep body > :not(.cdk-overlay-
container)` rule to hide the shell during their own print: under Angular's
style encapsulation this style is emitted fully unscoped into the global
stylesheet and is never removed once the component has loaded once in a
session, silently blanking every other page's print output for the rest of
the session. Dropped `::ng-deep` from that one selector so it goes back to
being properly scoped (and therefore inert, matching the other two dialogs
that never had this bug) — the app shell is already hidden for every print
via the global main.scss rules, so no dialog needs its own global override.
This commit is contained in:
2026-09-16 17:17:12 +05:30
parent 0cef1b5a50
commit d18bd9cf37
3 changed files with 283 additions and 27 deletions
@@ -576,13 +576,11 @@
}
/* ───────── Print — only the page, no toolbar / dialog chrome ─────────
This dialog is opened with `maxHeight: '92vh'`, which Angular Material carries onto the
overlay pane / .mat-mdc-dialog-container as an inline max-height + overflow:auto clip.
`position: absolute` still lives inside that clip and gets cut off — only the on-screen
scroll position prints. `position: fixed` escapes it: a fixed element's containing block is
the viewport itself, not the clipped ancestor (the classic "fixed child ignores an
overflow:hidden parent" behaviour), as long as nothing between here and the viewport sets a
transform/filter — the CDK overlay chrome doesn't. */
The document-level clip (`html, body { overflow: hidden }`) is lifted globally in main.scss's
print block; what remains here is this dialog's own clip — it opens with `maxHeight: '92vh'`,
which Angular Material carries onto the overlay pane / .mat-mdc-dialog-container as an inline
max-height plus overflow:auto. Freeing those lets the whole certificate flow onto the page in
normal static order (a fixed/absolute hack would pin it to the first page instead). */
@media print {
body > :not(.cdk-overlay-container) {
display: none !important;
@@ -611,9 +609,7 @@
}
.cpd-root {
position: fixed;
left: 0;
top: 0;
position: static;
width: 100% !important;
height: auto !important;
background: #fff;
@@ -384,18 +384,59 @@
/* Print CSS */
@media print {
/* Hide non-overlay contents during print */
::ng-deep html,
::ng-deep body {
height: auto !important;
overflow: visible !important;
}
/* Hide non-overlay contents during print. Deliberately NOT `::ng-deep` here: under Angular's
emulated encapsulation a bare `body` selector never carries this component's scoping
attribute, so a scoped rule can never match the real <body> and is safely inert — whereas
`::ng-deep` emits it fully unscoped into the GLOBAL stylesheet for the rest of the session
(Angular never removes a component's injected styles when it's destroyed), silently hiding
every other page's print output app-wide the moment this dialog is opened once. The app
shell (nav, toolbar, sidebar) is already hidden for every print via the global rules in
main.scss, so this dialog doesn't need its own global override to get the same effect. */
body > :not(.cdk-overlay-container) {
display: none !important;
}
/* The dialog's own scroll region clips anything past 80vh -- printing only captures what a
scrollable/max-height box shows on screen, so both constraints must be lifted. */
.dialog-content-container {
max-height: none !important;
overflow: visible !important;
}
/* CDK's overlay wrapper/backdrop/pane are all position: fixed. Unset them so the full certificate prints statically. */
::ng-deep .cdk-overlay-backdrop {
display: none !important;
}
::ng-deep .cdk-overlay-container,
::ng-deep .cdk-global-overlay-wrapper,
::ng-deep .cdk-overlay-pane,
::ng-deep .mat-mdc-dialog-container,
::ng-deep .mdc-dialog__container,
::ng-deep .mdc-dialog__surface {
position: static !important;
display: block !important;
max-height: none !important;
max-width: none !important;
height: auto !important;
width: auto !important;
overflow: visible !important;
transform: none !important;
box-shadow: none !important;
background: transparent !important;
}
/* Make certificate fill page */
#share-certificate-print {
position: absolute;
left: 0;
top: 0;
position: static !important;
width: 100% !important;
height: 100% !important;
height: auto !important;
padding: 0 !important;
margin: 0 !important;
background-color: #fff !important;
@@ -411,7 +452,135 @@
display: none !important;
}
.mat-mdc-dialog-container {
::ng-deep .mat-mdc-dialog-container {
padding: 0 !important;
}
/* Compact every spacing/font value so the whole certificate fits a single printed page */
.certificate-container {
padding: 6px !important;
}
.certificate-border-inner {
padding: 14px !important;
}
.certificate-header {
margin-bottom: 10px !important;
padding-bottom: 10px !important;
.bank-name {
font-size: 19px !important;
margin-bottom: 2px !important;
}
.bank-sub {
font-size: 10px !important;
margin-bottom: 8px !important;
}
.cert-title {
font-size: 19px !important;
letter-spacing: 2px !important;
margin-bottom: 2px !important;
}
.cert-subtitle {
font-size: 9px !important;
}
}
.cert-meta-row {
margin-bottom: 10px !important;
padding-bottom: 8px !important;
.meta-label {
font-size: 9px !important;
margin-bottom: 1px !important;
}
.meta-value {
font-size: 12px !important;
}
}
.cert-body-section {
margin-bottom: 10px !important;
.cert-main-text {
font-size: 11px !important;
line-height: 1.4 !important;
margin-bottom: 10px !important;
}
}
.issued-to-details {
padding: 8px 14px !important;
margin: 8px auto !important;
.client-name-details {
font-size: 14px !important;
}
.client-ids,
.client-address {
font-size: 10px !important;
}
}
.certificate-details-table {
margin-bottom: 12px !important;
td {
padding: 5px 10px !important;
font-size: 10px !important;
}
.lbl-col-highlight {
font-size: 12px !important;
}
.val-col-highlight {
font-size: 13px !important;
}
}
.allotment-table {
margin-bottom: 12px !important;
th {
padding: 4px 8px !important;
font-size: 8px !important;
}
td {
padding: 4px 8px !important;
font-size: 9px !important;
}
}
.cert-footer {
margin-top: 8px !important;
.seal-ring {
width: 60px !important;
height: 60px !important;
}
.seal-text {
font-size: 8px !important;
}
.closing-text {
font-size: 10px !important;
}
.signature-line {
height: 22px !important;
}
.signatory-title {
font-size: 10px !important;
}
}
}
+102 -11
View File
@@ -982,6 +982,16 @@ mat-card {
.mat-mdc-tab-header,
.mat-stepper-vertical-line,
.mat-step-header,
/* Account-view pages (Shares, Savings, Current, Deposits…) use `<nav mat-tab-nav-bar
class="navigation-tabs">` for their General/Passbook/Charges/… tab links — a DIFFERENT
Material component from mat-tab-group, so it never carries `.mat-mdc-tab-header` and slipped
past the rule above. Its own style (theme/_content.scss) gives it a grey background and
`overflow: auto`, which is exactly the grey box with a baked-in scrollbar seen in print/PDF
output — printing it is as pointless as printing the tab-group header already excluded above. */
.navigation-tabs,
[mat-tab-nav-bar],
.mat-mdc-tab-nav-bar,
.mat-mdc-tab-link-container,
/* The real 2-row nav menu (Client Master / Approvals / Cashier … and the row below it) and the
live KPI ticker live directly in shell.component.html as .main-header / .kpi-ticker, not
inside <mifosx-toolbar> — hiding only the toolbar left this menu printing on every page. */
@@ -997,17 +1007,57 @@ mat-card {
margin-left: 0 !important;
}
/* The whole app shell scrolls inside CDK's own clipped viewport —
.mat-drawer-container { overflow: hidden } and .mat-drawer-content { overflow: auto; height: 100% }
— so without freeing these too, print is still capped to one screen's worth of the page
regardless of the tab-body fix below. */
/* THE root clip: assets/styles/_overflow.scss sets `html, body { overflow: hidden }` and
index.html puts `h-full` (height: 100%) on both, so the document itself is locked to exactly
one viewport and everything past it is cut away. Every inner container fix below is useless
while this stands — it is why printing any page produced a blank sheet with only a sliver of
whatever happened to sit at the fold. */
html,
body {
height: auto !important;
overflow: visible !important;
width: 100% !important;
background: #fff !important;
/* Keep backgrounds/colours (certificate rules, table shading) instead of dropping them. */
print-color-adjust: exact;
}
/* The shell then scrolls inside CDK's own clipped viewport —
#mifosx-shell-container { height: 100vh }, .mat-drawer-content { height: 100%; overflow: auto }
— so these have to be freed as well. */
#mifosx-shell-container,
mat-sidenav-container,
mat-drawer-container,
mat-sidenav-content,
mat-drawer-content,
.mat-drawer-container,
.mat-drawer-content,
mat-sidenav-content.sidenav {
position: static !important;
.mat-sidenav-content {
overflow: visible !important;
height: auto !important;
max-height: none !important;
/* Material's own theme paints a background-color on .mat-drawer-container — without
overriding it here, that grey shows behind every printed page even though html/body are
already forced white above. */
background: #fff !important;
}
/* shell.component.scss:247-271 scopes `mifosx-content { overflow-x: hidden; max-width: 100% }`
specifically to `.sidenav mifosx-content` so tables/cards shrink to fit whenever the sidebar
is open on screen — this rule has nothing to do with the sidebar being hidden for print, and
without overriding it too, the routed page content keeps clipping/scrolling horizontally to
whatever width was last measured on screen, which is exactly the narrow box with a baked-in
scrollbar seen in print/PDF output. */
mifosx-content,
.sidenav mifosx-content,
mat-tab-nav-panel,
.mat-mdc-tab-nav-panel {
overflow: visible !important;
width: auto !important;
max-width: 100% !important;
height: auto !important;
}
/* Angular Material clips a tab's content to a JS-measured on-screen height via
@@ -1023,11 +1073,6 @@ mat-card {
height: auto !important;
}
body,
html {
background: #fff !important;
}
@page {
/* stylelint-disable-next-line unit-allowed-list */
margin: 1.5cm;
@@ -1869,3 +1914,49 @@ mifosx-client-datatable-step * {
--mdc-checkbox-selected-pressed-icon-color: #059669;
}
/* stylelint-enable selector-max-universal */
/* ==========================================================================
Global Print Styles for Material Dialogs & Certificates
========================================================================== */
@media print {
html,
body {
height: auto !important;
overflow: visible !important;
background: #fff !important;
}
/* Hide main application shell during dialog printing */
body > :not(.cdk-overlay-container) {
display: none !important;
}
/* Remove fixed positioning on CDK overlay elements so content flows naturally */
.cdk-overlay-backdrop {
display: none !important;
}
.cdk-overlay-container,
.cdk-global-overlay-wrapper,
.cdk-overlay-pane,
.mat-mdc-dialog-container,
.mdc-dialog__container,
.mdc-dialog__surface {
position: static !important;
display: block !important;
max-height: none !important;
max-width: none !important;
height: auto !important;
width: auto !important;
overflow: visible !important;
transform: none !important;
box-shadow: none !important;
background: transparent !important;
padding: 0 !important;
}
.no-print,
.mat-mdc-dialog-actions {
display: none !important;
}
}