Gestures
Each gesture has a target that applies while it's on: whileHover, whileTap, whileFocus, whileInView, and whileDrag for drag. When it ends, the element goes back to its animate.
import { w } from "@wardic/solid/unstable/v2"
import { createEffect, createSignal } from "solid-js"
/** A button that answers hover, press and keyboard focus, and counts its taps. */
export default function Gestures() {
const [taps, setTaps] = createSignal(0)
// A ward that only listens: the button's own props animate it, and this hears its taps.
const button = w.ward()
createEffect(button.when("tap"), () => {
setTaps((count) => count + 1)
})
return (
<div class="sample-stack">
<w.button class="sample-button" wardRef={button} whileHover={{ scale: 1.06 }} whileTap={{ scale: 0.94 }} whileFocus={{ y: -2 }}>
Tap me
</w.button>
<p class="sample-note">Tapped {taps()} times</p>
</div>
)
}import { w } from "@wardic/solid"
import { createSignal } from "solid-js"
/** A button that answers hover, press and keyboard focus, and counts its taps. */
export default function Gestures() {
const [taps, setTaps] = createSignal(0)
return (
<div class="sample-stack">
<w.button class="sample-button" whileHover={{ scale: 1.06 }} whileTap={{ scale: 0.94 }} whileFocus={{ y: -2 }} onTap={() => setTaps(taps() + 1)}>
Tap me
</w.button>
<p class="sample-note">Tapped {taps()} times</p>
</div>
)
}import { motion } from "motion/react"
import { useState } from "react"
/** A button that answers hover, press and keyboard focus, and counts its taps. */
export default function Gestures() {
const [taps, setTaps] = useState(0)
return (
<div className="sample-stack">
<motion.button className="sample-button" whileHover={{ scale: 1.06 }} whileTap={{ scale: 0.94 }} whileFocus={{ y: -2 }} onTap={() => setTaps((count) => count + 1)}>
Tap me
</motion.button>
<p className="sample-note">Tapped {taps} times</p>
</div>
)
}Press
whileTap applies while the pointer is down on the element, and a tap is a press released over it. The keyboard presses too: Enter, and Space as a button takes it. An element that can't take focus gets tabIndex = 0, so a keyboard can reach it.
A press inside a pressable element presses both, as in Motion. propagate={{ tap: false }} keeps an element's press from reaching its ancestors.
Focus
whileFocus applies to the keyboard's focus (:focus-visible), not a pointer's click.
In view
whileInView applies while the element is in the viewport. viewport tunes it: once keeps it on after the first time, margin grows or shrinks the area, amount is how much of the element must show, and root watches a scrolling element in place of the page.
<w.section initial={{ opacity: 0 }} whileInView={{ opacity: 1 }} viewport={{ once: true, amount: 0.4 }} />Hearing a gesture
- On Solid 1, an element takes Motion's callbacks:
onHoverStart,onHoverEnd,onTapStart,onTap,onTapCancel,onViewportEnter,onViewportLeaveand the drag and pan ones, each(event, info), withinfo.pointin the viewport's coordinates. - On Solid 2, the element's ward gives them: make one with
w.ward(), give it to the element aswardRef, thenawait button.next("tap"), or run an effect overbutton.when("tap").
The Features they need
Hover, press, focus and in-view are domAnimation's, which a provider usually gives every page. Each is also a Feature of its own (hover, press, focus, inView), for a page that needs only one.