diff options
feat: initial commit
Diffstat (limited to 'src/lib/vendor/svelte-range-slider/range-pips.svelte')
-rw-r--r-- | src/lib/vendor/svelte-range-slider/range-pips.svelte | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/src/lib/vendor/svelte-range-slider/range-pips.svelte b/src/lib/vendor/svelte-range-slider/range-pips.svelte new file mode 100644 index 0000000..418fc7e --- /dev/null +++ b/src/lib/vendor/svelte-range-slider/range-pips.svelte @@ -0,0 +1,303 @@ +<script lang="ts" module> + export interface PipsProps { + min?: number; + max?: number; + step?: number; + values?: number[]; + vertical?: boolean; + reversed?: boolean; + hoverable?: boolean; + disabled?: boolean; + pipstep?: number; + prefix?: string; + suffix?: string; + focus?: boolean; + range?: undefined | boolean | 'min' | 'max'; + all?: undefined | boolean | 'pip' | 'label'; + first?: boolean | 'pip' | 'label'; + last?: boolean | 'pip' | 'label'; + rest?: boolean | 'pip' | 'label'; + percentOf: (v: number) => number; + fixFloat: (v: number) => number; + orientationStart?: 'top' | 'bottom' | 'left' | 'right'; + orientationEnd?: 'top' | 'bottom' | 'left' | 'right'; + formatter?: (v: number, i: number, p: number) => string; + moveHandle: undefined | ((index: number | undefined, value: number) => number); + normalisedClient: (e: MouseEvent | TouchEvent) => { x: number; y: number }; + } +</script> + +<script lang="ts"> + let { + range = false, + min = 0, + max = 100, + step = 1, + values = [(max + min) / 2], + vertical = false, + reversed = false, + hoverable = true, + disabled = false, + pipstep, + all = true, + first, + last, + rest, + prefix = '', + suffix = '', + focus, + orientationStart, + // eslint-disable-next-line no-unused-vars + formatter = (v, i, p) => v.toString(), + percentOf, + moveHandle, + fixFloat, + normalisedClient + }: PipsProps = $props(); + + let clientStart = $state({ x: 0, y: 0 }); + let pipStep = $derived( + pipstep || + ((max - min) / step >= (vertical ? 50 : 100) ? (max - min) / (vertical ? 10 : 20) : 1) + ); + let pipCount = $derived(parseInt(((max - min) / (step * pipStep)).toString(), 10)); + let pipVal = $derived((val: number) => fixFloat(min + val * step * pipStep)); + let isSelected = $derived((val: number) => values.some((v) => fixFloat(v) === fixFloat(val))); + let inRange = $derived((val: number) => { + if (range === 'min') { + return values[0] > val; + } + if (range === 'max') { + return values[0] < val; + } + if (range) { + return values[0] < val && values[1] > val; + } + }); + + /** + * function to run when the user clicks on a label + * we store the original client position so we can check if the user has moved the mouse/finger + * @param {MouseEvent} e the event from browser + **/ + const labelDown = (e: MouseEvent) => { + clientStart = { x: e.clientX, y: e.clientY }; + }; + + /** + * function to run when the user releases the mouse/finger + * we check if the user has moved the mouse/finger, if not we "click" the label + * and move the handle it to the label position + * @param {number} val the value of the label + * @param {MouseEvent|TouchEvent} e the event from browser + */ + function labelUp(val: number, e: MouseEvent | TouchEvent) { + if (disabled) { + return; + } + + const clientPos = normalisedClient(e); + const distanceMoved = Math.sqrt( + Math.pow(clientStart.x - clientPos.x, 2) + Math.pow(clientStart.y - clientPos.y, 2) + ); + + if (clientStart && distanceMoved <= 5) { + moveHandle?.(undefined, val); + } + } +</script> + +<div + class="rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6" + class:disabled + class:hoverable + class:vertical + class:reversed + class:focus +> + {#if (all && first !== false) || first} + <span + class="pip-680f0f01-664b-43b5-9e1c-789449c63c62 first" + class:selected={isSelected(min)} + class:in-range={inRange(min)} + style="{orientationStart}: 0%;" + onpointerdown={labelDown} + onpointerup={(e) => labelUp(min, e)} + > + {#if all === 'label' || first === 'label'} + <span class="pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b"> + {prefix}{formatter(fixFloat(min), 0, 0)}{suffix} + </span> + {/if} + </span> + {/if} + + {#if (all && rest !== false) || rest} + <!-- eslint-disable-next-line no-unused-vars --> + {#each Array(pipCount + 1) as _, i} + {#if pipVal(i) !== min && pipVal(i) !== max} + <span + class="pip-680f0f01-664b-43b5-9e1c-789449c63c62" + class:selected={isSelected(pipVal(i))} + class:in-range={inRange(pipVal(i))} + style="{orientationStart}: {percentOf(pipVal(i))}%;" + onpointerdown={labelDown} + onpointerup={(e) => labelUp(pipVal(i), e)} + > + {#if all === 'label' || rest === 'label'} + <span class="pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b"> + {prefix}{formatter(pipVal(i), i, percentOf(pipVal(i)))}{suffix} + </span> + {/if} + </span> + {/if} + {/each} + {/if} + + {#if (all && last !== false) || last} + <span + class="pip last" + class:selected={isSelected(max)} + class:in-range={inRange(max)} + style="{orientationStart}: 100%;" + onpointerdown={labelDown} + onpointerup={(e) => labelUp(max, e)} + > + {#if all === 'label' || last === 'label'} + <span class="pipVal"> + {prefix}{formatter(fixFloat(max), pipCount, 100)}{suffix} + </span> + {/if} + </span> + {/if} +</div> + +<style> + :global(._rangeslider-0f6d4a99-47b0-4108-8415-b2aefa867e28) { + --pip: var(--range-pip, lightslategray); + --pip-text: var(--range-pip-text, var(--pip)); + --pip-active: var(--range-pip-active, darkslategrey); + --pip-active-text: var(--range-pip-active-text, var(--pip-active)); + --pip-hover: var(--range-pip-hover, darkslategrey); + --pip-hover-text: var(--range-pip-hover-text, var(--pip-hover)); + --pip-in-range: var(--range-pip-in-range, var(--pip-active)); + --pip-in-range-text: var(--range-pip-in-range-text, var(--pip-active-text)); + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6) { + position: absolute; + height: 1em; + left: 0; + right: 0; + bottom: -1em; + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.vertical) { + height: auto; + width: 1em; + left: 100%; + right: auto; + top: 0; + bottom: 0; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pip-680f0f01-664b-43b5-9e1c-789449c63c62 + ) { + height: 0.4em; + position: absolute; + top: 0.25em; + width: 1px; + white-space: nowrap; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.vertical + .pip-680f0f01-664b-43b5-9e1c-789449c63c62 + ) { + height: 1px; + width: 0.4em; + left: 0.25em; + top: auto; + bottom: auto; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b + ) { + position: absolute; + top: 0.4em; + transform: translate(-50%, 25%); + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.vertical + .pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b + ) { + position: absolute; + top: 0; + left: 0.4em; + transform: translate(25%, -50%); + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pip-680f0f01-664b-43b5-9e1c-789449c63c62 + ) { + transition: all 0.15s ease; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b + ) { + transition: + all 0.15s ease, + font-weight 0s linear; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pip-680f0f01-664b-43b5-9e1c-789449c63c62 + ) { + color: var(--pip-text, lightslategray); + background-color: var(--pip, lightslategray); + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pip.selected) { + color: var(--pip-active-text, darkslategrey); + background-color: var(--pip-active, darkslategrey); + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.hoverable:not(.disabled) .pip:hover) { + color: var(--pip-hover-text, darkslategrey); + background-color: var(--pip-hover, darkslategrey); + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pip.in-range) { + color: var(--pip-in-range-text, darkslategrey); + background-color: var(--pip-in-range, darkslategrey); + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 .pip.selected) { + height: 0.75em; + } + :global(.rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.vertical .pip.selected) { + height: 1px; + width: 0.75em; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6 + .pip.selected + .pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b + ) { + font-weight: bold; + top: 0.75em; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.vertical + .pip.selected + .pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b + ) { + top: 0; + left: 0.75em; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.hoverable:not(.disabled) + .pip:not(.selected):hover + ) { + transition: none; + } + :global( + .rangePips-f75c52e3-b799-4c81-8238-035d862cc2e6.hoverable:not(.disabled) + .pip:not(.selected):hover + .pipVal-c41e7185-de59-40a7-90f2-e3d98b1e844b + ) { + transition: none; + font-weight: bold; + } +</style> |