enzostvs HF Staff commited on
Commit
beaa75f
Β·
1 Parent(s): 822d5b9

some fixes

Browse files
src/lib/components/flow/FitViewOnResize.svelte CHANGED
@@ -1,5 +1,5 @@
1
  <script lang="ts">
2
- import { onMount, onDestroy, tick } from 'svelte';
3
  import type { Node, Edge } from '@xyflow/svelte';
4
  import { useNodes, useEdges } from '@xyflow/svelte';
5
  import { useSvelteFlow } from '@xyflow/svelte';
@@ -24,6 +24,7 @@
24
  let lastLayoutKey = $state<string | null>(null);
25
  let isFirstLayout = $state(true);
26
  let lastDraggable = $state(viewState.draggable);
 
27
 
28
  // ─── Helpers ────────────────────────────────────────────────────────
29
 
@@ -64,10 +65,10 @@
64
  })()
65
  );
66
 
67
- // ─── Fit view helper (only when draggable) ──────────────────────────
68
 
69
- function doFitView(opts?: { animate?: boolean; forceAnimate?: boolean }) {
70
- if (!viewState.draggable) return;
71
  const nodes = nodesStore.current;
72
  if (nodes.length === 0) return;
73
 
@@ -105,15 +106,15 @@
105
  });
106
  });
107
 
108
- // ─── Window resize ─────────────────────────────────────────────────
109
-
110
- function handleWindowResize() {
111
- if (!viewState.draggable) return;
112
- doFitView({ animate: true });
113
- }
114
-
115
- onMount(() => window.addEventListener('resize', handleWindowResize));
116
- onDestroy(() => window.removeEventListener('resize', handleWindowResize));
117
 
118
  // ─── Layout algorithm ──────────────────────────────────────────────
119
  //
@@ -291,7 +292,7 @@
291
  belowTotalW += extents.get(belowIds[i])!.width;
292
  }
293
 
294
- const childY = y + nodeH + V_SPACING;
295
  let childX = allocX + (blockAWidth - belowTotalW) / 2;
296
 
297
  for (const cid of belowIds) {
@@ -374,14 +375,18 @@
374
  );
375
  }
376
 
377
- if (viewState.draggable) {
378
- // Defer so layout is applied and nodes are measured before fitting
 
 
379
  tick().then(() => {
380
  requestAnimationFrame(() => {
381
- doFitView();
382
  isFirstLayout = false;
383
  });
384
  });
 
 
385
  }
386
  }
387
  </script>
 
1
  <script lang="ts">
2
+ import { tick } from 'svelte';
3
  import type { Node, Edge } from '@xyflow/svelte';
4
  import { useNodes, useEdges } from '@xyflow/svelte';
5
  import { useSvelteFlow } from '@xyflow/svelte';
 
24
  let lastLayoutKey = $state<string | null>(null);
25
  let isFirstLayout = $state(true);
26
  let lastDraggable = $state(viewState.draggable);
27
+ let lastFitViewRequest = $state(0);
28
 
29
  // ─── Helpers ────────────────────────────────────────────────────────
30
 
 
65
  })()
66
  );
67
 
68
+ // ─── Fit view helper ────────────────────────────────────────────────
69
 
70
+ function doFitView(opts?: { animate?: boolean; forceAnimate?: boolean; force?: boolean }) {
71
+ if (!viewState.draggable && !opts?.force) return;
72
  const nodes = nodesStore.current;
73
  if (nodes.length === 0) return;
74
 
 
106
  });
107
  });
108
 
109
+ // Respond to explicit fitView requests (e.g. button click in PanelCanvasActions)
110
+ $effect(() => {
111
+ const req = viewState.fitViewRequest;
112
+ if (req === 0 || req === lastFitViewRequest) return;
113
+ lastFitViewRequest = req;
114
+ tick().then(() => {
115
+ requestAnimationFrame(() => doFitView({ forceAnimate: true, force: true }));
116
+ });
117
+ });
118
 
119
  // ─── Layout algorithm ──────────────────────────────────────────────
120
  //
 
292
  belowTotalW += extents.get(belowIds[i])!.width;
293
  }
294
 
295
+ const childY = y + nodeH + V_SPACING;
296
  let childX = allocX + (blockAWidth - belowTotalW) / 2;
297
 
298
  for (const cid of belowIds) {
 
375
  );
376
  }
377
 
