From b56d56e5f2275bacb6af4354cbd5346fefcd61f2 Mon Sep 17 00:00:00 2001 From: desig9stein Date: Wed, 8 Jul 2026 17:58:30 +0300 Subject: [PATCH 1/3] feat(samples): add sample-size reporter for auto-fitting docs iframes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Demos on the docs site render inside cross-origin iframes. By default styles.scss pins html/body to height:100% + overflow:hidden, so an iframe can only ever echo its own height back — it can't grow to fit its content. This adds the demo-side half of a small postMessage handshake with the docs host (astro-components' sample-widget) so samples that opt into fitContent size themselves to their actual content. How it works: - the host posts { type: 'igd-sample-fit', width? } into the iframe on load; until that arrives the reporter stays completely dormant, so fixed-height demos and their percentage layouts are untouched - on enable, it injects a one-time stylesheet that releases the viewport pin (height:auto, overflow:visible) and reports content size back with { type: 'igd-sample-height', height, width? } immediately and on every resize (via ResizeObserver) - width is measured from the right-most element edge rather than the body box, mirroring the host's same-origin measurement, and is only computed when the host asks for it Notes: - no-ops outside an iframe (window.parent === window) and when there is no window (SSR/prerender) - replies target the host's captured origin instead of broadcasting to '*', and only ever emit layout dimensions - shared across all three Angular apps (src, app-crm, app-lob) via the "@shared/sample-size-reporter" tsconfig path alias so there is a single source of truth --- projects/app-crm/src/main.ts | 3 + .../src/app/index/docs-layout.component.scss | 7 +- projects/app-lob/src/main.ts | 3 + src/app/index/docs-layout.component.scss | 7 +- .../interactions/toggle/toggle-samples.scss | 11 +-- .../layouts/avatar/avatar-styling/layout.scss | 15 +--- src/main.ts | 3 + src/sample-size-reporter.ts | 79 +++++++++++++++++++ tsconfig.json | 3 + 9 files changed, 97 insertions(+), 34 deletions(-) create mode 100644 src/sample-size-reporter.ts diff --git a/projects/app-crm/src/main.ts b/projects/app-crm/src/main.ts index 06acb33cdc..e88e5798b3 100644 --- a/projects/app-crm/src/main.ts +++ b/projects/app-crm/src/main.ts @@ -3,9 +3,12 @@ import { environment } from './environments/environment'; import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { AppConfig } from './app/app.config'; +import { initSampleSizeReporter } from '@shared/sample-size-reporter'; if (environment.production) { enableProdMode(); } +initSampleSizeReporter(); + bootstrapApplication(AppComponent, AppConfig).catch((err) => console.error(err)); diff --git a/projects/app-lob/src/app/index/docs-layout.component.scss b/projects/app-lob/src/app/index/docs-layout.component.scss index cf86a1df88..8b13789179 100644 --- a/projects/app-lob/src/app/index/docs-layout.component.scss +++ b/projects/app-lob/src/app/index/docs-layout.component.scss @@ -1,6 +1 @@ -::ng-deep { - .custom-body { - color: var(--ig-surface-500-contrast); - background: var(--ig-surface-500); - } -} + diff --git a/projects/app-lob/src/main.ts b/projects/app-lob/src/main.ts index 785d0e1bc9..131aff4bbb 100644 --- a/projects/app-lob/src/main.ts +++ b/projects/app-lob/src/main.ts @@ -6,11 +6,14 @@ import { environment } from './environments/environment'; import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { AppConfig } from './app/app.config'; +import { initSampleSizeReporter } from '@shared/sample-size-reporter'; if (environment.production) { enableProdMode(); } +initSampleSizeReporter(); + bootstrapApplication(AppComponent, AppConfig).catch(err => console.error(err)); defineCustomElements(window); diff --git a/src/app/index/docs-layout.component.scss b/src/app/index/docs-layout.component.scss index cf86a1df88..8b13789179 100644 --- a/src/app/index/docs-layout.component.scss +++ b/src/app/index/docs-layout.component.scss @@ -1,6 +1 @@ -::ng-deep { - .custom-body { - color: var(--ig-surface-500-contrast); - background: var(--ig-surface-500); - } -} + diff --git a/src/app/interactions/toggle/toggle-samples.scss b/src/app/interactions/toggle/toggle-samples.scss index 38afa50748..e7c518d3d2 100644 --- a/src/app/interactions/toggle/toggle-samples.scss +++ b/src/app/interactions/toggle/toggle-samples.scss @@ -9,7 +9,7 @@ height: 260px; } -.toggle-section{ +.toggle-section { flex-flow: row wrap; display: flex; width: 100%; @@ -18,15 +18,6 @@ align-items: center; text-align: center; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); - - .dark-theme & { - background-color: #111; - } - - .custom-body & { - color: var(--ig-surface-500-contrast); - background-color: var(--ig-surface-500); - } } img{ diff --git a/src/app/layouts/avatar/avatar-styling/layout.scss b/src/app/layouts/avatar/avatar-styling/layout.scss index 19e8de55dd..d3a4208499 100644 --- a/src/app/layouts/avatar/avatar-styling/layout.scss +++ b/src/app/layouts/avatar/avatar-styling/layout.scss @@ -1,13 +1,4 @@ -.avatars-wrapper { - display: flex; - flex-flow: row wrap; -} - -.avatar-sample { - display: flex; - flex: 1 0 30%; - width: 88px; - justify-content: center; - align-items: center; - margin: 15px 0; +:host { + display: inline-flex; + gap: 32px } diff --git a/src/main.ts b/src/main.ts index fcc3112d63..9a1b0b91ea 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,11 +4,14 @@ import { defineCustomElements } from 'igniteui-dockmanager/loader'; import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; import { AppConfig } from './app/app.config'; +import { initSampleSizeReporter } from '@shared/sample-size-reporter'; if (environment.production) { enableProdMode(); } +initSampleSizeReporter(); + bootstrapApplication(AppComponent, AppConfig).catch(err => console.log(err)); defineCustomElements(window); diff --git a/src/sample-size-reporter.ts b/src/sample-size-reporter.ts new file mode 100644 index 0000000000..f9c666d28c --- /dev/null +++ b/src/sample-size-reporter.ts @@ -0,0 +1,79 @@ +/** + * Demo-side half of the docs contract + * (astro-components/src/scripts/sample-widget.ts). + * + * The docs host posts { type: 'igd-sample-fit', width?: boolean } into the + * iframe when it loads. In response we neutralize the viewport-bound sizing + * from styles.scss (html/body height: 100%, overflow: hidden — which would + * only echo the iframe's height back) and report the content's size with + * { type: 'igd-sample-height', height, width? } immediately and on every + * resize. Demos embedded at a fixed height never receive the enable message, + * so this stays dormant for them and their percentage layouts are untouched. + */ +const FIT_ENABLE = 'igd-sample-fit'; +const FIT_REPORT = 'igd-sample-height'; + +export function initSampleSizeReporter(): void { + if (typeof window === 'undefined' || window.parent === window) { + return; + } + + let reportWidth = false; + let observer: ResizeObserver | null = null; + let styled = false; + // Captured from the host's enable message so replies go back to that exact + // origin instead of being broadcast to any window that happens to listen. + let hostOrigin = '*'; + + // Right-most element edge, mirroring the host's same-origin measurement: + // block-level content stretches to the viewport width, so the intrinsic + // width has to come from the element boxes, not the body itself. + const measureWidth = (): number | undefined => { + const body = document.body; + const left = body.getBoundingClientRect().left; + let right = left; + body.querySelectorAll('*').forEach(el => { + right = Math.max(right, el.getBoundingClientRect().right); + }); + if (right <= left) { + return undefined; + } + const cs = getComputedStyle(body); + return right - left + parseFloat(cs.paddingRight || '0') + parseFloat(cs.borderRightWidth || '0'); + }; + + const report = () => { + const height = Math.max( + document.documentElement.offsetHeight, + document.body.offsetHeight, + document.body.scrollHeight, + ); + window.parent.postMessage( + { type: FIT_REPORT, height, width: reportWidth ? measureWidth() : undefined }, + hostOrigin, + ); + }; + + window.addEventListener('message', (e: MessageEvent) => { + if (!e.data || e.data.type !== FIT_ENABLE) { + return; + } + reportWidth = Boolean(e.data.width); + hostOrigin = e.origin || '*'; + + if (!styled) { + styled = true; + const style = document.createElement('style'); + style.textContent = + 'html, body { height: auto !important; overflow: visible !important; }' + + '.sample-wrapper { height: auto !important; }'; + document.head.appendChild(style); + } + + report(); + if ('ResizeObserver' in window && !observer) { + observer = new ResizeObserver(report); + observer.observe(document.body); + } + }); +} diff --git a/tsconfig.json b/tsconfig.json index a9f83e075c..a576502869 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,9 @@ { "compileOnSave": false, "compilerOptions": { + "paths": { + "@shared/sample-size-reporter": ["./src/sample-size-reporter.ts"] + }, "importHelpers": true, "module": "ES2022", "outDir": "./dist/out-tsc", From 6d0d9cb5cefd6ca07bb60335fc22f56e4dd96a32 Mon Sep 17 00:00:00 2001 From: desig9stein Date: Thu, 9 Jul 2026 10:55:22 +0300 Subject: [PATCH 2/3] fix(sample-size-reporter): validate message origin --- src/sample-size-reporter.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/sample-size-reporter.ts b/src/sample-size-reporter.ts index f9c666d28c..27a136cfb4 100644 --- a/src/sample-size-reporter.ts +++ b/src/sample-size-reporter.ts @@ -55,11 +55,17 @@ export function initSampleSizeReporter(): void { }; window.addEventListener('message', (e: MessageEvent) => { + if (e.source !== window.parent) { + return; + } + if (!e.origin || !/^https?:\/\//.test(e.origin)) { + return; + } if (!e.data || e.data.type !== FIT_ENABLE) { return; } reportWidth = Boolean(e.data.width); - hostOrigin = e.origin || '*'; + hostOrigin = e.origin; if (!styled) { styled = true; From 0ae2365cd86a7bfa66c6899582dc7643413ebb22 Mon Sep 17 00:00:00 2001 From: desig9stein Date: Thu, 9 Jul 2026 11:50:21 +0300 Subject: [PATCH 3/3] fix(sample-size-reporter): remove trailing commas in postMessage parameters --- src/sample-size-reporter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sample-size-reporter.ts b/src/sample-size-reporter.ts index 27a136cfb4..bef1d1f376 100644 --- a/src/sample-size-reporter.ts +++ b/src/sample-size-reporter.ts @@ -46,11 +46,11 @@ export function initSampleSizeReporter(): void { const height = Math.max( document.documentElement.offsetHeight, document.body.offsetHeight, - document.body.scrollHeight, + document.body.scrollHeight ); window.parent.postMessage( { type: FIT_REPORT, height, width: reportWidth ? measureWidth() : undefined }, - hostOrigin, + hostOrigin ); };