react-native-reusables icon indicating copy to clipboard operation
react-native-reusables copied to clipboard

[ FEATURE ] Automate Lucide Icon additions

Open stephendpmurphy opened this issue 1 year ago • 11 comments
trafficstars

Is your feature request related to a problem? Please describe. To remove a bit of the leg work of adding a new icon it would nice if part of the CLI was essentially a helper that takes the Icon name and creates the necessary lib/icons/*.ts file with the wrapped export.

Describe the solution you'd like Add a new icon command alongside add which takes Lucid icon names as an argument and creates the necessary .ts file.

Describe alternatives you've considered Currently using a script like this to automate the creation

#!/bin/bash

if [ -z "$1" ]; then
  echo "Usage: addIcon.sh <iconName>"
  exit 1
fi

iconName=$1

# Create the new icon file under `lib/icons`
iconPath="src/lib/icons/${iconName}.ts"
touch $iconPath

# Write the icon content
echo "import {${iconName}} from 'lucide-react-native';" >> $iconPath
echo "import {iconWithClassName} from './iconWithClassName';" >> $iconPath
echo "iconWithClassName(${iconName});" >> $iconPath
echo "export {${iconName}};" >> $iconPath

Additional context I've always been interested in creating a node based CLI script and would be happy to tackle this addition if that would be OK.

stephendpmurphy avatar Aug 05 '24 18:08 stephendpmurphy

This would be great! I am also having some troubles with auto imports from the icon exports, have you had any issues with that?

trevorpfiz avatar Aug 06 '24 02:08 trevorpfiz

Check this out https://github.com/mrzachnugent/react-native-reusables/issues/198, replace lucide with iconify and only one export needed. Iconify includes lucide and so much more https://icon-sets.iconify.design/

RajeshPandey057 avatar Aug 12 '24 07:08 RajeshPandey057

I am open to this. It will need to be another command than "add" since there are some conflicts between the components and the lucide-icon names.

mrzachnugent avatar Aug 19 '24 17:08 mrzachnugent

another suggestion: instead of creating separate files for each icons, create a single icons.tsx and increment the icons there. For example:

import {
  Home,
  Library,
  UserPlus,
  Layers,
  ListPlus,
} from 'lucide-react-native';
import { iconWithClassName } from './iconWithClassName';


iconWithClassName(Home);
iconWithClassName(Library);
iconWithClassName(UserPlus);
iconWithClassName(Layers);
iconWithClassName(ListPlus);

export {
  Home,
  Library,
  UserPlus,
  Layers,
  ListPlus,
};

after that just import { Home, Layers} from '../../lib/icons/icons';

This way the codebase will remain neat.

helix-77 avatar Sep 05 '24 10:09 helix-77

@helix-77 That's how it was at first, the problem I faced was with the CLI when adding icons. It would need to parse the file to see if the icon is already there, add text in 3 places, and if the user manually changed something it could stop working so it was easier to add a file for each icon.

React-native-reusables is meant as a quick start for your projects and it is encouraged that you make any changes you need. So, by all means, modify your the icons in your codebase to look like your suggestion.

mrzachnugent avatar Sep 05 '24 12:09 mrzachnugent

We can maybe utilise component.json here by adding an 'icons' field and then on each run we can just check that key and regenerate whole file without needing to parse it.

RajeshPandey057 avatar Sep 13 '24 01:09 RajeshPandey057

I am open to this. It will need to be another command than "add" since there are some conflicts between the components and the lucide-icon names.

sorry for falling off the deep end @mrzachnugent. I'm still interested in tackling this and I'll start working something up.

stephendpmurphy avatar Oct 30 '24 01:10 stephendpmurphy

I have gone with a different approach and it's working fine to me

I create a component named lucide-icon.tsx that allows me to use any lucide icon like <LucideIcon name="Check" className="size-4 text-accent-foreground" />

Notice that the name prop does have type safety

import { icons } from 'lucide-react-native';

import { iconWithClassName } from './iconWithClassName';

const LucideIcon = ({
  name,
  size,
  strokeWidth = 2,
  className,
}: {
  name: keyof typeof icons;
  size?: number;
  strokeWidth?: number;
  className?: string;
}) => {
  const Icon = icons[name];
  iconWithClassName(Icon);
  return <Icon size={size} strokeWidth={strokeWidth} className={className} />;
};

export { LucideIcon };

Dosbodoke avatar Feb 04 '25 03:02 Dosbodoke

If using the generic approach, please take this warning into consideration: https://lucide.dev/guide/packages/lucide-react-native#one-generic-icon-component

I would also suggest rapping the LucideIcon with the iconWithClassName function. In the snippet above, the iconWithClassName function is called every time the component renders.

On another note, to fix allowing the icons to receive a class name, I've been thinking about adding a patch-package but haven't looked into it. That way, we could import directly from 'lucide-react-native' and we could get ride of the /icons folder.

mrzachnugent avatar Feb 04 '25 13:02 mrzachnugent

What do you mean by

I would also suggest rapping the LucideIcon with the iconWithClassName function. In the snippet above, the iconWithClassName function is called every time the component renders.

Tried it and didn't worked. I couldn't find any other way to do it besides the one that I commented.

And when I read #341 found that it can be way harder than I tough. What do you suggets for now?

Dosbodoke avatar Feb 10 '25 03:02 Dosbodoke

Fwiw, here's a turbo generator for adding these icons:

// turbo/generators/config.ts

import type { PlopTypes } from '@turbo/gen'

export default function generator(plop: PlopTypes.NodePlopAPI): void {
plop.setGenerator('icon', {
    description: 'Create a new icon component from Lucide icons',
    prompts: [
      {
        type: 'input',
        name: 'name',
        message: 'What is the name of your icon? (must match Lucide icon name)',
        validate: (input: string) => {
          if (input.length === 0) {
            return 'Icon name is required'
          }
          return true
        },
      },
    ],
    actions: [
      {
        type: 'add',
        path: '{{ turbo.paths.root }}/packages/ui/src//lib/icons/{{pascalCase name}}.tsx',
        templateFile: 'templates/icon.tsx.hbs',
      },
      {
        type: 'append',
        path: '{{ turbo.paths.root }}/packages/ui/src/primitives/lib/icons/index.ts',
        pattern: /$/,
        template: "export * from './{{pascalCase name}}'\n",
      },
    ],
  })
}
{{!-- turbo/generators/templates/icon.tsx.hbs --}}

import { {{pascalCase name}} } from 'lucide-react-native'
import { iconWithClassName } from './iconWithClassName'

iconWithClassName({{pascalCase name}})
export { {{pascalCase name}} } 

Tellefsonjr avatar Apr 19 '25 04:04 Tellefsonjr

Instead of automation, there is now a single Icon component : https://github.com/founded-labs/react-native-reusables/blob/main/packages/registry/src/new-york/components/ui/icon.tsx

mrzachnugent avatar Aug 22 '25 17:08 mrzachnugent