@modul-es/icons 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Icons Module
2
+
3
+ A simple icon system supporting multiple icon sets with consistent props and styling.
4
+
5
+ ## Icon Sets
6
+
7
+ - **huge**
8
+ - **phosphor**
9
+ - **lucide**
10
+ - **pixelart**
11
+
12
+ ## Basic Usage
13
+
14
+ ```tsx
15
+ import { Icon } from '@modules/icons';
16
+
17
+ // Basic usage
18
+ <Icon set="huge" name="home-01" color="slate-400" stroke="2" />
19
+
20
+ // Phosphor with weight variants
21
+ <Icon set="phosphor" name="heart" style="thin" color="white" />
22
+ <Icon set="phosphor" name="heart" style="bold" color="white" />
23
+ <Icon set="phosphor" name="heart" style="fill" color="ef4444" />
24
+ <Icon set="phosphor" name="heart" style="duotone" color="fbbf24" />
25
+
26
+ // Lucide with color variants
27
+ <Icon set="lucide" name="heart" color="red-500" />
28
+ <Icon set="lucide" name="zap" color="yellow-400" />
29
+ ```
30
+
31
+ ## Props
32
+ - **set**
33
+ - **color** (accepts hex & tailwind color names)
34
+ - **stroke**
35
+ - **style** (does not apply to all sets)
package/dist/Icon.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export type IconSet = 'huge' | 'pixelart' | 'phosphor' | 'lucide';
2
+ export interface IconProps {
3
+ name: string;
4
+ color?: string;
5
+ stroke?: string;
6
+ style?: 'sharp' | 'default' | 'fill' | 'thin' | 'light' | 'bold' | 'duotone';
7
+ set?: IconSet;
8
+ className?: string;
9
+ size?: number | string;
10
+ }
11
+ export declare function Icon({ name, color, stroke, style, set, className, size }: IconProps): import("react/jsx-runtime").JSX.Element | null;
package/dist/Icon.js ADDED
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.Icon = Icon;
40
+ var jsx_runtime_1 = require("react/jsx-runtime");
41
+ var react_1 = require("react");
42
+ var colors_1 = require("./colors");
43
+ // Cache for loaded SVG content
44
+ var svgCache = new Map();
45
+ function Icon(_a) {
46
+ var _this = this;
47
+ var name = _a.name, _b = _a.color, color = _b === void 0 ? 'currentColor' : _b, stroke = _a.stroke, style = _a.style, _c = _a.set, set = _c === void 0 ? 'huge' : _c, _d = _a.className, className = _d === void 0 ? "w-6 select-none" : _d, size = _a.size;
48
+ var _e = (0, react_1.useState)(null), svgContent = _e[0], setSvgContent = _e[1];
49
+ var _f = (0, react_1.useState)(false), error = _f[0], setError = _f[1];
50
+ var iconKey = (0, react_1.useMemo)(function () {
51
+ var iconName = name.replace('.svg', '');
52
+ if (set === 'phosphor' && typeof style === 'string' && ['thin', 'light', 'bold', 'fill', 'duotone'].includes(style)) {
53
+ iconName = "".concat(iconName, ".").concat(style);
54
+ }
55
+ if (set === 'huge' && style === 'sharp') {
56
+ iconName = "".concat(iconName, ".sharp");
57
+ }
58
+ return iconName;
59
+ }, [name, set, style]);
60
+ var cacheKey = "".concat(set, "/").concat(iconKey);
61
+ (0, react_1.useEffect)(function () {
62
+ var loadSvg = function () { return __awaiter(_this, void 0, void 0, function () {
63
+ var params, colorValue, url, response, svg, err_1;
64
+ return __generator(this, function (_a) {
65
+ switch (_a.label) {
66
+ case 0:
67
+ if (svgCache.has(cacheKey)) {
68
+ setSvgContent(svgCache.get(cacheKey));
69
+ return [2 /*return*/];
70
+ }
71
+ setError(false);
72
+ _a.label = 1;
73
+ case 1:
74
+ _a.trys.push([1, 6, , 7]);
75
+ params = new URLSearchParams();
76
+ if (color !== 'currentColor') {
77
+ colorValue = (0, colors_1.resolveColor)(color).replace('#', '');
78
+ params.set('color', colorValue);
79
+ }
80
+ if (stroke)
81
+ params.set('stroke', stroke);
82
+ url = "https://icons.modul.es/".concat(set, "/").concat(iconKey, ".svg").concat(params.toString() ? "?".concat(params.toString()) : '');
83
+ return [4 /*yield*/, fetch(url, { mode: 'cors', cache: 'force-cache' })];
84
+ case 2:
85
+ response = _a.sent();
86
+ if (!response.ok) return [3 /*break*/, 4];
87
+ return [4 /*yield*/, response.text()];
88
+ case 3:
89
+ svg = _a.sent();
90
+ svgCache.set(cacheKey, svg);
91
+ setSvgContent(svg);
92
+ return [3 /*break*/, 5];
93
+ case 4:
94
+ setError(true);
95
+ _a.label = 5;
96
+ case 5: return [3 /*break*/, 7];
97
+ case 6:
98
+ err_1 = _a.sent();
99
+ setError(true);
100
+ return [3 /*break*/, 7];
101
+ case 7: return [2 /*return*/];
102
+ }
103
+ });
104
+ }); };
105
+ loadSvg();
106
+ }, [cacheKey, color, stroke, set, iconKey]);
107
+ var processedSvg = (0, react_1.useMemo)(function () {
108
+ if (!svgContent)
109
+ return null;
110
+ var svg = svgContent;
111
+ svg = svg.replace(/<\?xml[^>]*\?>/g, '');
112
+ svg = svg.replace(/<!--[\s\S]*?-->/g, '');
113
+ svg = svg.replace(/<svg([^>]*)\s(?:width|height)="[^"]*"([^>]*)>/gi, '<svg$1$2>');
114
+ if (size) {
115
+ svg = svg.replace(/<svg([^>]*)>/i, "<svg$1 width=\"".concat(size, "\" height=\"").concat(size, "\">"));
116
+ }
117
+ svg = svg.replace(/<svg([^>]*)>/i, function (match, attrs) {
118
+ var newAttrs = attrs;
119
+ if (!newAttrs.includes('class=')) {
120
+ newAttrs += " class=\"".concat(className, "\"");
121
+ }
122
+ if (set !== 'phosphor' && set !== 'lucide' && !newAttrs.includes('fill=')) {
123
+ newAttrs += " fill=\"currentColor\"";
124
+ }
125
+ if (!newAttrs.includes('shape-rendering=')) {
126
+ newAttrs += " shape-rendering=\"crispEdges\"";
127
+ }
128
+ return "<svg".concat(newAttrs, ">");
129
+ });
130
+ return svg.trim();
131
+ }, [svgContent, size, className, set]);
132
+ if (error || !processedSvg) {
133
+ return null;
134
+ }
135
+ return ((0, jsx_runtime_1.jsx)("div", { style: { imageRendering: 'crisp-edges' }, dangerouslySetInnerHTML: { __html: processedSvg } }));
136
+ }
@@ -0,0 +1 @@
1
+ export declare function resolveColor(color: string): string;
package/dist/colors.js ADDED
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveColor = resolveColor;
4
+ // Tailwind color mappings to hex values (without # prefix for URL params)
5
+ var tailwindColors = {
6
+ // Red
7
+ 'red-50': 'fef2f2', 'red-100': 'fee2e2', 'red-200': 'fecaca', 'red-300': 'fca5a5',
8
+ 'red-400': 'f87171', 'red-500': 'ef4444', 'red-600': 'dc2626', 'red-700': 'b91c1c',
9
+ 'red-800': '991b1b', 'red-900': '7f1d1d', 'red-950': '450a0a',
10
+ // Orange
11
+ 'orange-50': 'fff7ed', 'orange-100': 'ffedd5', 'orange-200': 'fed7aa', 'orange-300': 'fdba74',
12
+ 'orange-400': 'fb923c', 'orange-500': 'f97316', 'orange-600': 'ea580c', 'orange-700': 'c2410c',
13
+ 'orange-800': '9a3412', 'orange-900': '7c2d12', 'orange-950': '431407',
14
+ // Amber
15
+ 'amber-50': 'fffbeb', 'amber-100': 'fef3c7', 'amber-200': 'fde68a', 'amber-300': 'fcd34d',
16
+ 'amber-400': 'fbbf24', 'amber-500': 'f59e0b', 'amber-600': 'd97706', 'amber-700': 'b45309',
17
+ 'amber-800': '92400e', 'amber-900': '78350f', 'amber-950': '451a03',
18
+ // Yellow
19
+ 'yellow-50': 'fefce8', 'yellow-100': 'fef3c7', 'yellow-200': 'fde68a', 'yellow-300': 'fcd34d',
20
+ 'yellow-400': 'fbbf24', 'yellow-500': 'f59e0b', 'yellow-600': 'd97706', 'yellow-700': 'b45309',
21
+ 'yellow-800': '92400e', 'yellow-900': '78350f', 'yellow-950': '451a03',
22
+ // Lime
23
+ 'lime-50': 'f7fee7', 'lime-100': 'ecfccb', 'lime-200': 'd9f99d', 'lime-300': 'bef264',
24
+ 'lime-400': 'a3e635', 'lime-500': '84cc16', 'lime-600': '65a30d', 'lime-700': '4d7c0f',
25
+ 'lime-800': '365314', 'lime-900': '1a2e05', 'lime-950': '0c1a02',
26
+ // Green
27
+ 'green-50': 'f0fdf4', 'green-100': 'dcfce7', 'green-200': 'bbf7d0', 'green-300': '86efac',
28
+ 'green-400': '4ade80', 'green-500': '22c55e', 'green-600': '16a34a', 'green-700': '15803d',
29
+ 'green-800': '166534', 'green-900': '14532d', 'green-950': '052e16',
30
+ // Emerald
31
+ 'emerald-50': 'ecfdf5', 'emerald-100': 'd1fae5', 'emerald-200': 'a7f3d0', 'emerald-300': '6ee7b7',
32
+ 'emerald-400': '34d399', 'emerald-500': '10b981', 'emerald-600': '059669', 'emerald-700': '047857',
33
+ 'emerald-800': '065f46', 'emerald-900': '064e3b', 'emerald-950': '022c22',
34
+ // Teal
35
+ 'teal-50': 'f0fdfa', 'teal-100': 'ccfbf1', 'teal-200': '99f6e4', 'teal-300': '5eead4',
36
+ 'teal-400': '2dd4bf', 'teal-500': '14b8a6', 'teal-600': '0d9488', 'teal-700': '0f766e',
37
+ 'teal-800': '115e59', 'teal-900': '134e4a', 'teal-950': '042f2e',
38
+ // Cyan
39
+ 'cyan-50': 'ecfeff', 'cyan-100': 'cffafe', 'cyan-200': 'a5f3fc', 'cyan-300': '67e8f9',
40
+ 'cyan-400': '22d3ee', 'cyan-500': '06b6d4', 'cyan-600': '0891b2', 'cyan-700': '0e7490',
41
+ 'cyan-800': '155e75', 'cyan-900': '164e63', 'cyan-950': '083344',
42
+ // Sky
43
+ 'sky-50': 'f0f9ff', 'sky-100': 'e0f2fe', 'sky-200': 'bae6fd', 'sky-300': '7dd3fc',
44
+ 'sky-400': '38bdf8', 'sky-500': '0ea5e9', 'sky-600': '0284c7', 'sky-700': '0369a1',
45
+ 'sky-800': '075985', 'sky-900': '0c4a6e', 'sky-950': '082f49',
46
+ // Blue
47
+ 'blue-50': 'eff6ff', 'blue-100': 'dbeafe', 'blue-200': 'bfdbfe', 'blue-300': '93c5fd',
48
+ 'blue-400': '60a5fa', 'blue-500': '3b82f6', 'blue-600': '2563eb', 'blue-700': '1d4ed8',
49
+ 'blue-800': '1e40af', 'blue-900': '1e3a8a', 'blue-950': '172554',
50
+ // Indigo
51
+ 'indigo-50': 'eef2ff', 'indigo-100': 'e0e7ff', 'indigo-200': 'c7d2fe', 'indigo-300': 'a5b4fc',
52
+ 'indigo-400': '818cf8', 'indigo-500': '6366f1', 'indigo-600': '4f46e5', 'indigo-700': '4338ca',
53
+ 'indigo-800': '3730a3', 'indigo-900': '312e81', 'indigo-950': '1e1b4b',
54
+ // Violet
55
+ 'violet-50': 'f5f3ff', 'violet-100': 'ede9fe', 'violet-200': 'ddd6fe', 'violet-300': 'c4b5fd',
56
+ 'violet-400': 'a78bfa', 'violet-500': '8b5cf6', 'violet-600': '7c3aed', 'violet-700': '6d28d9',
57
+ 'violet-800': '5b21b6', 'violet-900': '4c1d95', 'violet-950': '2e1065',
58
+ // Purple
59
+ 'purple-50': 'faf5ff', 'purple-100': 'f3e8ff', 'purple-200': 'e9d5ff', 'purple-300': 'd8b4fe',
60
+ 'purple-400': 'c084fc', 'purple-500': 'a855f7', 'purple-600': '9333ea', 'purple-700': '7c3aed',
61
+ 'purple-800': '6b21a8', 'purple-900': '581c87', 'purple-950': '3b0764',
62
+ // Fuchsia
63
+ 'fuchsia-50': 'fdf4ff', 'fuchsia-100': 'fae8ff', 'fuchsia-200': 'f5d0fe', 'fuchsia-300': 'f0abfc',
64
+ 'fuchsia-400': 'e879f9', 'fuchsia-500': 'd946ef', 'fuchsia-600': 'c026d3', 'fuchsia-700': 'a21caf',
65
+ 'fuchsia-800': '86198f', 'fuchsia-900': '701a75', 'fuchsia-950': '4a044e',
66
+ // Pink
67
+ 'pink-50': 'fdf2f8', 'pink-100': 'fce7f3', 'pink-200': 'fbcfe8', 'pink-300': 'f9a8d4',
68
+ 'pink-400': 'f472b6', 'pink-500': 'ec4899', 'pink-600': 'db2777', 'pink-700': 'be185d',
69
+ 'pink-800': '9d174d', 'pink-900': '831843', 'pink-950': '500724',
70
+ // Rose
71
+ 'rose-50': 'fff1f2', 'rose-100': 'ffe4e6', 'rose-200': 'fecdd3', 'rose-300': 'fda4af',
72
+ 'rose-400': 'fb7185', 'rose-500': 'f43f5e', 'rose-600': 'e11d48', 'rose-700': 'be123c',
73
+ 'rose-800': '9f1239', 'rose-900': '881337', 'rose-950': '4c0519',
74
+ // Slate
75
+ 'slate-50': 'f8fafc', 'slate-100': 'f1f5f9', 'slate-200': 'e2e8f0', 'slate-300': 'cbd5e1',
76
+ 'slate-400': '94a3b8', 'slate-500': '64748b', 'slate-600': '475569', 'slate-700': '334155',
77
+ 'slate-800': '1e293b', 'slate-900': '0f172a', 'slate-950': '020617',
78
+ // Gray
79
+ 'gray-50': 'f9fafb', 'gray-100': 'f3f4f6', 'gray-200': 'e5e7eb', 'gray-300': 'd1d5db',
80
+ 'gray-400': '9ca3af', 'gray-500': '6b7280', 'gray-600': '4b5563', 'gray-700': '374151',
81
+ 'gray-800': '1f2937', 'gray-900': '111827', 'gray-950': '030712',
82
+ // Zinc
83
+ 'zinc-50': 'fafafa', 'zinc-100': 'f4f4f5', 'zinc-200': 'e4e4e7', 'zinc-300': 'd4d4d8',
84
+ 'zinc-400': 'a1a1aa', 'zinc-500': '71717a', 'zinc-600': '52525b', 'zinc-700': '3f3f46',
85
+ 'zinc-800': '27272a', 'zinc-900': '18181b', 'zinc-950': '09090b',
86
+ // Neutral
87
+ 'neutral-50': 'fafafa', 'neutral-100': 'f5f5f5', 'neutral-200': 'e5e5e5', 'neutral-300': 'd4d4d4',
88
+ 'neutral-400': 'a3a3a3', 'neutral-500': '737373', 'neutral-600': '525252', 'neutral-700': '404040',
89
+ 'neutral-800': '262626', 'neutral-900': '171717', 'neutral-950': '0a0a0a',
90
+ // Stone
91
+ 'stone-50': 'fafaf9', 'stone-100': 'f5f5f4', 'stone-200': 'e7e5e4', 'stone-300': 'd6d3d1',
92
+ 'stone-400': 'a8a29e', 'stone-500': '78716c', 'stone-600': '57534e', 'stone-700': '44403c',
93
+ 'stone-800': '292524', 'stone-900': '1c1917', 'stone-950': '0c0a09',
94
+ // Common colors
95
+ 'black': '000000',
96
+ 'white': 'ffffff',
97
+ 'transparent': 'transparent',
98
+ 'current': 'currentColor',
99
+ };
100
+ function resolveColor(color) {
101
+ // If it's already a hex color, return as is
102
+ if (color.match(/^[0-9a-fA-F]{3,8}$/)) {
103
+ return "#".concat(color);
104
+ }
105
+ // Check if it's a Tailwind color
106
+ if (tailwindColors[color]) {
107
+ return "#".concat(tailwindColors[color]);
108
+ }
109
+ // If it starts with bg-, text-, border-, etc., extract the color part
110
+ var colorMatch = color.match(/^(?:bg-|text-|border-|ring-|from-|to-|via-)?(.+)$/);
111
+ if (colorMatch && tailwindColors[colorMatch[1]]) {
112
+ return "#".concat(tailwindColors[colorMatch[1]]);
113
+ }
114
+ // Default to the original color (might be a CSS color name)
115
+ return color.startsWith('#') ? color : "#".concat(color);
116
+ }
@@ -0,0 +1,2 @@
1
+ export { Icon } from './Icon';
2
+ export type { IconProps, IconSet } from './Icon';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Icon = void 0;
4
+ var Icon_1 = require("./Icon");
5
+ Object.defineProperty(exports, "Icon", { enumerable: true, get: function () { return Icon_1.Icon; } });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@modul-es/icons",
3
+ "version": "0.1.1",
4
+ "description": "Icon component system",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "peerDependencies": {
22
+ "react": ">=16.8.0"
23
+ },
24
+ "devDependencies": {
25
+ "@types/react": "^18.0.0",
26
+ "typescript": "^5.0.0"
27
+ },
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/traf/modules.git",
31
+ "directory": "modules/icons"
32
+ },
33
+ "keywords": ["react", "icons", "components", "modules"],
34
+ "author": "@traf"
35
+ }