Skip to content

Commit d395b21

Browse files
committedFeb 15, 2025
iframe interactivity
1 parent f132435 commit d395b21

File tree

10 files changed

+196
-45
lines changed

10 files changed

+196
-45
lines changed
 

‎packages/docs/astro.config.mjs

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ export default defineConfig({
6464
],
6565
markdown: {
6666
rehypePlugins: [
67-
[rehypeGraphviz, { cache, class: className }],
68-
[rehypeVizdom, { cache, class: className }],
67+
[rehypeGraphviz, { ...conf, strategy: "inline" }],
68+
[rehypeVizdom, { ...conf, strategy: "inline" }],
6969
[rehypeMermaid, conf],
7070
[rehypeGnuplot, conf],
7171
[rehypeD2, { ...conf, shared: "shared/**/*.d2" }],

‎packages/docs/src/components/PageFrame.astro

+1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ import Default from "@astrojs/starlight/components/PageFrame.astro";
1414
import "./vizdom.ts";
1515
import "./graphviz.ts";
1616
import "./d2.ts";
17+
import "./iframeTarget.ts";
1718
</script>

‎packages/docs/src/components/d2.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
import { json, alg } from "@dagrejs/graphlib";
22

3+
const css = `.shadow { opacity: 0.4; }
4+
.shape { cursor: default; }`;
5+
36
// interactivity for d2 diagrams
4-
document.querySelectorAll(".d2.shadow").forEach((container) => {
7+
document.querySelectorAll(".d2.shadow").forEach(async (container: Element) => {
58
const data = container.getAttribute("data-beoe")
69
? JSON.parse(container.getAttribute("data-beoe")!)
710
: null;
811

12+
const iframe = container.querySelector("iframe");
13+
if (iframe) {
14+
if (!iframe.contentDocument)
15+
await new Promise((resolve) =>
16+
iframe.addEventListener("load", () => resolve(0))
17+
);
18+
container = iframe.contentDocument!.querySelector("svg")! as Element;
19+
const styleSheet = iframe.contentDocument!.styleSheets[0];
20+
css
21+
.split("\n")
22+
.forEach((row) => styleSheet.insertRule(row, styleSheet.cssRules.length));
23+
}
24+
925
if (!data) return;
1026
const graph = json.read(data);
1127

‎packages/docs/src/components/graphviz.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,20 @@ import { json, alg, type Path } from "@dagrejs/graphlib";
33
type D = { [node: string]: Path };
44

55
// interactivity for graphviz diagrams
6-
document.querySelectorAll(".graphviz").forEach((container) => {
6+
document.querySelectorAll(".graphviz").forEach(async (container) => {
77
const data = container.getAttribute("data-beoe")
88
? JSON.parse(container.getAttribute("data-beoe")!)
99
: null;
1010

11+
const iframe = container.querySelector("iframe");
12+
if (iframe) {
13+
if (!iframe.contentDocument)
14+
await new Promise((resolve) =>
15+
iframe.addEventListener("load", () => resolve(0))
16+
);
17+
container = iframe.contentDocument!.querySelector("svg")! as Element;
18+
}
19+
1120
if (!data) return;
1221
const graph = json.read(data);
1322

@@ -126,4 +135,4 @@ document.querySelectorAll(".graphviz").forEach((container) => {
126135
}
127136
}
128137
});
129-
});
138+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// to make sure anchors open in top frame
2+
document
3+
.querySelectorAll(".beoe iframe")
4+
// @ts-expect-error
5+
.forEach((iframe: HTMLIFrameElement) => {
6+
const addTargets = () =>
7+
iframe.contentDocument
8+
?.querySelectorAll("a")
9+
.forEach((x) => x.setAttribute("target", "_top"));
10+
iframe.addEventListener("load", addTargets);
11+
addTargets();
12+
});

‎packages/docs/src/components/vizdom.ts

+62-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,62 @@ import { json, alg, type Path } from "@dagrejs/graphlib";
22

33
type D = { [node: string]: Path };
44

5+
// const vizdomCss = [
6+
// `@keyframes dash {
7+
// from {
8+
// stroke-dashoffset: 40;
9+
// }
10+
// to {
11+
// stroke-dashoffset: 0;
12+
// }
13+
// }`,
14+
// `.edge.active a path:first-child {
15+
// stroke-dasharray: 5 5;
16+
// animation-name: dash;
17+
// animation-duration: 1000ms;
18+
// stroke-dashoffset: 0;
19+
// animation-iteration-count: infinite;
20+
// animation-timing-function: linear;
21+
// }`,
22+
23+
// `.node.selected a *:first-child {
24+
// stroke-width: 2px;
25+
// }`,
26+
// `.node {
27+
// cursor: pointer;
28+
// }`,
29+
// `@media (prefers-reduced-motion) {
30+
// .edge.active a path:first-child {
31+
// animation-duration: 4000ms;
32+
// }
33+
// }`,
34+
// ];
35+
536
// interactivity for vizdom diagrams
6-
document.querySelectorAll(".vizdom.ants").forEach((container) => {
37+
document.querySelectorAll(".vizdom.ants").forEach(async (container) => {
738
const data = container.getAttribute("data-beoe")
839
? JSON.parse(container.getAttribute("data-beoe")!)
940
: null;
1041

42+
// const iframe = container.querySelector("iframe");
43+
// if (iframe) {
44+
// if (!iframe.contentDocument)
45+
// await new Promise((resolve) =>
46+
// iframe.addEventListener("load", () => resolve(0))
47+
// );
48+
49+
// container = iframe.contentDocument!.querySelector("svg")! as Element;
50+
// // container.setAttribute("preserveAspectRatio", "xMinYMin meet");
51+
// const style = iframe.contentDocument!.createElement("style");
52+
// style.setAttribute("type", "text/css");
53+
// container.prepend(style);
54+
// const styleSheet = iframe.contentDocument!.styleSheets[0];
55+
// if (styleSheet)
56+
// vizdomCss.forEach((row) =>
57+
// styleSheet.insertRule(row, styleSheet.cssRules.length)
58+
// );
59+
// }
60+
1161
if (!data) return;
1262
const graph = json.read(data);
1363

@@ -129,11 +179,21 @@ document.querySelectorAll(".vizdom.ants").forEach((container) => {
129179
});
130180

131181
// interactivity for vizdom diagrams
132-
document.querySelectorAll(".vizdom.shadow").forEach((container) => {
182+
document.querySelectorAll(".vizdom.shadow").forEach(async (container) => {
133183
const data = container.getAttribute("data-beoe")
134184
? JSON.parse(container.getAttribute("data-beoe")!)
135185
: null;
136186

187+
// const iframe = container.querySelector("iframe");
188+
// if (iframe) {
189+
// if (!iframe.contentDocument)
190+
// await new Promise((resolve) =>
191+
// iframe.addEventListener("load", () => resolve(0))
192+
// );
193+
194+
// container = iframe.contentDocument!.querySelector("svg")! as Element;
195+
// }
196+
137197
if (!data) return;
138198
const graph = json.read(data);
139199

‎packages/docs/src/content/docs/examples/d2-test.md

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ direction: right
1111
a -> b -> c -> d -> e
1212
```
1313

14+
### tag=iframe
15+
16+
```d2 darkScheme=false graphFormat=dagre class=shadow svgo=false strategy=file tag=iframe
17+
direction: right
18+
a -> b -> c -> d -> e
19+
```
20+
1421
### import
1522

1623
```d2

‎packages/docs/src/content/docs/examples/vizdom-test.md

+30
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ draft: true
77

88
**Interactivity**: ants. Try 👇 hover or click nodes.
99

10+
### tag=svg
11+
1012
```vizdom graphFormat=dagre class=ants
1113
digraph finite_state_machine {
1214
bgcolor="transparent";
@@ -33,6 +35,34 @@ digraph finite_state_machine {
3335
}
3436
```
3537

38+
### tag=iframe
39+
40+
```vizdom graphFormat=dagre class=ants strategy=file tag=iframe
41+
digraph finite_state_machine {
42+
bgcolor="transparent";
43+
fontname="Helvetica,Arial,sans-serif";
44+
node [fontname="Helvetica,Arial,sans-serif"]
45+
edge [fontname="Helvetica,Arial,sans-serif"]
46+
rankdir=LR;
47+
node [shape = doublecircle]; 0 3 4 8;
48+
node [shape = circle];
49+
0 -> 2 [label = "SS(B)"];
50+
0 -> 1 [label = "SS(S)"];
51+
1 -> 3 [label = "S($end)"];
52+
2 -> 6 [label = "SS(b)"];
53+
2 -> 5 [label = "SS(a)"];
54+
2 -> 4 [label = "S(A)"];
55+
5 -> 7 [label = "S(b)"];
56+
5 -> 5 [label = "S(a)"];
57+
6 -> 6 [label = "S(b)"];
58+
6 -> 5 [label = "S(a)"];
59+
7 -> 8 [label = "S(b)"];
60+
7 -> 5 [label = "S(a)"];
61+
8 -> 6 [label = "S(b)"];
62+
8 -> 5 [label = "S(a)"];
63+
}
64+
```
65+
3666
## rehype-plugin
3767

3868
### works with dark mode

‎packages/docs/src/content/docs/start-here/tag.md

+5-4
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ diagram text
6464
| --------------------------------------------------------------------------------------- | ------------------------------------------------ | -------------------- | -------------------- |
6565
| [Searchable text](/start-here/interactivity/#searchable-text) | yes | no | yes |
6666
| [Links](/start-here/interactivity/#links) | yes | no | yes with caveats (1) |
67-
| [Interactivity with JS](/start-here/interactivity/#progressive-enhancement-with-js) (2) | yes | no | no (3) |
67+
| [Interactivity with JS](/start-here/interactivity/#progressive-enhancement-with-js) (2) | yes | no | yes with caveats (3) |
6868
| [Can be styled with CSS](/start-here/styling-with-css/) | yes | no | no |
6969
| CSS conflicts | possible | no | no |
7070
| [`alt="..."` or `title="..."`](/start-here/accessibility/) | no | yes | yes |
@@ -73,8 +73,9 @@ diagram text
7373

7474
- (1) Links require `target=_top`, iframe may require `allow-top-navigation`
7575
- (2) This includes [link previews](https://astro-digital-garden.stereobooster.com/recipes/link-previews/)
76-
- (3) Problem is that `iframe` sandboxes content, which makes it impossible to access it via JS
77-
- **TODO**: I wonder if domain is the same, maybe restriction can be lifted.
78-
- **TODO**: I also don't know if `embed` has the same restrictions
76+
- (3) It is possible to access `iframe` content via JS, but I suspect it will have issues
77+
- with [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
78+
- `embed`, it seems, doesn't have `DOM`
79+
- there probably will be issues with `@floating-ui/dom`
7980
- (4) [Work only if images inlined (via `data-url`)](https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_as_an_Image#restrictions)
8081
- (5) gestures don't work (at least in the current implementation), buttons work though

0 commit comments

Comments
 (0)
Failed to load comments.