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

feat(@lucide/svelte): Lucide svelte 5 package #2753

Merged
merged 24 commits into from
Mar 7, 2025
Merged

Conversation

ericfennis
Copy link
Member

For more info see #2727

This PR creates a new package: @lucide/svelte.

aurelienrichard and others added 8 commits January 11, 2025 15:33
* Update peerDependencies to support Svelte 5

* Bump svelte version

* Bump @testing-library/svelte version

* Remove alias in vitest.config.ts that causes tests to fail due to deprecated svelte/internal API

* Convert to svelte 5 syntax

* Bump vite & @sveltejs/vite-plugin-svelte version

* Fix error during render when children prop is missing & fix components being mounted on the server during tests

* Update test snapshots to reflect the differences in the html generated by svelte 5

* Convert class attribute to new array syntax with built-in clsx

* Convert export template to svelte 5 syntax
* Update peerDependencies to support Svelte 5

* Bump svelte version

* Bump @testing-library/svelte version

* Remove alias in vitest.config.ts that causes tests to fail due to deprecated svelte/internal API

* Convert to svelte 5 syntax

* Bump vite & @sveltejs/vite-plugin-svelte version

* Fix error during render when children prop is missing & fix components being mounted on the server during tests

* Update test snapshots to reflect the differences in the html generated by svelte 5

* Convert class attribute to new array syntax with built-in clsx

* Convert export template to svelte 5 syntax
@ericfennis ericfennis marked this pull request as draft January 24, 2025 15:59
@github-actions github-actions bot added 📦 dependencies Pull requests that update a dependency file 🧣 svelte package About the Svelte package labels Jan 24, 2025
@github-actions github-actions bot added 📖 documentation Improvements or additions to documentation 🌍 site Has to do something with the Lucide website labels Jan 24, 2025
@woconnor
Copy link

Hello, thanks for putting this together. I would like to try Lucide with Svelte 5 but I am getting a TypeScript error when I try to import an icon (any icon) from @lucide/svelte version 0.474.0-rc.0:

Module '"@lucide/svelte"' has no exported member 'House'. ts (2305)

I also noticed a test is failing which might be related?

Error: Failed to resolve import "./icons/index" from "src/lucide-svelte.ts". Does the file exist?

@ericfennis
Copy link
Member Author

@woconnor Thanks for checking, made some fixes.
New version on @lucide/svelte@0.474.0-rc.1

@aurelienrichard
Copy link
Contributor

aurelienrichard commented Feb 5, 2025

Thanks for the work @ericfennis!
I have tried the new package, it runs smoothly in runes mode. The only trouble I ran into is a type error when replicating this example from the docs. I couldn't get to the bottom of what was causing it, but I updated the code like so:

<script lang="ts">
	import { Home, Library, Cog } from '@lucide/svelte';

	const menuItems = [
		{
			name: 'Home',
			href: '/',
			icon: Home
		},
		{
			name: 'Blog',
			href: '/blog',
			icon: Library
		},
		{
			name: 'Projects',
			href: '/projects',
			icon: Cog
		}
	] as const;
</script>

