From b4061e71babe9711846e786d3e3f7949462bd2b2 Mon Sep 17 00:00:00 2001 From: mohiit1502 Date: Sun, 8 Feb 2026 14:37:47 +0530 Subject: [PATCH] Widened React lib peer deps to fix legacy peer deps issue in host apps --- docs/USAGE.md | 356 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 +- publish-local.sh | 19 ++- 3 files changed, 374 insertions(+), 7 deletions(-) create mode 100644 docs/USAGE.md diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 0000000..43ec592 --- /dev/null +++ b/docs/USAGE.md @@ -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 Identifier Format + +The most common way to use the component is with **react-icons identifiers**: + +``` +. +``` + +- **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 `` 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 + +``` + +### `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 ` + + +``` + +### Sizing + +```tsx +// Using size shorthand (sets both width and height) + + +// Using explicit width/height + + +// Using inline styles + +``` + +### Colors + +```tsx +// Fill color + + +// Stroke color + + +// Hover colors + + +// Dark theme colors (applied when theme is DARK1) + +``` + +### Toggle State + +```tsx +// Icon toggles fill on click + +``` + +### Path-Level Coloring + +```tsx +// Apply colors to all elements inside the SVG + + +// Apply colors to specific paths by index + +``` + +### Events + +```tsx + console.log("clicked", e), + onMouseEnter: () => console.log("hovered"), + onMouseLeave: () => console.log("left"), + }} +/> +``` + +### CSS Classes + +```tsx + +``` + +### Hover Shadow + +```tsx + +``` + +### SVG String Source + +```tsx + +``` + +### URL Source + +```tsx + +``` + +### Explicit IconSource + +```tsx + + +``` + +--- + +## 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); + } +} +``` diff --git a/package.json b/package.json index aa31149..a601aca 100644 --- a/package.json +++ b/package.json @@ -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": { diff --git a/publish-local.sh b/publish-local.sh index 6e75b05..8e80110 100755 --- a/publish-local.sh +++ b/publish-local.sh @@ -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 \ No newline at end of file