Widened React lib peer deps to fix legacy peer deps issue in host apps
All checks were successful
armco-org/icon/pipeline/head This commit looks good
All checks were successful
armco-org/icon/pipeline/head This commit looks good
This commit is contained in:
356
docs/USAGE.md
Normal file
356
docs/USAGE.md
Normal file
@@ -0,0 +1,356 @@
|
||||
# @armco/icon — Usage Guide
|
||||
|
||||
## Overview
|
||||
|
||||
`@armco/icon` is a flexible, theme-aware React Icon component. It renders icons from multiple sources: **react-icons identifiers**, SVG strings, base64-encoded SVGs, image URLs, and raw image elements. Icons fetched via identifier or URL are cached in a global registry to prevent duplicate network requests.
|
||||
|
||||
The component is a React class component wrapped with the `withTheme` HOC from `@armco/utils`, giving it automatic access to the current theme context.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @armco/icon
|
||||
```
|
||||
|
||||
Peer dependencies: `react`, `react-dom` (^18.x)
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
```tsx
|
||||
import Icon from "@armco/icon"
|
||||
|
||||
// Identifier-based (most common usage)
|
||||
<Icon icon="md.MdEdit" />
|
||||
<Icon icon="hi.HiViewBoards" />
|
||||
<Icon icon="tb.TbHomeEdit" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Icon Identifier Format
|
||||
|
||||
The most common way to use the component is with **react-icons identifiers**:
|
||||
|
||||
```
|
||||
<category>.<IconName>
|
||||
```
|
||||
|
||||
- **category** — 2–3 letter prefix matching a [react-icons](https://react-icons.github.io/react-icons/) library:
|
||||
- `ai` — Ant Design Icons
|
||||
- `bi` — Bootstrap Icons
|
||||
- `bs` — Bootstrap Icons (alt)
|
||||
- `ci` — Circum Icons
|
||||
- `cg` — css.gg
|
||||
- `di` — Devicons
|
||||
- `fa` — Font Awesome
|
||||
- `fc` — Flat Color Icons
|
||||
- `fi` — Feather Icons
|
||||
- `gi` — Game Icons
|
||||
- `go` — Github Octicons
|
||||
- `gr` — Grommet Icons
|
||||
- `hi` — Heroicons
|
||||
- `im` — IcoMoon
|
||||
- `io` — Ionicons
|
||||
- `lu` — Lucide
|
||||
- `md` — Material Design Icons
|
||||
- `pi` — Phosphor Icons
|
||||
- `ri` — Remix Icons
|
||||
- `rx` — Radix Icons
|
||||
- `si` — Simple Icons
|
||||
- `sl` — Simple Line Icons
|
||||
- `tb` — Tabler Icons
|
||||
- `ti` — Typicons
|
||||
- `vsc` — VS Code Icons
|
||||
- `wi` — Weather Icons
|
||||
|
||||
- **IconName** — the PascalCase icon name from that library.
|
||||
|
||||
### Resolution
|
||||
|
||||
When an identifier like `hi.HiViewBoards` is passed, the component:
|
||||
1. Detects it as an `identifier` type via regex: `/^[a-zA-Z0-9]{2,3}[.\/][a-zA-Z0-9]+$/`
|
||||
2. Converts dots to slashes: `hi.HiViewBoards` → `/icon/hi/HiViewBoards`
|
||||
3. Fetches the SVG from the icon server at that path
|
||||
4. Caches the result in a global `iconRegistry` (keyed by the original identifier string)
|
||||
5. Subsequent uses of the same identifier skip the network call
|
||||
|
||||
---
|
||||
|
||||
## Props API
|
||||
|
||||
### `IconProps`
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `icon` | `string \| object \| IconSource` | — | The icon source. Can be an identifier (`"hi.HiViewBoards"`), SVG string, base64 string, URL, or an `IconSource` object. |
|
||||
| `attributes` | `IconAttributes` | — | Sizing, colors, classes, and inline styles. |
|
||||
| `events` | `IconEvents` | — | Event handlers: `onClick`, `onMouseEnter`, `onMouseLeave`. |
|
||||
| `fillPath` | `boolean \| number[]` | — | Apply fill/stroke colors to specific `<path>` elements inside the SVG. `true` = all paths, `[0, 2]` = paths at those indices. |
|
||||
| `toggled` | `boolean` | `false` | Initial toggle state. Toggles on click. Affects which colors are applied. |
|
||||
| `hoverShadow` | `boolean` | `false` | Adds a box-shadow on hover. |
|
||||
| `slot` | `ArPopoverSlots` | — | Popover slot assignment (`"popover"` or `"anchor"`). |
|
||||
| `theme` | `ArThemes` | auto | Injected by `withTheme` HOC. Can be overridden. |
|
||||
|
||||
### `IconSource` (explicit type specification)
|
||||
|
||||
```ts
|
||||
interface IconSource {
|
||||
source: string | object
|
||||
type: ArIconSourceTypes // "URL" | "identifier" | "svgString" | "b64" | "raw"
|
||||
}
|
||||
```
|
||||
|
||||
Use this when you need to explicitly specify the source type instead of relying on auto-detection:
|
||||
|
||||
```tsx
|
||||
<Icon icon={{ source: "https://example.com/icon.svg", type: "URL" }} />
|
||||
```
|
||||
|
||||
### `IconAttributes`
|
||||
|
||||
```ts
|
||||
interface IconAttributes {
|
||||
height?: string // e.g., "24px", "2rem"
|
||||
width?: string
|
||||
size?: string // Shorthand — sets both height and width
|
||||
strokeWidth?: string // SVG stroke-width attribute
|
||||
colors?: {
|
||||
fillColor?: string
|
||||
strokeColor?: string
|
||||
strokeWidth?: string
|
||||
toggleFillColor?: string
|
||||
toggleStrokeColor?: string
|
||||
hoverFillColor?: string
|
||||
hoverStrokeColor?: string
|
||||
darkFillColor?: string
|
||||
darkStrokeColor?: string
|
||||
darkToggleFillColor?: string
|
||||
darkToggleStrokeColor?: string
|
||||
darkHoverFillColor?: string
|
||||
darkHoverStrokeColor?: string
|
||||
}
|
||||
styles?: CSSProperties // React inline styles applied to the SVG element
|
||||
classes?: string // CSS class names appended to the SVG element
|
||||
}
|
||||
```
|
||||
|
||||
### `IconEvents`
|
||||
|
||||
```ts
|
||||
interface IconEvents {
|
||||
onClick?: (e?: MouseEvent) => void
|
||||
onMouseEnter?: (e?: MouseEvent) => void
|
||||
onMouseLeave?: (e?: MouseEvent) => void
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Source Types
|
||||
|
||||
The component auto-detects the icon source type. Detection order:
|
||||
|
||||
| Type | Detection Rule | Example |
|
||||
|------|---------------|---------|
|
||||
| `identifier` | Matches regex `^[a-zA-Z0-9]{2,3}[./][a-zA-Z0-9]+$` | `"hi.HiViewBoards"` |
|
||||
| `URL` | Starts with `http://` or `https://` | `"https://cdn.example.com/icon.svg"` |
|
||||
| `b64` | Starts with `data:image/svg+xml;base64,` | Base64-encoded SVG data URI |
|
||||
| `svgString` | Starts with `<svg` | Raw SVG markup string |
|
||||
| `raw` | `typeof source === "object"` (not IconSource) | React element or image object |
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic — Identifier
|
||||
|
||||
```tsx
|
||||
import Icon from "@armco/icon"
|
||||
|
||||
<Icon icon="hi.HiViewBoards" />
|
||||
<Icon icon="md.MdDelete" />
|
||||
<Icon icon="tb.TbHomeEdit" />
|
||||
```
|
||||
|
||||
### Sizing
|
||||
|
||||
```tsx
|
||||
// Using size shorthand (sets both width and height)
|
||||
<Icon icon="hi.HiViewBoards" attributes={{ size: "2rem" }} />
|
||||
|
||||
// Using explicit width/height
|
||||
<Icon icon="hi.HiViewBoards" attributes={{ width: "32px", height: "32px" }} />
|
||||
|
||||
// Using inline styles
|
||||
<Icon icon="hi.HiViewBoards" attributes={{ styles: { width: 32, height: 32 } }} />
|
||||
```
|
||||
|
||||
### Colors
|
||||
|
||||
```tsx
|
||||
// Fill color
|
||||
<Icon icon="md.MdEdit" attributes={{ colors: { fillColor: "#333" } }} />
|
||||
|
||||
// Stroke color
|
||||
<Icon icon="fi.FiEdit" attributes={{ colors: { strokeColor: "red" } }} />
|
||||
|
||||
// Hover colors
|
||||
<Icon
|
||||
icon="md.MdDelete"
|
||||
attributes={{
|
||||
colors: {
|
||||
fillColor: "#666",
|
||||
hoverFillColor: "#ff0000",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
// Dark theme colors (applied when theme is DARK1)
|
||||
<Icon
|
||||
icon="md.MdEdit"
|
||||
attributes={{
|
||||
colors: {
|
||||
fillColor: "#333",
|
||||
darkFillColor: "#ccc",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Toggle State
|
||||
|
||||
```tsx
|
||||
// Icon toggles fill on click
|
||||
<Icon
|
||||
icon="md.MdFavorite"
|
||||
attributes={{
|
||||
colors: {
|
||||
fillColor: "#ccc",
|
||||
toggleFillColor: "#ff0000",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### Path-Level Coloring
|
||||
|
||||
```tsx
|
||||
// Apply colors to all <path> elements inside the SVG
|
||||
<Icon icon="md.MdEdit" fillPath={true} attributes={{ colors: { fillColor: "blue" } }} />
|
||||
|
||||
// Apply colors to specific paths by index
|
||||
<Icon icon="md.MdEdit" fillPath={[0, 2]} attributes={{ colors: { strokeColor: "red" } }} />
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
```tsx
|
||||
<Icon
|
||||
icon="md.MdDelete"
|
||||
events={{
|
||||
onClick: (e) => console.log("clicked", e),
|
||||
onMouseEnter: () => console.log("hovered"),
|
||||
onMouseLeave: () => console.log("left"),
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
### CSS Classes
|
||||
|
||||
```tsx
|
||||
<Icon icon="hi.HiViewBoards" attributes={{ classes: "me-2 text-primary" }} />
|
||||
```
|
||||
|
||||
### Hover Shadow
|
||||
|
||||
```tsx
|
||||
<Icon icon="md.MdEdit" hoverShadow />
|
||||
```
|
||||
|
||||
### SVG String Source
|
||||
|
||||
```tsx
|
||||
<Icon icon='<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/></svg>' />
|
||||
```
|
||||
|
||||
### URL Source
|
||||
|
||||
```tsx
|
||||
<Icon icon="https://cdn.example.com/my-icon.svg" />
|
||||
```
|
||||
|
||||
### Explicit IconSource
|
||||
|
||||
```tsx
|
||||
<Icon icon={{ source: "https://cdn.example.com/icon.svg", type: "URL" }} />
|
||||
<Icon icon={{ source: "hi.HiViewBoards", type: "identifier" }} />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exported Utilities
|
||||
|
||||
The package also exports helper functions and types from `index.ts`:
|
||||
|
||||
### Helper Functions (`helper.ts`)
|
||||
|
||||
| Function | Signature | Description |
|
||||
|----------|-----------|-------------|
|
||||
| `inferIconType` | `(source: string \| object) => ArIconSourceTypes` | Auto-detects the icon source type from the input. |
|
||||
| `parseSvgString` | `(svgString: string) => SVGSVGElement` | Parses an SVG markup string into an `SVGSVGElement`. |
|
||||
| `parseSvgB64String` | `(b64: string) => SVGSVGElement` | Decodes a base64 SVG string and parses it. |
|
||||
| `createElementFromSvg` | `(svg: SVGSVGElement) => ReactNode` | Converts an `SVGSVGElement` DOM node into a React element tree. |
|
||||
| `applyStyles` | `(milk, props, state) => SVGSVGElement` | Applies sizing, colors, classes, and styles to a cloned SVG element. |
|
||||
| `getFillColor` | `(props, state?) => string \| undefined` | Resolves the correct fill color based on theme, hover, and toggle state. |
|
||||
| `getStrokeColor` | `(props, state?) => string \| undefined` | Resolves the correct stroke color based on theme, hover, and toggle state. |
|
||||
| `placeholder` | `SVGSVGElement` | A default placeholder SVG (empty rectangle) used when icon loading fails. |
|
||||
|
||||
### Enums (`enums.ts`)
|
||||
|
||||
| Enum | Values | Description |
|
||||
|------|--------|-------------|
|
||||
| `ArIconSourceTypes` | `URL`, `identifier`, `svgString`, `b64`, `raw` | Icon source type classification. |
|
||||
| `ArIconTileTypes` | `COMFY`, `COMPACT`, `LIST` | Icon tile display modes. |
|
||||
| `ArValidImageMimeTypes` | `JPEG`, `PNG`, `GIF`, `WEBP`, `SVG`, `TIFF`, `BMP`, `ICON` | Valid image MIME types for content-type detection. |
|
||||
| `ArPopoverSlots` | `POPOVER`, `ANCHOR` | Slot assignment for popover usage. |
|
||||
|
||||
### Types (`types.ts`)
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `IconProps` | Full props interface for the Icon component. |
|
||||
| `IconSource` | Explicit `{ source, type }` icon descriptor. |
|
||||
| `IconAttributes` | Sizing, colors, classes, styles. |
|
||||
| `IconEvents` | Click, hover event handlers. |
|
||||
| `IconState` | Internal component state (hovered, toggled, milk, shake, type). |
|
||||
| `IconRegistry` | Global cache type: `{ [key]: { promise?, icon? } }`. |
|
||||
| `IconStyles` | Simplified style descriptor (fill, stroke, bg). |
|
||||
| `IconResponse` | Server API response shape for icon data. |
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
1. **Icon Resolution**: The `parseIconDescriptor` method determines the source type and either fetches from the server (identifier/URL) or parses locally (SVG string, base64, raw).
|
||||
2. **Registry Caching**: A module-level `iconRegistry` object caches both the fetch promise and the resolved icon. This prevents duplicate network requests when the same icon is used multiple times.
|
||||
3. **Style Application**: On every render-relevant state change (hover, toggle, attribute change), `applyStyles` clones the SVG DOM node and applies colors, sizing, classes, and inline styles.
|
||||
4. **React Conversion**: The styled SVG DOM node is converted to a React element tree via `createElementFromSvg`, enabling React event binding.
|
||||
5. **Theme Awareness**: The `withTheme` HOC injects the current theme. Color resolution functions (`getFillColor`, `getStrokeColor`) select the appropriate color variant based on theme + hover + toggle state.
|
||||
|
||||
---
|
||||
|
||||
## CSS
|
||||
|
||||
The component applies the class `ar-Icon` to all rendered SVG elements. Additional classes can be added via `attributes.classes`.
|
||||
|
||||
```scss
|
||||
.ar-Icon {
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover.hover-shadow {
|
||||
box-shadow: 0px 4px 8px var(--ar-shadow);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@armco/icon",
|
||||
"version": "0.0.12",
|
||||
"version": "0.0.13",
|
||||
"type": "module",
|
||||
"main": "build/cjs/index.js",
|
||||
"module": "build/es/index.js",
|
||||
@@ -28,8 +28,8 @@
|
||||
}
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.3.1"
|
||||
"react": ">=18.0.0",
|
||||
"react-dom": ">=18.0.0"
|
||||
},
|
||||
"prettier": "prettier-config-nick",
|
||||
"repository": {
|
||||
|
||||
@@ -6,11 +6,22 @@ set -e
|
||||
|
||||
npm run build
|
||||
cp package.json build/
|
||||
sed -i '' -E 's/"build"/"*"/' build/package.json
|
||||
|
||||
sed -i '' 's#"build/cjs/Icon.js"#"cjs/Icon.js"#' build/package.json
|
||||
sed -i '' 's#"build/es/Icon.js"#"es/Icon.js"#' build/package.json
|
||||
sed -i '' 's#"build/types/Icon.d.ts"#"types/Icon.d.ts"#' build/package.json
|
||||
# Use Node.js for portable package.json normalization
|
||||
PKG_PATH="$(pwd)/build/package.json" node - <<'EOF'
|
||||
const fs = require('fs');
|
||||
const path = process.env.PKG_PATH;
|
||||
const pkg = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
pkg.private = false;
|
||||
delete pkg.scripts;
|
||||
delete pkg.devDependencies;
|
||||
if (!pkg.files) pkg.files = ['*'];
|
||||
else pkg.files = pkg.files.map(x => x === 'build' ? '*' : x);
|
||||
['main','module','types'].forEach(k => {
|
||||
if (pkg[k]) pkg[k] = pkg[k].replace(/^\.??\/build\//, '').replace(/^build\//, '');
|
||||
});
|
||||
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n');
|
||||
EOF
|
||||
|
||||
cd build
|
||||
npm pack --pack-destination ~/__Projects__/Common
|
||||
Reference in New Issue
Block a user