Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified src/lib/icons.spec.ts
Binary file not shown.
33 changes: 28 additions & 5 deletions src/lib/icons/audio-lines.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { untrack } from 'svelte';
import type { IconProps } from './types.js';

let {
Expand Down Expand Up @@ -214,15 +215,15 @@
}
}

function handleMouseEnter() {
hoverAnimate = true;
function startLoop() {
isAnimatingBack = false;
startTime = null;
animationFrameId = requestAnimationFrame(animateFrame);
if (!animationFrameId) {
animationFrameId = requestAnimationFrame(animateFrame);
}
}

function handleMouseLeave() {
hoverAnimate = false;
function settleBack() {
startPositions = {
line1: { y1: line1Y1, y2: line1Y2 },
line2: { y1: line2Y1, y2: line2Y2 },
Expand All @@ -237,6 +238,28 @@
animationFrameId = requestAnimationFrame(animateFrame);
}
}

function handleMouseEnter() {
hoverAnimate = true;
startLoop();
}

function handleMouseLeave() {
hoverAnimate = false;
// A parent still asking for animation keeps the loop running.
if (!animateProp) settleBack();
}

// The loop is driven imperatively, so the prop needs an explicit start/stop.
// untrack keeps this effect depending on animateProp alone - reading the frame
// state as a dependency would re-run it on every frame.
$effect(() => {
const on = animateProp;
untrack(() => {
if (on) startLoop();
else if (!hoverAnimate && animationFrameId) settleBack();
});
});
</script>

<div
Expand Down
10 changes: 9 additions & 1 deletion src/lib/icons/bot.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { untrack } from 'svelte';
import type { IconProps } from './types.js';

let {
Expand Down Expand Up @@ -49,7 +50,9 @@
}

function handleMouseEnter() {
if (animate) return;
// hoverAnimate doubles as the in-flight flag: guard on it, not on the
// animate union, or a parent holding animate=true would block every blink.
if (hoverAnimate) return;
hoverAnimate = true;
animateEyes(13, 15, 14, 14, 250, 200).then(() => {
animateEyes(14, 14, 13, 15, 250).then(() => {
Expand All @@ -58,6 +61,11 @@
});
}

// The blink is driven imperatively, so the prop has to trigger it explicitly.
$effect(() => {
if (animateProp) untrack(handleMouseEnter);
});

$effect(() => () => clearTimeout(entryTimer));
</script>

Expand Down
7 changes: 7 additions & 0 deletions src/lib/icons/eye.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { untrack } from 'svelte';
import type { IconProps } from './types.js';

let {
Expand Down Expand Up @@ -84,6 +85,12 @@
});
}

// The blink morph is driven imperatively, so the prop has to trigger it
// explicitly; the pupil scaling is CSS and follows the class union below.
$effect(() => {
if (animateProp) untrack(handleMouseEnter);
});

const topOutlineD = $derived(topArchPath(morphProgress));
const bottomOutlineD = $derived(bottomArchPath(morphProgress));
</script>
Expand Down
11 changes: 10 additions & 1 deletion src/lib/icons/message-circle-more.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { untrack } from 'svelte';
import type { IconProps } from './types.js';

let {
Expand Down Expand Up @@ -67,7 +68,9 @@
}

function handleMouseEnter() {
if (animate) return;
// hoverAnimate doubles as the in-flight flag: guard on it, not on the
// animate union, or a parent holding animate=true would block the dots.
if (hoverAnimate) return;
hoverAnimate = true;

animateLine(12, 12, 10.5, 13.5, 12, 12, 0.6, 0.2, (y1, y2) => {
Expand All @@ -90,6 +93,12 @@
}, 800);
}

// The dot animation is driven imperatively, so the prop has to trigger it
// explicitly; the group rotation is CSS and follows the animate union.
$effect(() => {
if (animateProp) untrack(handleMouseEnter);
});

$effect(() => () => clearTimeout(resetTimer));
</script>

Expand Down
11 changes: 10 additions & 1 deletion src/lib/icons/message-square-more.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import { untrack } from 'svelte';
import type { IconProps } from './types.js';

let {
Expand Down Expand Up @@ -67,7 +68,9 @@
}

function handleMouseEnter() {
if (animate) return;
// hoverAnimate doubles as the in-flight flag: guard on it, not on the
// animate union, or a parent holding animate=true would block the dots.
if (hoverAnimate) return;
hoverAnimate = true;

animateLine(10, 10, 8.5, 11.5, 10, 10, 0.6, 0.2, (y1, y2) => {
Expand All @@ -90,6 +93,12 @@
}, 800);
}

// The dot animation is driven imperatively, so the prop has to trigger it
// explicitly; the group rotation is CSS and follows the animate union.
$effect(() => {
if (animateProp) untrack(handleMouseEnter);
});

$effect(() => () => clearTimeout(resetTimer));
</script>

Expand Down
2 changes: 1 addition & 1 deletion static/r/audio-lines.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion static/r/bot.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion static/r/eye.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading