58 lines
1.1 KiB
Svelte
58 lines
1.1 KiB
Svelte
<script lang="ts">
|
||
import { clamp } from '$lib/builder/loadout';
|
||
|
||
let {
|
||
label,
|
||
min,
|
||
max,
|
||
value = $bindable(),
|
||
provisional = false,
|
||
step = 1,
|
||
onchange
|
||
}: {
|
||
label: string;
|
||
min: number;
|
||
max: number;
|
||
value: number;
|
||
provisional?: boolean;
|
||
step?: number;
|
||
onchange?: (value: number) => void;
|
||
} = $props();
|
||
|
||
function update(raw: unknown) {
|
||
const next = Number(clamp(raw, min, max));
|
||
if (onchange) onchange(next);
|
||
else value = next;
|
||
}
|
||
</script>
|
||
|
||
<label class="range-value-control">
|
||
<span class="range-value-head">
|
||
<b>{label}</b>
|
||
<small>{min}–{max}{provisional ? ' · ESTIMATED' : ''}</small>
|
||
</span>
|
||
<span class="range-value-inputs">
|
||
<input
|
||
class="range-value-slider"
|
||
type="range"
|
||
{min}
|
||
{max}
|
||
{step}
|
||
value={value}
|
||
aria-label={`${label} slider`}
|
||
oninput={(event) => update(event.currentTarget.value)}
|
||
/>
|
||
<input
|
||
class="range-value-number"
|
||
type="number"
|
||
{min}
|
||
{max}
|
||
{step}
|
||
value={value}
|
||
aria-label={`${label} value`}
|
||
onchange={(event) => update(event.currentTarget.value)}
|
||
onblur={(event) => update(event.currentTarget.value)}
|
||
/>
|
||
</span>
|
||
</label>
|