Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use frame for sandboxed component preview, stricter accessibility checks #437

Closed
wants to merge 10 commits into from

Conversation

aduth
Copy link
Contributor

@aduth aduth commented Apr 19, 2024

🛠 Summary of changes

Adapts component previews to use an isolated preview sandbox using iframe elements.

The intent is to be able to enable stricter automated accessibility tests, which were previously not possible and identified as a follow-up goal due to the fact that previews assume an isolated render environment, but didn't actually isolate.

This is similar to #418 and adapts some of the postMessage-based frame communication, though in a much more limited capacity, as the frame content itself is generated statically by Jekyll, and the only frame communication is necessary to resize the preview on content changes.

Draft: Currently, proof-of-concept only adapts the Accordion Default preview.

📜 Testing Plan

Verify there is no detectable difference in the preview of a component, e.g. the Accordions Default preview.

👀 Screenshots

Screenshot 2024-04-19 at 11 39 30 AM

></iframe>
<script>
/** @type {HTMLIFrameElement} */
const iframe = document.currentScript.previousElementSibling;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I think about it, since we don't actually sandbox the frame and it's hosted on the same domain, we could probably just add an observer directly from this point:

Suggested change
const iframe = document.currentScript.previousElementSibling;
const iframe = document.currentScript.previousElementSibling;
const { body: frameBody } = iframe.contentWindow.document;
new ResizeObserver(() => {
iframe.height = frameBody.offsetHeight;
}).observe(frameBody);

Then again, maybe we do want to sandbox, or at least treat as if it's sandboxed? I don't know that it's a whole lot more complex as implemented.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need resize support? this is local previews only, could we have folks just hit refresh after they resize?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't strictly need it, but we also can't know the natural height of the preview ahead-of-time†, so if we didn't have this, we'd have to set the height to something static and let the page either (a) be taller than necessary or (b) have scroll.

† Technically, we could measure this ahead of time, either manually or through some script using something like Puppeteer to measure the heights of each rendered preview, but that would be far more involved than what this implementation is currently doing.

@aduth
Copy link
Contributor Author

aduth commented Apr 19, 2024

I'm staring at this visual regression diff and struggling to find the difference 😅

@aduth
Copy link
Contributor Author

aduth commented Apr 22, 2024

I'm staring at this visual regression diff and struggling to find the difference 😅

There appears to be a one pixel difference in height (2504px vs. 2505px). I'll try to track down where that pixel difference is coming from, but also I noticed that our visual regression test is supposed to fill empty differences in dimensions, but this doesn't work correctly. It should do a two-pass loop on both width and height, since otherwise it won't draw the necessary height "rows" if the width already matches. I think I'll either want to fix that, or track down the source of the pixel offset (and maybe remove the fillImageToSize helper?).

@aduth
Copy link
Contributor Author

aduth commented Apr 22, 2024

One interesting idea that this could enable is to adapt visual regression tests to take screenshots of individual examples in isolation, to avoid common failures due to changes in content or navigation.

Comment on lines +26 to +27
const height = Number(event.data);
iframe.height = height;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to check that event has a data? or should we send an Object { height } as event data do we could guard with 'height' in event.data ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be wise to do some basic validation, yeah. The condition above at least assures that the message originates from the same domain and we can assume for the moment this is the only code sending messages, but including some validation might help avoid future issues if someone wanted to use postMessage for something else.

@aduth
Copy link
Contributor Author

aduth commented Apr 23, 2024

General thoughts after I've started migrating a few more examples:

  • It creates some fragmentation where the code samples live in a different folder from the rest of the documentation, which could become burdensome to keep track of
  • On the other hand:
    • It could be beneficial to keep the content documentation focused on the content and the different variants available (subheadings) and not on the actual code
    • There could be opportunities to automate how these individual examples are compiled together to produce the documentation page

@aduth
Copy link
Contributor Author

aduth commented May 1, 2024

I think I might pause on this for now, and may return to it later.

One idea I've been thinking about that may simplify the effort is to try to find a way to generate the embed pages dynamically via a custom Jekyll tag like {% code_example %}, so the code snippets can remain in the original documentation files, while having the same end-result of creating individual embedded pages.

@aduth aduth closed this May 1, 2024
@aduth aduth deleted the aduth-code-example-frame branch May 1, 2024 18:02
@timothy-spencer timothy-spencer restored the aduth-code-example-frame branch June 6, 2024 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants