ant-design / ant-design-icons

⭐ Ant Design SVG Icons
https://ant.design/components/icon/
MIT License
961 stars 582 forks source link

An alternative usage of React icon components #357

Open fuweichin opened 4 years ago

fuweichin commented 4 years ago

Current example usage

This is a basic usage of React icon components, see official documentation

import {
  HomeOutlined,
  SettingFilled,
  SmileOutlined,
  SyncOutlined,
  LoadingOutlined,
} from '@ant-design/icons';

ReactDOM.render(
  <div className="icons-list">
    <HomeOutlined />
    <SettingFilled />
    <SmileOutlined />
    <SyncOutlined spin />
    <SmileOutlined rotate={180} />
    <LoadingOutlined />
  </div>,
  mountNode,
);

The naming issue

  1. Not all XxxOutlined icons are ideographically outlined. Isn't it self-contradictory?
  2. Icon components are named with (and distinguished by) suffixes, challenging for developers who use a LTR writing system.

One possible solution

Dummy usage

import {
  outlined as Icon, // default to outlined
  filled as IconFilled,
} from '@ant-design/icons';

ReactDOM.render(
  <div className="icons-list">
    <Icon.Home />
    <IconFilled.Setting />
    <Icon.Smile />
    <Icon.Sync spin />
    <Icon.Smile rotate={180} />
    <Icon.Loading />
  </div>,
  mountNode,
);
// or replace 'Icon', 'IconFilled' with abbreviated namespaces like 'I', 'IF'

Reference implementation

Grouping icon components by suffixes Outlined Filled and TwoTone

// packages/icons-react/src/index.tsx
import * as icons from './icons';

let outlined = {};
let filled = {};
let twoTone = {};
Object.keys(icons).forEach((Component)=> {
  let {name} = Component; // XXX get component name
  if(name.endsWith('Outlined')) {
    outlined[name.slice(0, -8)] = Component;
  }else if(name.endsWith('Filled')) {
    filled[name.slice(0, -6)] = Component;
  }else if(name.endsWith('TwoTone')) {
    twoTone[name.slice(0, -7)] = Component;
  }
});

export { outlined, filled, twoTone };

Another possible solution

If the implementation above slows down module initialization, then just provide a method to generate groups as needed

Reference implementation

// packages/icons-react/src/index.tsx
import * as icons from './icons';

function createIconGroups() {
  let outlined = {};
  let filled = {};
  let twoTone = {};
  Object.keys(icons).forEach((Component)=> {
    let {name} = Component; // XXX get component name
    if(name.endsWith('Outlined')) {
      outlined[name.slice(0, -8)] = Component;
    }else if(name.endsWith('Filled')) {
      filled[name.slice(0, -6)] = Component;
    }else if(name.endsWith('TwoTone')) {
      twoTone[name.slice(0, -7)] = Component;
    }
  });
  return { outlined, filled, twoTone };
}

export { createIconGroups };

Dummy usage

import { createIconGroups } from '@ant-design/icons';
const {
  outlined: Icon, // default to outlined
  filled: IconFilled,
} = createIconGroups();

ReactDOM.render(
  <div className="icons-list">
    <Icon.Home />
    <IconFilled.Setting />
    <Icon.Smile />
    <Icon.Sync spin />
    <Icon.Smile rotate={180} />
    <Icon.Loading />
  </div>,
  mountNode,
);
// or replace 'Icon', 'IconFilled' with abbreviated namespaces like 'I', 'IF'
fuweichin commented 4 years ago

Revision

For the second solution, icon groups should be cached, so export and use getIconGroups instead of createIconGroups.

let iconGroups=null;
function getIconGroups() {
  if (iconGroups===null) {
    iconGroups=createIconGroups();
  }
  return iconGroups;
}

export { getIconGroups };
import { getIconGroups } from '@ant-design/icons';
const {
  outlined: Icon, // default to outlined
  filled: IconFilled,
} = getIconGroups();