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 ───────── /* ───────── Print — only the page, no toolbar / dialog chrome ─────────
This dialog is opened with `maxHeight: '92vh'`, which Angular Material carries onto the The document-level clip (`html, body { overflow: hidden }`) is lifted globally in main.scss's
overlay pane / .mat-mdc-dialog-container as an inline max-height + overflow:auto clip. print block; what remains here is this dialog's own clip — it opens with `maxHeight: '92vh'`,
`position: absolute` still lives inside that clip and gets cut off — only the on-screen which Angular Material carries onto the overlay pane / .mat-mdc-dialog-container as an inline
scroll position prints. `position: fixed` escapes it: a fixed element's containing block is max-height plus overflow:auto. Freeing those lets the whole certificate flow onto the page in
the viewport itself, not the clipped ancestor (the classic "fixed child ignores an normal static order (a fixed/absolute hack would pin it to the first page instead). */
overflow:hidden parent" behaviour), as long as nothing between here and the viewport sets a
transform/filter — the CDK overlay chrome doesn't. */
@media print { @media print {
body > :not(.cdk-overlay-container) { body > :not(.cdk-overlay-container) {
display: none !important; display: none !important;
@@ -611,9 +609,7 @@
} }
.cpd-root { .cpd-root {
position: fixed; position: static;
left: 0;
top: 0;
width: 100% !important; width: 100% !important;
height: auto !important; height: auto !important;
background: #fff; background: #fff;
@@ -384,18 +384,59 @@
/* Print CSS */ /* Print CSS */
@media print { @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) { body > :not(.cdk-overlay-container) {
display: none !important; 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 */ /* Make certificate fill page */
#share-certificate-print { #share-certificate-print {
position: absolute; position: static !important;
left: 0;
top: 0;
width: 100% !important; width: 100% !important;
height: 100% !important; height: auto !important;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;
background-color: #fff !important; background-color: #fff !important;
@@ -411,7 +452,135 @@
display: none !important; display: none !important;
} }
.mat-mdc-dialog-container { ::ng-deep .mat-mdc-dialog-container {
padding: 0 !important; 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-mdc-tab-header,
.mat-stepper-vertical-line, .mat-stepper-vertical-line,
.mat-step-header, .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 /* 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 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. */ inside <mifosx-toolbar> — hiding only the toolbar left this menu printing on every page. */
@@ -997,17 +1007,57 @@ mat-card {
margin-left: 0 !important; margin-left: 0 !important;
} }
/* The whole app shell scrolls inside CDK's own clipped viewport — /* THE root clip: assets/styles/_overflow.scss sets `html, body { overflow: hidden }` and
.mat-drawer-container { overflow: hidden } and .mat-drawer-content { overflow: auto; height: 100% } index.html puts `h-full` (height: 100%) on both, so the document itself is locked to exactly
— so without freeing these too, print is still capped to one screen's worth of the page one viewport and everything past it is cut away. Every inner container fix below is useless
regardless of the tab-body fix below. */ 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, #mifosx-shell-container,
mat-sidenav-container,
mat-drawer-container,
mat-sidenav-content,
mat-drawer-content,
.mat-drawer-container, .mat-drawer-container,
.mat-drawer-content, .mat-drawer-content,
mat-sidenav-content.sidenav { .mat-sidenav-content {
position: static !important;
overflow: visible !important; overflow: visible !important;
height: auto !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 /* Angular Material clips a tab's content to a JS-measured on-screen height via
@@ -1023,11 +1073,6 @@ mat-card {
height: auto !important; height: auto !important;
} }
body,
html {
background: #fff !important;
}
@page { @page {
/* stylelint-disable-next-line unit-allowed-list */ /* stylelint-disable-next-line unit-allowed-list */
margin: 1.5cm; margin: 1.5cm;
@@ -1869,3 +1914,49 @@ mifosx-client-datatable-step * {
--mdc-checkbox-selected-pressed-icon-color: #059669; --mdc-checkbox-selected-pressed-icon-color: #059669;
} }
/* stylelint-enable selector-max-universal */ /* 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;
}
}