iPad Cursor
Zero-dependency, component-based iPadOS style cursor, applicable to
Hover input below to see input cursor
$lib/ipad/ipad.ts
import { cursorTarget } from './cursorStore';
function get__store(store: any) {
let $val;
store.subscribe(($: any) => ($val = $))();
return $val;
}
export function ipad(element: HTMLElement, options?: any | null) {
let move = options?.move;
const transitionOnCancelSnap =
'transform .4s cubic-bezier(0.175, 0.885, 0.32, 1.275), background-color 0.3s';
const transitionOnSnap = 'transform .1s ease-out, background-color 0.8s ease-in-out';
const damp = 0.15;
const drag = (e: MouseEvent) => {
if (!e.currentTarget) return;
const target = e.currentTarget as HTMLElement;
if (get__store(cursorTarget) !== target) {
cursorTarget.set(target);
}
if (typeof move == 'undefined' || move == false) return;
const rect = target.getBoundingClientRect();
const x = e.clientX - (rect.left + rect.width / 2);
const y = e.clientY - (rect.top + rect.height / 2);
// console.log(x, y);
const pos = {
x: x * damp,
y: y * damp
};
startSnap(target, pos);
};
const stop = (e: any) => {
cancelSnap(e.currentTarget);
cursorTarget.set(null);
};
function cancelSnap(element: HTMLElement) {
element.style.transform = `translate3d(0, 0, 0)`;
element.style.transition = transitionOnCancelSnap;
}
function startSnap(element: HTMLElement, position: any) {
element.style.transform = `translate3d(${position.x}px, ${position.y}px, 0) scale(1.05)`;
element.style.transition = transitionOnSnap;
}
element.addEventListener('mousemove', drag);
element.addEventListener('mouseout', stop);
return {
update(options?: any | null) {
move = options.move;
// tooltip.innerHTML = options.content;
},
destroy() {
// cleanup
}
};
}