Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to Svelte 5 #716

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Conversation

kodaicoder
Copy link

@kodaicoder kodaicoder commented Nov 20, 2024

It's time for Svelte5 😆

I has re-writing a Select component and all +page.svelte to using a Svelte 5 rune mode so many $effect has been used without using any $derived that should been reviewing and change in the future if it not affected a core function

Issue waiting to solve

Even the core function working great but it still have some issue that need attention

  • on multi-item-checkboxes page there will be some infinite looping happen on $effect after selecting 1 of a items

  • onvirtual-list page there will be problem because svelte-tiny-virtual-list package still using svelte 4 then it can not passing snippet to render in there children , for now it will not show any error but the visualize will not show a list of items to be picked.

  • a problem that list of Select component not scrolling to a selected item

  • I didn't change README.md too then please using on Website as a document for now.

BTW this PR still have some rough edge and need a community to make it shine✨

Copy link

vercel bot commented Nov 20, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
svelte-select ❌ Failed (Inspect) Nov 20, 2024 8:49am

@kodaicoder
Copy link
Author

Oh, and another thing
I just has adding a most request function of the select that will made justValue
two way bindable and working as setter of data
you can see in use-just-value page

thank you for #641 for a idea on that

@@ -26,7 +28,6 @@ export default function filter({
return filterSelectedItems ? x[itemId] === item[itemId] : false;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be simplified

Current:

 matchesFilter = !value.some((x) => {
                return filterSelectedItems ? x[itemId] === item[itemId] : false;
            });

To:
matchesFilter = !value.some((x) => filterSelectedItems && x[itemId] === item[itemId]);

});
$effect(() => {
computeIsChecked(checked);
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check if these can be changed to use $derived states without any warnings or errors, then you won't have $effect at all and no infinite loops

Current:

 let value = $state([]);
    let checked = $state([]);
    let isChecked = $state({});
    $: computeValue(checked);
    $: computeIsChecked(checked);
    $effect(() => {
        computeValue(checked);
    });
    $effect(() => {
        computeIsChecked(checked);
    });
    function computeIsChecked() {
        isChecked = {};
        checked.forEach((c) => (isChecked[c] = true));
    }
    function computeValue() {
        value = checked.map((c) => items.find((i) => i.value === c));
    }

To


    let checked = $state([]);
    let value = $derived.by(()=> checked.map((c) => items.find((i) => i.value === c)));
    let isChecked = $derived.by(()=> {
        let r = {};
	checked.forEach((c) => (r[c] = true))
        return r;   
    });

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cause of the infinite loop does not coming from a $effect that using on a +page.svelte because even I try comment out both of $effect in +page.svelte a issue of infinite loop still persist.

but dont be worry I will try tracking on this issue because it a last page that svelte-select should work 😁

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well either way still it might help reduce lines of code and complexity, if what I proposed works as expected

</div>
onhoverItem={(e) => handleHover(e.detail)}>
{#snippet listSnippet(filteredItems)}
{#if filteredItems && filteredItems.length > 0}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could simplify this

Current:

 {#if filteredItems && filteredItems.length > 0}
            <VirtualList width="100%" height={200} itemCount={filteredItems.length} itemSize={30}>

To:


 {@const itemCount = filteredItems?.length ?? 0;
 {#if itemCount > 0}
            <VirtualList width="100%" height={200} {itemCount} itemSize={30}>

@go-aegian
Copy link

go-aegian commented Nov 20, 2024

I added some minor reviews if it helps

@kodaicoder
Copy link
Author

@go-aegian latest reply is that a svelte-select project ?
I think it a svelte-flatpickr (datepicker) project.
🤔

@go-aegian
Copy link

@go-aegian latest reply is that a svelte-select project ? I think it a svelte-flatpickr (datepicker) project. 🤔

You are right sorry I got confused as I had trouble with that library too. Svelte 5 causing problems in the community for sure.

@@ -74,7 +74,7 @@
}

.list .list-group-title {
@apply text-gray-400 cursor-default text-sm font-medium h-10 leading-10 px-5 overflow-ellipsis whitespace-nowrap uppercase;
@apply text-slate-800 cursor-default text-sm font-medium h-10 leading-10 px-5 overflow-ellipsis whitespace-nowrap uppercase;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of whether this is a better choice than the other gray, you should not sneak changes like this because this PR is just for Svelte v5, right?

This change can be discussed and treated outside of the Svelte v5 migration context.

if (inputAttributes || !searchable) assignInputAttributes();
});
});
$effect(() => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$effect(() => {
onMount(() => {

An effect that doesn't track anything is just going to run once, when mounting.

untrack(() => (hasValue = multiple ? value && value?.length > 0 : !!value));
});
$effect(() => {
hideSelectedItem = hasValue && filterText.length > 0;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hideSelectedItem can be a $derived.

hideSelectedItem = hasValue && filterText.length > 0;
});
$effect(() => {
showClear = hasValue && clearable && !disabled && !loading;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showClear can be a $derived.

showClear = hasValue && clearable && !disabled && !loading;
});
$effect(() => {
ariaSelection = value ? handleAriaSelection(multiple) : '';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ariaSelection can be a $derived.

ariaSelection = value ? handleAriaSelection(multiple) : '';
});
$effect(() => {
ariaContext = handleAriaContent({ filteredItems, hoverItemIndex, focused, listOpen });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ariaContext has no use. This is either a mistake, or is really not needed. If needed, it can be a $derived.

if (listOpen && container && list) setListWidth();
});
$effect(() => {
scrollToHoverItem = hoverItemIndex;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scrollToHoverItem seems unused right now. Its former usage is commented now. Error? Not needed anymore? Also this is weird. Can't its job be done with hoverItemIndex? Why this copy?

Comment on lines +102 to +111
oninput = () => {},
onfilter = () => {},
onclear = () => {},
onfocus = () => {},
onchange = () => {},
onselect = () => {},
onblur = () => {},
onhoveritem = () => {},
onerror = () => {},
onloaded = () => {},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let these be undefined, and then in code use ?.() to call them. Example: onfocus?.().

onhoveritem = () => {},
onerror = () => {},
onloaded = () => {},
...rest
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is only used to carry rest.class. I'd just remove and simply add the class prop.

if (disabled) return;
if (filterText.length > 0) return listOpen = true;
if (filterText && filterText.length > 0) return (listOpen = true);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (filterText && filterText.length > 0) return (listOpen = true);
if (filterText?.length ?? 0 > 0) return (listOpen = true);

As it is, while the result is unchanged, incorrectly filters out the empty string value, to which one can query for its length.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants