73 lines
1.7 KiB
Svelte
73 lines
1.7 KiB
Svelte
<script>import { afterUpdate } from "svelte";
|
|
export let name;
|
|
export let id = String(Math.random());
|
|
export let value = 0;
|
|
export let min = 0;
|
|
export let max = 100;
|
|
export let step = 1;
|
|
export let ticked = false;
|
|
export let accent = "accent-surface-900 dark:accent-surface-50";
|
|
export let label = "";
|
|
const cBase = "space-y-2";
|
|
const cBaseLabel = "";
|
|
const cBaseContent = "flex justify-center py-2";
|
|
const cBaseInput = "w-full h-2";
|
|
let tickmarks;
|
|
function setTicks() {
|
|
if (ticked == false)
|
|
return;
|
|
tickmarks = Array.from({ length: max - min + 1 }, (_, i) => i + min);
|
|
}
|
|
if (ticked)
|
|
setTicks();
|
|
afterUpdate(() => {
|
|
setTicks();
|
|
});
|
|
$:
|
|
classesBase = `${cBase} ${$$props.class ?? ""}`;
|
|
$:
|
|
classesInput = `${cBaseInput} ${accent}`;
|
|
function prunedRestProps() {
|
|
delete $$restProps.class;
|
|
return $$restProps;
|
|
}
|
|
</script>
|
|
|
|
<div class="range-slider {classesBase}" data-testid="range-slider">
|
|
<!-- Slot: Default -->
|
|
{#if $$slots.default}<label class="range-slider-label {cBaseLabel}" for={id}><slot /></label>{/if}
|
|
|
|
<!-- Content -->
|
|
<div class="range-content {cBaseContent}">
|
|
<!-- Input -->
|
|
<input
|
|
type="range"
|
|
{id}
|
|
{name}
|
|
class="range-slider-input {classesInput}"
|
|
list="tickmarks-{id}"
|
|
aria-label={label}
|
|
{min}
|
|
{max}
|
|
{step}
|
|
bind:value
|
|
on:click
|
|
on:change
|
|
on:blur
|
|
{...prunedRestProps()}
|
|
/>
|
|
|
|
<!-- Tickmarks -->
|
|
{#if ticked && tickmarks && tickmarks.length}
|
|
<datalist id="tickmarks-{id}" class="range-slider-ticks">
|
|
{#each tickmarks as tm}
|
|
<option value={tm} label={tm} />
|
|
{/each}
|
|
</datalist>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Slot: Trail -->
|
|
{#if $$slots.trail}<div class="range-slider-trail"><slot name="trail" /></div>{/if}
|
|
</div>
|