svelte-range-slider-pips icon indicating copy to clipboard operation
svelte-range-slider-pips copied to clipboard

[bug] Svelte 5 Range handles are not moving when dragged.

Open serferdinand2 opened this issue 1 year ago • 13 comments

Describe the bug The slider handles are not moving even tho the value is being read and the handler recognizes the value EDIT: It looks like this is, in general, an issue with bind: values = {...} and it is not limited to range property. As soon as you bind the values the slider handles will stop moving. To Reproduce

Steps to reproduce the behavior:

  1. npmi svelte-range-slider-pips components into svelte 5 project
let {min, max} = $props();
// old export let min

let values = $state([0, 8]);
// old $: values = [0,8]
<RangeSlider
		float
		range
		pips
		hoverable
		{id}
		{min}
		{max}
		all="label"
		bind:values
		on:stop={someHandler} />
  1. Run in Vite

Screenshots As seen from the picture below, even tho the handle was moved and the value was read, the actual handle element stayed in place.

Screenshot 2024-01-24 at 19 59 39 Screenshot 2024-01-24 at 20 00 37

Device/Environtment

Svelte 5 with typescript and sveltekit 2

Additional context I have noticed that this component is on svelte 3.0.0. It would be great to create an alpha version of svelte-range-slider-pips that is accommodating the new runes system. If not, it should be crosscompatible with at least Svelte 4.

serferdinand2 avatar Jan 24 '24 19:01 serferdinand2

thanks @serferdinand2 for the detailed explainer! I have a question, though, your last line indicates the issue exists in svelte4?

Also I note you've written Sveltekit2 ... is this a SSR issue? Does the same thing happen when SSR is off? Perhaps the new runes are not compatible with binding to an array?

simeydotme avatar Jan 26 '24 03:01 simeydotme

@simeydotme

