Skip to content

Commit 48b41d2

Browse files
authored
Merge pull request #38 from shellui-dev/fix/iframe-preview-navigation
fix: IframePreview keeps the previous page's preview after navigation (0.1.16-alpha)
2 parents 04e1c04 + 0e5eaa6 commit 48b41d2

6 files changed

Lines changed: 46 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to ShellDocs land here. Format follows [Keep a Changelog](ht
44

55
## [Unreleased]
66

7+
## [0.1.16-alpha] — 2026-10-14
8+
9+
Fixes `<IframePreview>` showing the previous page's preview after navigating within a site.
10+
11+
### Fixed
12+
13+
- **`<IframePreview>` after in-site navigation.** When the next page has an iframe preview in the same place, Blazor reuses the element and only changes its `data-src`. `shelldocs.js` kept treating it as loaded, so the frame went on showing the previous page's preview and the Run button stayed hidden. It now watches `data-src` and `data-lazy`, unloads a host whose values change, and sets it up again: the Run button comes back for `Lazy="click"`, and `visible` / `none` previews load the new page. Sites that worked around it with their own `MutationObserver` can drop it.
14+
715
## [0.1.15-alpha] — 2026-10-11
816

917
Search now works in static exports, the last piece of chrome that needed a running Blazor app.

‎Directory.Build.props‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<!-- Package metadata (applies to any project with IsPackable=true) -->
1919
<PropertyGroup>
20-
<Version>0.1.15-alpha</Version>
20+
<Version>0.1.16-alpha</Version>
2121
<Authors>ShellUI</Authors>
2222
<Company>ShellUI</Company>
2323
<Copyright>Copyright © 2026 ShellUI</Copyright>

‎docs/ARCHITECTURE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Chrome that must work without a Blazor runtime follows one contract:
209209
| Package / version selectors, preview ⋯ menu | `.pkg` / `.ver` / `.preview-menu` `[data-open]` | open on trigger; close on outside click, Escape or option |
210210
| Preview tabs | `.preview-frame[data-preview-tab]` | Preview / Code; arrow keys; copy reads the source |
211211
| Tabs, CodeGroup, preview code tabs, page switch | `[data-tabs]`, `[data-tab-target]`, `[data-tab-panel]` | switch on click / arrows; `[data-tabs-sync]` groups switch together and persist in `localStorage`; a `[data-tabs-missing]` group without the chosen value shows its `[data-tab-missing]` note; with nothing saved yet, groups follow a `[data-tabs-switch]` for their key |
212-
| Iframe previews | `[data-iframe-preview][data-src][data-lazy]` | sets the iframe's `src` (plus `?theme=`) when visible (IntersectionObserver), on `[data-iframe-run]` or at once; posts `{ type: "shelldocs-theme", theme }` to loaded frames on theme change |
212+
| Iframe previews | `[data-iframe-preview][data-src][data-lazy]` | sets the iframe's `src` (plus `?theme=`) when visible (IntersectionObserver), on `[data-iframe-run]` or at once; posts `{ type: "shelldocs-theme", theme }` to loaded frames on theme change; a host Blazor reuses for another page (`data-src` or `data-lazy` changed) is unloaded and set up again |
213213
| Mobile nav | page shell `[data-mobile-open]` | hamburger toggles; backdrop, Escape, link or navigation closes; page scroll locked on `<html>` |
214214
| Sidebar collapse | page shell `[data-sidebar-collapsed]`, `[data-sidebar-collapse-toggle]` | toggles collapse; remembered in `localStorage` and restored as soon as `shelldocs.js` runs, so the sidebar doesn't flash open |
215215
| TOC | `[data-toc-list][data-toc-ids]` | IntersectionObserver scroll-spy, re-attached on `enhancedload` |

‎docs/ROADMAP.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Ships to `ShellDocs.Components` + `ShellDocs.Templates` + `ShellDocs.CLI` + `She
209209
**Authoring fix (`ShellDocs.Markdown`)**
210210
- `SlotExtractor.ReplaceComponentTags` no longer `.Trim()`s the raw child content of inline component tags. The Trim was stripping the first line's indent and defeating `SlotRenderer.Dedent` — Markdig then interpreted the remaining 4-space-indented lines as an indented code block. Symptom was the same "literal `<pre>` around placeholder divs" bug that had already been fixed for `razor:preview` fences; the inline-tag code path was still hitting it.
211211

212-
### ✅ Hardening releases (`0.1.3`–`0.1.15-alpha`) — shipped
212+
### ✅ Hardening releases (`0.1.3`–`0.1.16-alpha`) — shipped
213213
Driven by building the ShellUI docs on ShellDocs. Highlights (details in the CHANGELOG):
214214

215215
- `feat/build-static-prerender` (0.1.5) — `shelldocs build` prerenders every URL into a static site.
@@ -222,6 +222,7 @@ Driven by building the ShellUI docs on ShellDocs. Highlights (details in the CHA
222222
- `feat/preview-code-variants` (0.1.13) — code tabs on previews with sync and a missing-tab note, page switch (`AddSyncSwitch`), captions, `<IframePreview>`, XAML highlighting; one-line component bodies stay inline.
223223
- `fix/not-found-and-sidebar-collapse` (0.1.14) — `<DocsNotFound>` answers 404, `build` fails on not-found pages and writes `404.html`, desktop sidebar collapse in `shelldocs.js`.
224224
- `feat/static-search` (0.1.15) — search runs in `shelldocs.js` against `/_shelldocs/search.json`, which `build` copies into the export, so static sites have search.
225+
- `fix/iframe-preview-navigation` (0.1.16) — an `<IframePreview>` reused for the next page after in-site navigation is unloaded and set up again.
225226
- `fix/preview-fidelity`, `feat/generics-redirects-page-title` (0.1.10) — `not-prose` previews, Razor child content, stretch layout, generic components in markdown, redirects (middleware + static pages), `RenderPageTitle`, theme sync and a static-host `ThemeToggle`.
226227

227228
### `feat/animation-polish`

‎src/ShellDocs.Components/wwwroot/shelldocs.js‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,13 +369,36 @@ window.shelldocsIframes = (function () {
369369
if (scope.matches && scope.matches('[data-iframe-preview]')) hosts.unshift(scope);
370370
hosts.forEach(function (host) {
371371
if (host.__shelldocsIframe) return;
372-
host.__shelldocsIframe = true;
372+
host.__shelldocsIframe = { src: host.getAttribute('data-src'), lazy: host.getAttribute('data-lazy') };
373373
var lazy = host.getAttribute('data-lazy');
374374
if (lazy === 'none') load(host);
375375
else if (lazy !== 'click') watch(host);
376376
});
377377
}
378378

379+
/* Navigating within the site can reuse a host for the next page's preview and
380+
change only its data-src (or data-lazy), which would leave the previous page's
381+
frame loaded and its Run button hidden. Unload it and set the host up again. */
382+
function reset(host) {
383+
var state = host.__shelldocsIframe;
384+
if (!state) return;
385+
if (state.src === host.getAttribute('data-src') && state.lazy === host.getAttribute('data-lazy')) return;
386+
if (observer) observer.unobserve(host);
387+
host.removeAttribute('data-loaded');
388+
var frame = host.querySelector('iframe');
389+
if (frame && frame.hasAttribute('src')) frame.src = 'about:blank';
390+
host.__shelldocsIframe = null;
391+
init(host);
392+
}
393+
394+
if (window.MutationObserver) {
395+
new MutationObserver(function (records) {
396+
records.forEach(function (r) {
397+
if (r.target.matches && r.target.matches('[data-iframe-preview]')) reset(r.target);
398+
});
399+
}).observe(document.documentElement, { attributes: true, attributeFilter: ['data-src', 'data-lazy'], subtree: true });
400+
}
401+
379402
function postTheme(dark) {
380403
var message = { type: 'shelldocs-theme', theme: dark ? 'dark' : 'light' };
381404
document.querySelectorAll('[data-iframe-preview][data-loaded="true"] iframe').forEach(function (frame) {

‎tests/ShellDocs.Tests/PreviewCodeVariantsTests.cs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,16 @@ public void ShelldocsJs_ShowsTheMissingNote_AndLoadsIframesLazily()
240240
Assert.Matches(new Regex("IntersectionObserver"), js);
241241
}
242242

243+
[Fact]
244+
public void ShelldocsJs_ResetsAnIframeHostReusedForAnotherPage()
245+
{
246+
var js = ReadAsset("shelldocs.js");
247+
248+
Assert.Contains("attributeFilter: ['data-src', 'data-lazy']", js);
249+
Assert.Contains("host.removeAttribute('data-loaded')", js);
250+
Assert.Contains("frame.src = 'about:blank'", js);
251+
}
252+
243253
private static string ReadAsset(string name)
244254
{
245255
var testDir = Path.GetDirectoryName(typeof(PreviewCodeVariantsTests).Assembly.Location)!;

0 commit comments

Comments
 (0)