378
+ // Only fit the view on the very first layout (component mount).
379
+ // Subsequent layout updates (new nodes, resizes) reposition nodes
380
+ // without moving the camera β€” the user stays in control of the viewport.
381
+ if (isFirstLayout) {
382
  tick().then(() => {
383
  requestAnimationFrame(() => {
384
+ doFitView({ animate: false });
385
  isFirstLayout = false;
386
  });
387
  });
388
+ } else {
389
+ isFirstLayout = false;
390
  }
391
  }
392
  </script>
src/lib/components/flow/actions/PanelCanvasActions.svelte CHANGED
@@ -1,20 +1,16 @@
1
  <script lang="ts">
2
- import { Maximize, Minus, Plus, MousePointer, HandGrab, Spotlight } from '@lucide/svelte';
3
  import { Panel } from '@xyflow/svelte';
4
 
5
  import { Button } from '$lib/components/ui/button';
6
  import { viewState } from '$lib/state/view.svelte';
7
  import { useSvelteFlow } from '@xyflow/svelte';
8
 
9
- const { fitView, zoomIn, zoomOut, getZoom } = useSvelteFlow();
10
-
11
- $effect(() => {
12
- localStorage.setItem('hf-playground-draggable-option', viewState.draggable.toString());
13
- });
14
-
15
- function handleDraggable() {
16
- viewState.draggable = !viewState.draggable;
17
  }
 
 
18
  </script>
19
 
20
  <Panel
@@ -40,53 +36,8 @@
40
  >
41
  <Minus />
42
  </Button>
43
- <Button
44
- variant="ghost"
45
- size="icon-sm"
46
- onclick={() =>
47
- fitView({
48
- interpolate: 'smooth',
49
- duration: 250,
50
- padding: 0.15
51
- })}
52
- >
53
  <Maximize />
54
  </Button>
55
  </div>
56
- <!-- <div
57
- class="inline-flex w-fit flex-row gap-0.5 rounded-lg border border-border bg-background/30 p-1 backdrop-blur-sm dark:bg-gray-900/30"
58
- >
59
- <Tooltip.Root delayDuration={0}>
60
- <Tooltip.Trigger>
61
- <Button
62
- variant={!viewState.draggable ? 'default' : 'ghost'}
63
- size="icon-sm"
64
- onclick={handleDraggable}
65
- >
66
- <MousePointer />
67
- </Button>
68
- </Tooltip.Trigger>
69
- <Tooltip.Content>
70
- <p class="flex items-center gap-1">
71
- <MousePointer class="size-3.5" /> Free: Move the canvas freely
72
- </p>
73
- </Tooltip.Content>
74
- </Tooltip.Root>
75
- <Tooltip.Root>
76
- <Tooltip.Trigger>
77
- <Button
78
- variant={viewState.draggable ? 'default' : 'ghost'}
79
- size="icon-sm"
80
- onclick={handleDraggable}
81
- >
82
- <Spotlight />
83
- </Button>
84
- </Tooltip.Trigger>
85
- <Tooltip.Content>
86
- <p class="flex items-center gap-1">
87
- <Spotlight class="size-3.5" /> Spotlight: Focus on the selected node
88
- </p>
89
- </Tooltip.Content>
90
- </Tooltip.Root>
91
- </div> -->
92
  </Panel>
 
1
  <script lang="ts">
2
+ import { Maximize, Minus, Plus } from '@lucide/svelte';
3
  import { Panel } from '@xyflow/svelte';
4
 
5
  import { Button } from '$lib/components/ui/button';
6
  import { viewState } from '$lib/state/view.svelte';
7
  import { useSvelteFlow } from '@xyflow/svelte';
8
 
9
+ function requestFitView() {
10
+ viewState.fitViewRequest++;
 
 
 
 
 
 
11
  }
12
+
13
+ const { zoomIn, zoomOut, getZoom } = useSvelteFlow();
14
  </script>
15
 
16
  <Panel
 
36
  >
37
  <Minus />
38
  </Button>
39
+ <Button variant="ghost" size="icon-sm" onclick={requestFitView}>
 
 
 
 
 
 
 
 
 
40
  <Maximize />
41
  </Button>
42
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  </Panel>
src/lib/state/view.svelte.ts CHANGED
@@ -1,3 +1,4 @@
1
  export const viewState = $state({
2
- draggable: true
 
3
  });
 
1
  export const viewState = $state({
2
+ draggable: true,
3
+ fitViewRequest: 0
4
  });