{#each menuItems as item}
	{@const Icon = item.icon}
	<!-- const Icon: typeof Home | typeof Library | typeof Cog -->
	<Icon />
	<a href={item.href}>
		<span>{item.name}</span>
	</a>
{/each}

It got rid of the error and I believe gives better type information as well, but I'll leave it up to you to be the judge of that.

The other thing I noticed is that the component type definitions generated during build use the SvelteComponent type, which is supposed to be deprecated. I'm not sure why this is the case.

@OllieJT
Copy link

OllieJT commented Feb 5, 2025

Thanks for the work @ericfennis! I have tried the new package, it runs smoothly in runes mode. The only trouble I ran into is a type error when replicating this example from the docs. I couldn't get to the bottom of what was causing it, but I updated the code like so:

<script lang="ts">
	import { Home, Library, Cog } from '@lucide/svelte';

	const menuItems = [
		{
			name: 'Home',
			href: '/',
			icon: Home
		},
		{
			name: 'Blog',
			href: '/blog',
			icon: Library
		},
		{
			name: 'Projects',
			href: '/projects',
			icon: Cog
		}
	] as const;
</script>

{#each menuItems as item}
	{@const Icon = item.icon}
	<!-- const Icon: typeof Home | typeof Library | typeof Cog -->
	<Icon />
	<a href={item.href}>
		<span>{item.name}</span>
	</a>
{/each}

It got rid of the error and I believe gives better type information as well, but I'll leave it up to you to be the judge of that.

The other thing I noticed is that the component type definitions generated during build use the SvelteComponent type, which is supposed to be deprecated. I'm not sure why this is the case.

Yes, I ran into this too. Svelte has moved to the new Component type. You can find the documentation here: https://svelte.dev/docs/svelte/typescript#The-Component-type

Also, side note @aurelienrichard - you can just render <item.icon />. It isn't valid html to have a . in an element name, so Svelte knows you're referring to a component rather than a custom element.

@woconnor
Copy link

woconnor commented Feb 8, 2025

Thanks for the fixes @ericfennis. I am also running into the type error that the icons do not extend the Svelte 5 Component type.

Here's the output from svelte-check when I pass an icon as a prop expecting a Component, as in <Button icon={House} [...] />:

Error: Type 'typeof House' is not assignable to type 'Component<{}, {}, string>'.
  Type 'typeof House' provides no match for the signature '(this: void, internals: Brand<"ComponentInternals">, props: {}): { $on?(type: string, callback: (e: any) => void): () => void; $set?(props: Partial<{}>): void; }'. (ts)

Apart from this type error, everything seems to work fine at runtime.

@ericfennis
Copy link
Member Author

@woconnor Can you maybe post your Button component? I will check what is going on.

@AirZona
Copy link

AirZona commented Feb 17, 2025

Any update on this package being updated to svelte 5?

@woconnor
Copy link

@woconnor Can you maybe post your Button component? I will check what is going on.

Here's the component. As a workaround, I let the icon props type be either Component (Svelte 5) or ComponentType (deprecated Svelte 4).

<script lang="ts">
  import type { Component, ComponentType } from "svelte";
  import { page } from "$app/state";

  interface Props {
    href: string;
    title: string;
    // eslint-disable-next-line @typescript-eslint/no-deprecated
    icon: Component | ComponentType;
  }
  const { href, title, icon: Icon }: Props = $props();
</script>

<a
  {href}
  data-prime={page.url.pathname == href}
  class="p-2 rounded-md flex items-center leading-none gap-3 text-grey-700 dark:text-grey-400 hover:text-primary-700 dark:hover:text-white data-prime:text-primary-700 dark:data-prime:text-white hover:bg-primary-300/25 dark:hover:bg-grey-800 data-prime:bg-primary-300/25 dark:data-prime:bg-grey-800"
>
  <Icon class="shrink-0 size-6" />
  <span class="text-sm leading-6 font-semibold">{title}</span>
</a>

To use it, an icon is imported and then passed as a prop. This works with other Svelte components, e.g. I have a Logo.svelte file that contains an SVG that I can pass as an icon. I found that I must import Lucide icons using the full path otherwise I get an error.

<script lang="ts">
  // Module '"@lucide/svelte"' has no exported member 'House'. ts (2305)
  // import { House } from "@lucide/svelte";
  import House from "@lucide/svelte/icons/house";
  import Button from "$lib/components/Button.svelte";
</script>

<Button href="/" title="Home" icon={House} />

I looked at the type declaration file node_modules/@lucide/svelte/dist/icons/house.svelte.d.ts and saw that it uses the deprecated type:

import { SvelteComponent } from "svelte";
declare const __propDef: {
    props: $$_sveltets_Props;
    events: {
        [evt: string]: CustomEvent<any>;
    };
    slots: {};
};
export type HouseProps = typeof __propDef.props;
export type HouseEvents = typeof __propDef.events;
export type HouseSlots = typeof __propDef.slots;
export default class House extends SvelteComponent<HouseProps, HouseEvents, HouseSlots> {
}
export {};

@github-actions github-actions bot added the 🎨 icon About new icons label Feb 28, 2025
@lucide-icons lucide-icons deleted a comment from github-actions bot Feb 28, 2025
@ericfennis
Copy link
Member Author

@woconnor Thanks this helped. I've fixed the types created a new version on: @lucide/svelte:0.477.0-rc.0.
During testing locally it worked great.

@ericfennis ericfennis marked this pull request as ready for review February 28, 2025 17:38
@woconnor
Copy link

woconnor commented Mar 1, 2025

Thanks @ericfennis, I confirmed that fixes my issue with the component type.

@ericfennis ericfennis merged commit aefb710 into main Mar 7, 2025
27 of 28 checks passed
@ericfennis ericfennis deleted the svelte-5-support branch March 7, 2025 12:44
@memark
Copy link

memark commented Mar 8, 2025

I've been using lucide-svelte with Svelte 5 for some time now. Should I switch to this new package? How are they different?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📦 dependencies Pull requests that update a dependency file 📖 documentation Improvements or additions to documentation 🎨 icon About new icons 🌍 site Has to do something with the Lucide website 🧣 svelte package About the Svelte package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants