Initial commit -- Core Cooldown v0.1.0
This commit is contained in:
88
src/lib/components/Stepper.svelte
Normal file
88
src/lib/components/Stepper.svelte
Normal file
@@ -0,0 +1,88 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
value: number;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
formatValue?: (v: number) => string;
|
||||
onchange?: (value: number) => void;
|
||||
}
|
||||
|
||||
let {
|
||||
value = $bindable(),
|
||||
min = 0,
|
||||
max = 100,
|
||||
step = 1,
|
||||
formatValue = (v: number) => String(v),
|
||||
onchange,
|
||||
}: Props = $props();
|
||||
|
||||
let holdTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
let holdInterval: ReturnType<typeof setInterval> | null = null;
|
||||
|
||||
function decrement() {
|
||||
if (value > min) {
|
||||
value = Math.max(min, value - step);
|
||||
onchange?.(value);
|
||||
}
|
||||
}
|
||||
|
||||
function increment() {
|
||||
if (value < max) {
|
||||
value = Math.min(max, value + step);
|
||||
onchange?.(value);
|
||||
}
|
||||
}
|
||||
|
||||
function startHold(fn: () => void) {
|
||||
fn();
|
||||
// Initial delay before repeating
|
||||
holdTimer = setTimeout(() => {
|
||||
// Start repeating, accelerate over time
|
||||
let delay = 150;
|
||||
function tick() {
|
||||
fn();
|
||||
delay = Math.max(40, delay * 0.85);
|
||||
holdInterval = setTimeout(tick, delay) as unknown as ReturnType<typeof setInterval>;
|
||||
}
|
||||
tick();
|
||||
}, 400);
|
||||
}
|
||||
|
||||
function stopHold() {
|
||||
if (holdTimer) { clearTimeout(holdTimer); holdTimer = null; }
|
||||
if (holdInterval) { clearTimeout(holdInterval as unknown as ReturnType<typeof setTimeout>); holdInterval = null; }
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex items-center gap-1.5">
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-7 w-7 items-center justify-center rounded-lg
|
||||
bg-[#141414] text-[#444] transition-colors
|
||||
hover:bg-[#1c1c1c] hover:text-white
|
||||
disabled:opacity-20"
|
||||
onmousedown={() => startHold(decrement)}
|
||||
onmouseup={stopHold}
|
||||
onmouseleave={stopHold}
|
||||
disabled={value <= min}
|
||||
>
|
||||
−
|
||||
</button>
|
||||
<span class="min-w-[38px] text-center text-[13px] tabular-nums text-white">
|
||||
{formatValue(value)}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-7 w-7 items-center justify-center rounded-lg
|
||||
bg-[#141414] text-[#444] transition-colors
|
||||
hover:bg-[#1c1c1c] hover:text-white
|
||||
disabled:opacity-20"
|
||||
onmousedown={() => startHold(increment)}
|
||||
onmouseup={stopHold}
|
||||
onmouseleave={stopHold}
|
||||
disabled={value >= max}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
Reference in New Issue
Block a user