Spaces:
Running
Running
| <script lang="ts"> | |
| import { T } from "@threlte/core"; | |
| import { TransformControls, interactivity } from "@threlte/extras"; | |
| import type { Snippet } from "svelte"; | |
| import { Spring } from "svelte/motion"; | |
| import { useCursor } from "@threlte/extras"; | |
| interface Props { | |
| content: Snippet<[{ isHovered: boolean; isSelected: boolean }]>; // renderable | |
| onClick?: () => void; | |
| } | |
| let { content, onClick }: Props = $props(); | |
| interactivity(); | |
| const scale = new Spring(1); | |
| // Hover state | |
| let isHovered = $state(false); | |
| let isSelected = $state(false); | |
| let isHighlighted = $derived(isHovered || isSelected); | |
| $effect(() => { | |
| // If isHighlighted is true, set the color to hoverColor and opacity to hoverOpacity | |
| if (isHighlighted) { | |
| scale.target = 1.05; | |
| } else { | |
| scale.target = 1; | |
| } | |
| }); | |
| // Handle keyboard events for deselection | |
| $effect(() => { | |
| const handleKeyDown = (event: KeyboardEvent) => { | |
| if (event.key === "Escape" && isSelected) { | |
| isSelected = false; | |
| } | |
| }; | |
| if (isSelected) { | |
| document.addEventListener("keydown", handleKeyDown); | |
| return () => { | |
| document.removeEventListener("keydown", handleKeyDown); | |
| }; | |
| } | |
| }); | |
| const { onPointerEnter, onPointerLeave } = useCursor(); | |
| </script> | |
| <T.Group | |
| onclick={() => { | |
| isSelected = true; | |
| if (onClick) { | |
| onClick(); | |
| } | |
| }} | |
| onpointerenter={() => { | |
| onPointerEnter(); | |
| isHovered = true; | |
| }} | |
| onpointerleave={() => { | |
| onPointerLeave(); | |
| isHovered = false; | |
| }} | |
| scale={scale.current} | |
| > | |
| {#snippet children({ ref })} | |
| {@render content({ isHovered, isSelected })} | |
| {/snippet} | |
| </T.Group> | |
| <!-- From https://github.com/brean/urdf-viewer --> | |