@cnvx/nodal 0.0.5 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,29 +1,19 @@
1
1
  <script lang="ts" module>
2
- const browser = !!globalThis?.window;
3
- const dev =
4
- (globalThis as any)?.process?.env?.NODE_ENV &&
5
- !(globalThis as any)?.process.env.NODE_ENV.toLowerCase().startsWith(
6
- "prod",
7
- );
8
-
9
- console.debug({ browser, dev });
10
-
11
2
  import { onMount, setContext, type Snippet } from "svelte";
12
3
  import { SvelteMap } from "svelte/reactivity";
13
4
  import {
14
- debugSide,
15
5
  eq,
16
6
  getBezierPath,
17
7
  getSmoothStepPath,
18
8
  normaliseAngle,
19
9
  Side,
20
10
  sideForAngle,
21
- unitVectorFromAngle,
22
11
  vector2,
23
12
  type Vector2,
24
13
  Anchor,
14
+ browser,
15
+ dev,
25
16
  } from "./diagram-lib.js";
26
- import { draw } from "svelte/transition";
27
17
 
28
18
  export interface DiagramNodeDef {
29
19
  id: string;
@@ -160,7 +150,7 @@
160
150
  }
161
151
 
162
152
  function calculateDimensions(_nodes: typeof nodes) {
163
- console.time("dim");
153
+ // console.time("dim");
164
154
  let newMin = vector2(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
165
155
  let newMax = vector2(Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
166
156
 
@@ -183,7 +173,7 @@
183
173
  );
184
174
  }
185
175
 
186
- console.timeEnd("dim");
176
+ // console.timeEnd("dim");
187
177
  return { min: newMin, max: newMax };
188
178
  }
189
179
 
@@ -13,42 +13,93 @@
13
13
  } from "svelte";
14
14
  import type { HTMLAttributes } from "svelte/elements";
15
15
  import PrerenderDiagram from "./PrerenderDiagram.svelte";
16
+ import { browser } from "./diagram-lib.js";
16
17
 
17
18
  let {
18
19
  children,
20
+ eagerLoad = false,
21
+ rootMargin = "100px", // start a bit before it enters the viewport
19
22
  ...rest
20
23
  }: {
21
24
  children: Snippet;
25
+ eagerLoad: boolean;
26
+ rootMargin?: string;
22
27
  } & HTMLAttributes<HTMLDivElement> = $props();
23
28
 
24
29
  const nodes = new SvelteMap<string, DiagramNodeDef>();
25
-
26
30
  const layers = new SvelteMap<number, Record<string, DiagramNodeDef>>();
27
31
  setContext("layerNodeMap", () => layers);
28
-
29
32
  const edges = new SvelteMap<string, DiagramEdgeDef>();
30
33
 
31
- // let initialDiagramContainer: HTMLElement;
34
+ let containerEl: HTMLDivElement | undefined;
32
35
 
33
- // onMount(() => {
34
- // initialDiagramContainer.remove();
35
- // });
36
+ // If we're SSR (not browser), or eagerLoad is false, render immediately.
37
+ // Otherwise wait until after load + idle + intersection.
38
+ let shouldRender = $derived(!eagerLoad);
36
39
 
37
40
  const initialTime = performance.now();
41
+
42
+ onMount(() => {
43
+ if (!eagerLoad || !containerEl) return;
44
+
45
+ let io: IntersectionObserver | null = null;
46
+
47
+ const idle = (fn: () => void) => {
48
+ const ric = (window as any).requestIdleCallback as
49
+ | ((cb: () => void) => number)
50
+ | undefined;
51
+ if (ric) ric(fn);
52
+ else setTimeout(fn, 0);
53
+ };
54
+
55
+ const startObserving = () => {
56
+ // In case the element is already visible at this moment
57
+ io = new IntersectionObserver(
58
+ (entries) => {
59
+ if (entries.some((e) => e.isIntersecting)) {
60
+ shouldRender = true;
61
+ io?.disconnect();
62
+ io = null;
63
+ }
64
+ },
65
+ { root: null, rootMargin, threshold: 0 },
66
+ );
67
+ io.observe(containerEl!);
68
+ };
69
+
70
+ if (document.readyState === "complete") {
71
+ idle(startObserving);
72
+ } else {
73
+ // Wait until the whole document (including images) has loaded
74
+ window.addEventListener("load", () => idle(startObserving), {
75
+ once: true,
76
+ });
77
+ }
78
+
79
+ return () => {
80
+ io?.disconnect();
81
+ io = null;
82
+ };
83
+ });
38
84
  </script>
39
85
 
40
- <!-- first time to register all the nodes and edges -->
41
- <PrerenderDiagram {nodes} {edges} {children} />
42
-
43
- <!-- second time to actually render it after we calculate all the relative positions and total widths and heights -->
44
- <!-- this is necessary because we need to calculate the relative positions of the nodes and edges -->
45
- <!-- TODO: Investigate how to do this properly with hydrate and mount and render https://svelte.dev/docs/svelte/imperative-component-api#hydrate -->
46
- <div {...rest}>
47
- <Diagram {nodes} {edges}>
48
- {@render children()}
49
- </Diagram>
50
- </div>
86
+ {#if shouldRender}
87
+ <!-- first pass: register all the nodes and edges -->
88
+ <PrerenderDiagram {nodes} {edges} {children} />
89
+
90
+ <!-- second pass: render with computed positions -->
91
+ <div {...rest}>
92
+ <Diagram {nodes} {edges}>
93
+ {@render children()}
94
+ </Diagram>
95
+ </div>
96
+ {:else}
97
+ <!-- Lightweight placeholder / container used for intersection observation. -->
98
+ <div bind:this={containerEl} {...rest}></div>
99
+ {/if}
100
+
51
101
  <!--
52
102
  <svelte:boundary>
53
103
  {@const _ = console.log('Finished rendering diagram in', performance.now() - initialTime, 'ms')}
54
- </svelte:boundary> -->
104
+ </svelte:boundary>
105
+ -->
@@ -2,6 +2,8 @@ import { type Snippet } from "svelte";
2
2
  import type { HTMLAttributes } from "svelte/elements";
3
3
  type $$ComponentProps = {
4
4
  children: Snippet;
5
+ eagerLoad: boolean;
6
+ rootMargin?: string;
5
7
  } & HTMLAttributes<HTMLDivElement>;
6
8
  declare const DiagramController: import("svelte").Component<$$ComponentProps, {}, "">;
7
9
  type DiagramController = ReturnType<typeof DiagramController>;
@@ -187,6 +187,5 @@ top:${top}px;left:${left}px;${nodeDef.clientOnly && !mounted ? "opacity:0" : ""}
187
187
  bind:clientHeight
188
188
  ></div>
189
189
  {/if}
190
- <!-- <div class="absolute top-0 left-0 w-full h-full bg-red-500"> {nodeDef.clientOnly} {mounted}</div> -->
191
190
  {@render children?.()}
192
191
  </div>
@@ -1,3 +1,5 @@
1
+ export declare const browser = true;
2
+ export declare const dev: any;
1
3
  export interface Vector2 {
2
4
  x: number;
3
5
  y: number;
@@ -1,3 +1,6 @@
1
+ export const browser = !!globalThis?.window;
2
+ export const dev = globalThis?.process?.env?.NODE_ENV &&
3
+ !globalThis?.process.env.NODE_ENV.toLowerCase().startsWith("prod");
1
4
  export const vector2 = (x, y) => ({ x, y });
2
5
  export const eq = (a, b) => a.x === b.x && a.y === b.y;
3
6
  export const Anchor = {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@cnvx/nodal",
3
3
  "private": false,
4
4
  "license": "MIT",
5
- "version": "0.0.5",
5
+ "version": "0.1.0",
6
6
  "scripts": {
7
7
  "dev": "vite dev",
8
8
  "dev-lib": "svelte-package -w",