I have made sure that the component is rendered in the browser with {#if browser} module. If not, an error occurs:

ReferenceError: document is not defined
    at pureText (/Users/***/Work/***/svelte_components/node_modules/svelte-range-slider-pips/src/RangeSlider.svelte:396:17)
    ...

So yes, I made sure that it is CSR.

As for the comment on Svelte 4, different issues might occur. The bundler support has changed. I am not 100% sure how exactly this might affect the slider. I did not dig into its code but I think it might be the reason for the #125 issue.

https://svelte.dev/docs/v4-migration-guide#browser-conditions-for-bundlers

I'd love to try and experimentally upgrade this component to Svelte 5 when I find some time.

serferdinand2 avatar Jan 26 '24 15:01 serferdinand2

Ah that was my bad, I fixed it with 2.3.1, apologies on that

simeydotme avatar Jan 26 '24 16:01 simeydotme

Regarding Svelte 5;

Every few weeks I sit down and think "today is the day"... I install Svelte in a fresh branch and look at it and get mad.

There's no clear way, and no good tutorials, on how to build and bundle the Svelte components from the new Sveltekit library project into a UMD plain js.

I haven't upgraded from Svelte 3 because that was the last time the rollup bundler was able to convert the Svelte components into a .js file.

I feel quite disappointed, because I don't really want to isolate this component to Svelte. I've used it in my own Vue projects and jQuery projects. I don't want to lose that. can't seem to get the "custom element" bundle working.

If you have any information, or know any good resources on this I'd really appreciate it

I've learned a lot since I first started this project so I would love to rebuild it in Svelte 4/5 , maybe even with TypeScript 😬 .. but yeh I just can't get over that problem of locking it in to Svelte only.

simeydotme avatar Jan 26 '24 17:01 simeydotme

ok, I have something working. 😅

watch this space

simeydotme avatar Jan 28 '24 16:01 simeydotme

Sorry, long weekend.

I am glad if you found something that works.

Usually you can control SSR with onMount, {browser}, +page.js/ts and other.

serferdinand2 avatar Jan 29 '24 20:01 serferdinand2

hey @serferdinand2 do you mind to try with the beta version I just published? https://www.npmjs.com/package/svelte-range-slider-pips/v/3.0.0-beta.3 see if that is working?

I updated to svelte4 and added types and other small improvements. Haven't updated readme/docs yet ... need to make sure I didn't break anything first

simeydotme avatar Feb 04 '24 16:02 simeydotme

I've installed the beta version, unfortunately, the issue with handles moving is persisting on Svelte 5 with Sveltekit 2

It looks like the value is updated but the nub is not moving still..

serferdinand2 avatar Feb 07 '24 16:02 serferdinand2

It also looks like if you pass the value like

<RangeSlider 
    {min}
    {max}
    value = {2}
    />

The numb is moved to the position indicated by the value. I hope this helps!

serferdinand2 avatar Feb 07 '24 16:02 serferdinand2

thanks @serferdinand2 , I'll look into it!

simeydotme avatar Feb 10 '24 14:02 simeydotme

ok, I think it's to do with how Svelte5 Runes have compiled with the spring store;

$.untrack(() => {
  const trimmedAlignedValues = trimRange(values().map((v) => alignValueToStep(v, min(), max(), step(), precision())));
  
  if (!(values().length === trimmedAlignedValues.length) || !values().every((element, index) => coerceFloat(element, precision()) === trimmedAlignedValues[index])) {
    values(trimmedAlignedValues);
  }
  
  if ($.get(valueLength) !== values().length) {
    $.set(springPositions, spring(values().map((v) => valueAsPercent(v, min(), max())), springValues()));
  } else {
    $.get(springPositions).set(values().map((v) => valueAsPercent(v, min(), max())));
  }
  
  $.set(valueLength, values().length);
});

This is the compiled svelte5 (internal) rune code, and it seems to be not tracking anything inside this reactive chunk ($.untrack) when the values[] array changes .. I guess something about the way my reactive block code is done just doesn't convert well;

$: {
  // trim the range so it remains as a min/max (only 2 handles)
  // and also align the handles to the steps
  const trimmedAlignedValues = trimRange(
    values.map((v) => alignValueToStep(v, min, max, step, precision))
  );
  if (
    !(values.length === trimmedAlignedValues.length) ||
    !values.every(
      (element, index) =>
        coerceFloat(element, precision) === trimmedAlignedValues[index]
    )
  ) {
    values = trimmedAlignedValues;
  }

  // check if the valueLength (length of values[]) has changed,
  // because if so we need to re-seed the spring function with the
  // new values array.
  if (valueLength !== values.length) {
    // set the initial spring values when the slider initialises,
    // or when values array length has changed
    springPositions = spring(
      values.map((v) => valueAsPercent(v, min, max)),
      springValues
    );
  } else {
    // update the value of the spring function for animated handles
    // whenever the values has updated
    springPositions.set(values.map((v) => valueAsPercent(v, min, max)));
  }
  // set the valueLength for the next check
  valueLength = values.length;
}

None of this executes (I've run the debugger), but the specifically problematic code for this issue is; springPositions.set(values.map((v) => valueAsPercent(v, min, max)));

I might be able to modify the code execution and explicitly set the spring store when modifying the values array... however I feel there must be more deeper problems than this.

It might be that Svelte5 just simply breaks this component and we'll need to re-write it in Svelte5.

What's funny, though, is that in my Svelte4 branch I added the prop value as an option which still works, as it's not defined in the untrack parameters?

simeydotme avatar Feb 12 '24 17:02 simeydotme

Oh so it is Svelte compiler doing this.

If the issue is with the spring library, it might not even work to convert it to Svelte 5.

I didn't see any issues regarding spring in svelte that are newer tho :/

serferdinand2 avatar Feb 13 '24 17:02 serferdinand2

no, it's not the Spring library .. its the way the "untrack" super-helper (no idea what to call that) is interpreting my code as something that doesn't need to be reactive... even though it's in a freaking reactive block. Seems the logic they are using is not fully walking my syntax tree

simeydotme avatar Feb 14 '24 11:02 simeydotme

The problem is on Svelte's side. The problem is the combination of passing in $state (which is fine-grained, compared to the old let which is not) in combination with the transformation of $: which only checks that the property as a whole, not its properties, have changed, in order to rerun. https://github.com/sveltejs/svelte/pull/10543 will fix this.

dummdidumm avatar Feb 19 '24 16:02 dummdidumm

The problem is on Svelte's side. The problem is the combination of passing in $state (which is fine-grained, compared to the old let which is not) in combination with the transformation of $: which only checks that the property as a whole, not its properties, have changed, in order to rerun. sveltejs/svelte#10543 will fix this.

Thank you so much for following up on this! 🙏 Let me know if anything I can do to help

simeydotme avatar Feb 20 '24 09:02 simeydotme

Looks like it works now after the latest svelte update!

serferdinand2 avatar Feb 23 '24 14:02 serferdinand2

amaze!

simeydotme avatar Feb 23 '24 18:02 simeydotme