import { createMixin, css, on, type Handle } from '@remix-run/ui'
import { animateEntrance, animateExit, spring } from '@remix-run/ui/animation'
// Demo
const buttonExitAnimation = {
opacity: 0,
transform: 'scale(1.15)',
duration: 100,
easing: 'ease-in',
}
const confirmationEnterAnimation = {
opacity: 0,
transform: 'scale(0.9)',
duration: 200,
easing: 'ease-out',
}
export function HoldToConfirm(handle: Handle) {
let confirmed = false
return () => (
*': { gridArea: '1 / 1' },
}),
]}
>
{!confirmed && (
{
confirmed = true
handle.update()
}}
/>
)}
{confirmed && (
{
confirmed = false
handle.update()
}}
/>
)}
)
}
function HoldButton(handle: Handle<{ onConfirm: () => void }>) {
let confirming = false
return () => (
)
}
function Confirmation(handle: Handle<{ onReset: () => void }>) {
return () => (
Deleted
)
}
function TrashIcon() {
return () => (
)
}
function CheckIcon() {
return () => (
)
}
const PRESS_CONFIRM_TIME = 2000
const pressConfirmStartEventType = 'demo:press-confirm-start' as const
const pressConfirmCancelEventType = 'demo:press-confirm-cancel' as const
const pressConfirmEndEventType = 'demo:press-confirm-end' as const
declare global {
interface HTMLElementEventMap {
[pressConfirmStartEventType]: Event
[pressConfirmCancelEventType]: Event
[pressConfirmEndEventType]: Event
}
}
const baseConfirmPress = createMixin((handle) => {
let timer = 0
let pressing = false
let clearTimer = () => {
if (timer) {
clearTimeout(timer)
timer = 0
}
}
let start = (target: Element) => {
clearTimer()
pressing = true
target.dispatchEvent(new Event(pressConfirmStartEventType, { bubbles: true }))
timer = window.setTimeout(() => {
timer = 0
pressing = false
target.dispatchEvent(new Event(pressConfirmEndEventType, { bubbles: true }))
}, PRESS_CONFIRM_TIME)
}
let cancel = (target: Element) => {
if (!pressing) return
clearTimer()
pressing = false
target.dispatchEvent(new Event(pressConfirmCancelEventType, { bubbles: true }))
}
handle.addEventListener('remove', () => {
clearTimer()
pressing = false
})
return (props) => (
{
if (event.isPrimary === false) return
start(event.currentTarget)
}),
on('pointerup', (event) => {
cancel(event.currentTarget)
}),
on('pointercancel', (event) => {
cancel(event.currentTarget)
}),
on('pointerleave', (event) => {
cancel(event.currentTarget)
}),
on('keydown', (event) => {
if (!(event.key === 'Enter' || event.key === ' ') || event.repeat) return
event.preventDefault()
start(event.currentTarget)
}),
on('keyup', (event) => {
if (!(event.key === 'Enter' || event.key === ' ')) return
event.preventDefault()
cancel(event.currentTarget)
}),
on('blur', (event) => {
cancel(event.currentTarget)
}),
]}
/>
)
})
type ConfirmPressMixin = typeof baseConfirmPress & {
readonly start: typeof pressConfirmStartEventType
readonly cancel: typeof pressConfirmCancelEventType
readonly end: typeof pressConfirmEndEventType
}
const confirmPress: ConfirmPressMixin = Object.assign(baseConfirmPress, {
start: pressConfirmStartEventType,
cancel: pressConfirmCancelEventType,
end: pressConfirmEndEventType,
})