feathericons / react-feather

React component for Feather icons
https://npm.im/react-feather
MIT License
1.93k stars 126 forks source link

Provide Typescript definitions [fixes #13] #18

Closed alaz closed 6 years ago

alaz commented 6 years ago

The initial version of definitions courtesy of @sgoll.

macklinu commented 6 years ago

This looks like a great start. I think per https://github.com/carmelopullara/react-feather/issues/13#issuecomment-382337691, this would need to be generated by the build script. Below is a local diff that generates the types you've created via running yarn build. I'm happy to PR this into this project or your PR branch, @alaz, if I can be of help. 😄

diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..2f173e0
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,5 @@
+{
+  "singleQuote": true,
+  "trailingComma": "es5",
+  "bracketSpacing": true
+}
diff --git a/bin/build.js b/bin/build.js
index 11705d8..0dda0e9 100644
--- a/bin/build.js
+++ b/bin/build.js
@@ -8,12 +8,29 @@ const prettier = require('prettier');

 const rootDir = path.join(__dirname, '..');

+const initialTypeDefinitions = `/// <reference types="react" />
+import { ComponentType, SVGAttributes } from 'react';
+
+interface Props extends SVGAttributes<SVGElement> {
+  color?: string;
+  size?: string | number;
+}
+
+type Icon = ComponentType<Props>;
+`;
+
 glob(`${rootDir}/src/feather/icons/**.svg`, (err, icons) => {
   fs.writeFileSync(path.join(rootDir, 'src', 'index.js'), '', 'utf-8');
+  fs.writeFileSync(
+    path.join(rootDir, 'src', 'index.d.ts'),
+    initialTypeDefinitions,
+    'utf-8'
+  );

-  icons.forEach((i) => {
+  icons.forEach(i => {
     const svg = fs.readFileSync(i, 'utf-8');
     const id = path.basename(i, '.svg');
+    const ComponentName = uppercamelcase(id);
     const $ = cheerio.load(svg, {
       xmlMode: true,
     });
@@ -21,9 +38,11 @@ glob(`${rootDir}/src/feather/icons/**.svg`, (err, icons) => {
     const location = path.join(rootDir, 'src/icons', fileName);

     $('*').each((index, el) => {
-      Object.keys(el.attribs).forEach((x) => {
+      Object.keys(el.attribs).forEach(x => {
         if (x.includes('-')) {
-          $(el).attr(camelcase(x), el.attribs[x]).removeAttr(x);
+          $(el)
+            .attr(camelcase(x), el.attribs[x])
+            .removeAttr(x);
         }
         if (x === 'stroke') {
           $(el).attr(x, 'currentColor');
@@ -39,20 +58,19 @@ glob(`${rootDir}/src/feather/icons/**.svg`, (err, icons) => {
       import React from 'react';
       import PropTypes from 'prop-types';

-      const ${uppercamelcase(id)} = (props) => {
+      const ${ComponentName} = (props) => {
         const { color, size, ...otherProps } = props;
         return (
-          ${
-            $('svg').toString()
-              .replace(new RegExp('stroke="currentColor"', 'g'), 'stroke={color}')
-              .replace('width="24"', 'width={size}')
-              .replace('height="24"', 'height={size}')
-              .replace('otherProps="..."', '{...otherProps}')
-          }
+          ${$('svg')
+            .toString()
+            .replace(new RegExp('stroke="currentColor"', 'g'), 'stroke={color}')
+            .replace('width="24"', 'width={size}')
+            .replace('height="24"', 'height={size}')
+            .replace('otherProps="..."', '{...otherProps}')}
         )
       };

-      ${uppercamelcase(id)}.propTypes = {
+      ${ComponentName}.propTypes = {
         color: PropTypes.string,
         size: PropTypes.oneOfType([
           PropTypes.string,
@@ -60,12 +78,12 @@ glob(`${rootDir}/src/feather/icons/**.svg`, (err, icons) => {
         ]),
       }

-      ${uppercamelcase(id)}.defaultProps = {
+      ${ComponentName}.defaultProps = {
         color: 'currentColor',
         size: '24',
       }

-      export default ${uppercamelcase(id)}
+      export default ${ComponentName}
     `;

     const component = prettier.format(element, {
@@ -77,7 +95,18 @@ glob(`${rootDir}/src/feather/icons/**.svg`, (err, icons) => {

     fs.writeFileSync(location, component, 'utf-8');

-    const exportString = `export ${uppercamelcase(id)} from './icons/${id}';\r\n`;
-    fs.appendFileSync(path.join(rootDir, 'src', 'index.js'), exportString, 'utf-8');
+    const exportString = `export ${ComponentName} from './icons/${id}';\r\n`;
+    fs.appendFileSync(
+      path.join(rootDir, 'src', 'index.js'),
+      exportString,
+      'utf-8'
+    );
+
+    const exportTypeString = `export const ${ComponentName}: Icon;\n`;
+    fs.appendFileSync(
+      path.join(rootDir, 'src', 'index.d.ts'),
+      exportTypeString,
+      'utf-8'
+    );
   });
 });
diff --git a/src/index.d.ts b/src/index.d.ts
new file mode 100644
index 0000000..dc04a0d
--- /dev/null
+++ b/src/index.d.ts
@@ -0,0 +1,275 @@
+/// <reference types="react" />
+import { ComponentType, SVGAttributes } from 'react';
+
+interface Props extends SVGAttributes<SVGElement> {
+  color?: string;
+  size?: string | number;
+}
+
+type Icon = ComponentType<Props>;
+export const Activity: Icon;
+export const Airplay: Icon;
+export const AlertCircle: Icon;
+export const AlertOctagon: Icon;
+export const AlertTriangle: Icon;
+export const AlignCenter: Icon;
+export const AlignJustify: Icon;
+export const AlignLeft: Icon;
+export const AlignRight: Icon;
+export const Anchor: Icon;
+export const Aperture: Icon;
+export const Archive: Icon;
+export const ArrowDownCircle: Icon;
+export const ArrowDownLeft: Icon;
+export const ArrowDownRight: Icon;
+export const ArrowDown: Icon;
+export const ArrowLeftCircle: Icon;
+export const ArrowLeft: Icon;
+export const ArrowRightCircle: Icon;
+export const ArrowRight: Icon;
+export const ArrowUpCircle: Icon;
+export const ArrowUpLeft: Icon;
+export const ArrowUpRight: Icon;
+export const ArrowUp: Icon;
+export const AtSign: Icon;
+export const Award: Icon;
+export const BarChart2: Icon;
+export const BarChart: Icon;
+export const BatteryCharging: Icon;
+export const Battery: Icon;
+export const BellOff: Icon;
+export const Bell: Icon;
+export const Bluetooth: Icon;
+export const Bold: Icon;
+export const BookOpen: Icon;
+export const Book: Icon;
+export const Bookmark: Icon;
+export const Box: Icon;
+export const Briefcase: Icon;
+export const Calendar: Icon;
+export const CameraOff: Icon;
+export const Camera: Icon;
+export const Cast: Icon;
+export const CheckCircle: Icon;
+export const CheckSquare: Icon;
+export const Check: Icon;
+export const ChevronDown: Icon;
+export const ChevronLeft: Icon;
+export const ChevronRight: Icon;
+export const ChevronUp: Icon;
+export const ChevronsDown: Icon;
+export const ChevronsLeft: Icon;
+export const ChevronsRight: Icon;
+export const ChevronsUp: Icon;
+export const Chrome: Icon;
+export const Circle: Icon;
+export const Clipboard: Icon;
+export const Clock: Icon;
+export const CloudDrizzle: Icon;
+export const CloudLightning: Icon;
+export const CloudOff: Icon;
+export const CloudRain: Icon;
+export const CloudSnow: Icon;
+export const Cloud: Icon;
+export const Code: Icon;
+export const Codepen: Icon;
+export const Command: Icon;
+export const Compass: Icon;
+export const Copy: Icon;
+export const CornerDownLeft: Icon;
+export const CornerDownRight: Icon;
+export const CornerLeftDown: Icon;
+export const CornerLeftUp: Icon;
+export const CornerRightDown: Icon;
+export const CornerRightUp: Icon;
+export const CornerUpLeft: Icon;
+export const CornerUpRight: Icon;
+export const Cpu: Icon;
+export const CreditCard: Icon;
+export const Crop: Icon;
+export const Crosshair: Icon;
+export const Database: Icon;
+export const Delete: Icon;
+export const Disc: Icon;
+export const DollarSign: Icon;
+export const DownloadCloud: Icon;
+export const Download: Icon;
+export const Droplet: Icon;
+export const Edit2: Icon;
+export const Edit3: Icon;
+export const Edit: Icon;
+export const ExternalLink: Icon;
+export const EyeOff: Icon;
+export const Eye: Icon;
+export const Facebook: Icon;
+export const FastForward: Icon;
+export const Feather: Icon;
+export const FileMinus: Icon;
+export const FilePlus: Icon;
+export const FileText: Icon;
+export const File: Icon;
+export const Film: Icon;
+export const Filter: Icon;
+export const Flag: Icon;
+export const FolderMinus: Icon;
+export const FolderPlus: Icon;
+export const Folder: Icon;
+export const Gift: Icon;
+export const GitBranch: Icon;
+export const GitCommit: Icon;
+export const GitMerge: Icon;
+export const GitPullRequest: Icon;
+export const Github: Icon;
+export const Gitlab: Icon;
+export const Globe: Icon;
+export const Grid: Icon;
+export const HardDrive: Icon;
+export const Hash: Icon;
+export const Headphones: Icon;
+export const Heart: Icon;
+export const HelpCircle: Icon;
+export const Home: Icon;
+export const Image: Icon;
+export const Inbox: Icon;
+export const Info: Icon;
+export const Instagram: Icon;
+export const Italic: Icon;
+export const Layers: Icon;
+export const Layout: Icon;
+export const LifeBuoy: Icon;
+export const Link2: Icon;
+export const Link: Icon;
+export const Linkedin: Icon;
+export const List: Icon;
+export const Loader: Icon;
+export const Lock: Icon;
+export const LogIn: Icon;
+export const LogOut: Icon;
+export const Mail: Icon;
+export const MapPin: Icon;
+export const Map: Icon;
+export const Maximize2: Icon;
+export const Maximize: Icon;
+export const Menu: Icon;
+export const MessageCircle: Icon;
+export const MessageSquare: Icon;
+export const MicOff: Icon;
+export const Mic: Icon;
+export const Minimize2: Icon;
+export const Minimize: Icon;
+export const MinusCircle: Icon;
+export const MinusSquare: Icon;
+export const Minus: Icon;
+export const Monitor: Icon;
+export const Moon: Icon;
+export const MoreHorizontal: Icon;
+export const MoreVertical: Icon;
+export const Move: Icon;
+export const Music: Icon;
+export const Navigation2: Icon;
+export const Navigation: Icon;
+export const Octagon: Icon;
+export const Package: Icon;
+export const Paperclip: Icon;
+export const PauseCircle: Icon;
+export const Pause: Icon;
+export const Percent: Icon;
+export const PhoneCall: Icon;
+export const PhoneForwarded: Icon;
+export const PhoneIncoming: Icon;
+export const PhoneMissed: Icon;
+export const PhoneOff: Icon;
+export const PhoneOutgoing: Icon;
+export const Phone: Icon;
+export const PieChart: Icon;
+export const PlayCircle: Icon;
+export const Play: Icon;
+export const PlusCircle: Icon;
+export const PlusSquare: Icon;
+export const Plus: Icon;
+export const Pocket: Icon;
+export const Power: Icon;
+export const Printer: Icon;
+export const Radio: Icon;
+export const RefreshCcw: Icon;
+export const RefreshCw: Icon;
+export const Repeat: Icon;
+export const Rewind: Icon;
+export const RotateCcw: Icon;
+export const RotateCw: Icon;
+export const Rss: Icon;
+export const Save: Icon;
+export const Scissors: Icon;
+export const Search: Icon;
+export const Send: Icon;
+export const Server: Icon;
+export const Settings: Icon;
+export const Share2: Icon;
+export const Share: Icon;
+export const ShieldOff: Icon;
+export const Shield: Icon;
+export const ShoppingBag: Icon;
+export const ShoppingCart: Icon;
+export const Shuffle: Icon;
+export const Sidebar: Icon;
+export const SkipBack: Icon;
+export const SkipForward: Icon;
+export const Slack: Icon;
+export const Slash: Icon;
+export const Sliders: Icon;
+export const Smartphone: Icon;
+export const Speaker: Icon;
+export const Square: Icon;
+export const Star: Icon;
+export const StopCircle: Icon;
+export const Sun: Icon;
+export const Sunrise: Icon;
+export const Sunset: Icon;
+export const Tablet: Icon;
+export const Tag: Icon;
+export const Target: Icon;
+export const Terminal: Icon;
+export const Thermometer: Icon;
+export const ThumbsDown: Icon;
+export const ThumbsUp: Icon;
+export const ToggleLeft: Icon;
+export const ToggleRight: Icon;
+export const Trash2: Icon;
+export const Trash: Icon;
+export const TrendingDown: Icon;
+export const TrendingUp: Icon;
+export const Triangle: Icon;
+export const Truck: Icon;
+export const Tv: Icon;
+export const Twitter: Icon;
+export const Type: Icon;
+export const Umbrella: Icon;
+export const Underline: Icon;
+export const Unlock: Icon;
+export const UploadCloud: Icon;
+export const Upload: Icon;
+export const UserCheck: Icon;
+export const UserMinus: Icon;
+export const UserPlus: Icon;
+export const UserX: Icon;
+export const User: Icon;
+export const Users: Icon;
+export const VideoOff: Icon;
+export const Video: Icon;
+export const Voicemail: Icon;
+export const Volume1: Icon;
+export const Volume2: Icon;
+export const VolumeX: Icon;
+export const Volume: Icon;
+export const Watch: Icon;
+export const WifiOff: Icon;
+export const Wifi: Icon;
+export const Wind: Icon;
+export const XCircle: Icon;
+export const XSquare: Icon;
+export const X: Icon;
+export const Youtube: Icon;
+export const ZapOff: Icon;
+export const Zap: Icon;
+export const ZoomIn: Icon;
+export const ZoomOut: Icon;
alaz commented 6 years ago

@macklinu agree, this looks much better than hard-coded list of definitions. I've closed my PR, please provide yours 🎩