@loke/icons
Version:
A Loke icon library package for React applications.
221 lines (153 loc) • 5.75 kB
Markdown
---
name: create-custom-icons
description: >
Build one-off icon components when no @loke/icons library icon fits. Covers
createLokeIcon(name, iconNode) factory, Icon base component with iconNode
prop, IconNode type ([SVGElementType, attrs][] with attrs as Record<string,
string>), supported SVG elements (circle, ellipse, g, line, path, polygon,
polyline, rect), LokeIcon and LokeProps exported types. Always check existing
icons and aliases first. Activate only when creating a custom icon not
available in the library.
type: core
library: '@loke/icons'
library_version: '1.0.0-alpha.1'
sources:
- 'LOKE/merchant-frontends:packages/icons/src/createLokeIcon.ts'
- 'LOKE/merchant-frontends:packages/icons/src/Icon.tsx'
- 'LOKE/merchant-frontends:packages/icons/src/types.ts'
---
# @loke/icons — Creating Custom Icons
Before creating a custom icon, check if the icon already exists in the library.
There are 107 icons with 100+ aliases. See find-icons/SKILL.md for the full
list and search tips.
## Setup
### Using createLokeIcon
```tsx
import { createLokeIcon } from "@loke/icons";
import type { IconNode } from "@loke/icons";
const customIconNode: IconNode = [
["path", { d: "M10 10 L20 20" }],
["circle", { cx: "10", cy: "10", r: "5" }],
];
const CustomIcon = createLokeIcon("custom-icon", customIconNode);
```
`createLokeIcon` returns a `ForwardRefExoticComponent` with all standard icon
props (`size`, `color`, `strokeWidth`, `absoluteStrokeWidth`, `className`).
### Using the Icon base component
```tsx
import { Icon } from "@loke/icons";
import type { IconNode } from "@loke/icons";
const iconNode: IconNode = [
["path", { d: "M12 2 L22 12 L12 22 L2 12 Z" }],
];
function MyComponent() {
return <Icon iconNode={iconNode} size={24} color="currentColor" />;
}
```
Use `Icon` directly for inline one-off icons. Use `createLokeIcon` when
you need a reusable named component.
## Core Patterns
### IconNode format
`IconNode` is an array of tuples: `[SVGElementType, Record<string, string>][]`
Supported SVG element types: `circle`, `ellipse`, `g`, `line`, `path`,
`polygon`, `polyline`, `rect`.
All attribute values must be strings:
```tsx
import type { IconNode } from "@loke/icons";
const diamondIcon: IconNode = [
["polygon", { points: "12 2, 22 12, 12 22, 2 12" }],
];
const targetIcon: IconNode = [
["circle", { cx: "12", cy: "12", r: "10" }],
["circle", { cx: "12", cy: "12", r: "6" }],
["circle", { cx: "12", cy: "12", r: "2" }],
];
```
### Typing custom icons
```tsx
import { createLokeIcon } from "@loke/icons";
import type { IconNode, LokeIcon } from "@loke/icons";
const node: IconNode = [["path", { d: "M5 12h14" }]];
const HorizontalLine = createLokeIcon("horizontal-line", node);
// HorizontalLine is typed as LokeIcon (ForwardRefExoticComponent)
// No explicit type annotation needed — inferred from createLokeIcon
```
## Common Mistakes
### CRITICAL Hand-writing inline SVG instead of using the library
Wrong:
```tsx
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
<path d="M9 18l6-6-6-6" />
</svg>
```
Correct:
```tsx
import { ChevronRight } from "@loke/icons";
<ChevronRight size={24} />
```
Always check the icon list and aliases before creating custom icons or writing inline SVG. The library has 107 icons covering common UI needs.
Source: maintainer interview
### HIGH Using unsupported SVG element types
Wrong:
```tsx
const node: IconNode = [
["text", { x: "10", y: "20" }],
];
```
Correct:
```tsx
const node: IconNode = [
["path", { d: "M10 10 L20 20" }],
];
```
`IconNode` only supports 8 SVG element types: `circle`, `ellipse`, `g`, `line`, `path`, `polygon`, `polyline`, `rect`. Elements like `text`, `image`, `use`, `defs`, `clipPath` are not supported.
Source: src/types.ts — SVGElementType union
### HIGH Passing numeric attribute values
Wrong:
```tsx
const node: IconNode = [
["circle", { cx: 12, cy: 12, r: 5 }],
];
```
Correct:
```tsx
const node: IconNode = [
["circle", { cx: "12", cy: "12", r: "5" }],
];
```
`IconNode` attrs are typed as `Record<string, string>`. All attribute values must be strings. Passing numbers causes a TypeScript error.
Source: src/types.ts
### HIGH Not checking if icon already exists
Wrong:
```tsx
// Creating a custom checkmark icon
const checkNode: IconNode = [
["polyline", { points: "20 6 9 17 4 12" }],
];
const CustomCheck = createLokeIcon("custom-check", checkNode);
```
Correct:
```tsx
// Check already exists in the library
import { Check } from "@loke/icons";
```
The library has 107 icons with 100+ aliases including Material UI-style names. Search the icon list before creating custom icons.
Source: maintainer interview
### MEDIUM Typing createLokeIcon result as React.FC
Wrong:
```tsx
import type { LokeProps } from "@loke/icons";
const MyIcon: React.FC<LokeProps> = createLokeIcon("my-icon", node);
```
Correct:
```tsx
const MyIcon = createLokeIcon("my-icon", node);
```
`createLokeIcon` returns a `ForwardRefExoticComponent`, not a function component. Let TypeScript infer the type.
Source: src/createLokeIcon.ts
### HIGH Tension: Existing icons vs custom creation
Agents default to creating custom icons when an existing icon with an alias would suffice. This adds maintenance burden and misses the library's consistent styling, accessibility defaults, and CSS class naming.
See also: find-icons/SKILL.md — search icons and aliases before creating custom
See also: find-icons/SKILL.md — verify icon exists before creating custom
See also: use-icons/SKILL.md — how to use existing icons
See also: add-icons/SKILL.md — if the icon is reusable, add it to the library instead