@genarou/blazir-icons 1.1.5 → 1.1.7

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/dist/Icon.svelte CHANGED
@@ -1,16 +1,16 @@
1
- <!-- src/lib/Icon.svelte -->
2
1
  <script lang="ts">
3
2
  import { iconRegistry, type IconName } from "./icons/registry";
4
- import type { IconProps } from "./types";
3
+ import type { IconComponent, IconProps } from "./types";
5
4
  import { coerceSize } from "./utils/defaults";
6
5
 
7
6
  let {
8
7
  name,
9
- size = 24, // ✅ primitivo
10
- color = "#6b7280",
8
+ size = 24,
9
+ color,
11
10
  stroke,
12
11
  strokeWidth,
13
12
  fill,
13
+ class: classAttr = "",
14
14
  className = "",
15
15
  ariaLabel,
16
16
  title = "",
@@ -30,16 +30,24 @@
30
30
  ...rest
31
31
  }: { name: IconName } & Partial<IconProps> = $props();
32
32
 
33
- const Comp = $derived(iconRegistry[name]);
33
+ // Comp tipado como el mismo tipo que usa tu registry
34
+ const Comp: IconComponent | undefined = $derived(iconRegistry?.[name]);
35
+
36
+ // ❌ ANTES: const colorOverrides = $derived(() => color !== undefined ? {...} : {...})
37
+ // ✅ AHORA:
38
+ const colorOverrides = $derived(
39
+ color !== undefined
40
+ ? { color, stroke: stroke ?? "none", fill: fill ?? color }
41
+ : { stroke, fill }
42
+ );
34
43
 
35
- const passProps = $derived(() => ({
36
- // ✅ tamaño garantizado como number|string simple
44
+ // ❌ ANTES: const passProps = $derived(() => ({ ... }))
45
+ // ✅ AHORA:
46
+ const passProps = $derived({
37
47
  size: coerceSize(size, 24),
38
- color,
39
- stroke: color ? (stroke ?? "none") : stroke,
40
- fill: color ? (fill ?? color) : fill,
48
+ ...colorOverrides,
41
49
  strokeWidth,
42
- className,
50
+ className: classAttr || className,
43
51
  ariaLabel,
44
52
  title,
45
53
  rotate,
@@ -62,7 +70,7 @@
62
70
  : animationDelay,
63
71
  animationEasing,
64
72
  ...rest,
65
- }));
73
+ });
66
74
  </script>
67
75
 
68
76
  {#if Comp}
@@ -1,3 +1,4 @@
1
+ <!-- 📁 src/lib/IconBase.svelte -->
1
2
  <script lang="ts">
2
3
  import type { IconMode, IconProps } from "./types.js";
3
4
  import {
@@ -11,58 +12,122 @@
11
12
  normalizeClass,
12
13
  } from "./utils/defaults.js";
13
14
 
15
+ // Props del icono + modo visual
14
16
  const props: IconProps & { mode?: IconMode } = $props();
15
17
 
18
+ // ====== Derivados visuales / clases / defaults ======
16
19
  const mode = $derived(props.mode ?? "solid");
17
20
  const klass = $derived(normalizeClass(props));
18
- const common = $derived(commonDefaults(props)); // ya coercea size
19
- const visual = $derived(modeDefaults(mode, props));
21
+ const common = $derived(commonDefaults(props)); // size, viewBox, preserveAspectRatio
22
+ const visual = $derived(modeDefaults(mode, props)); // lo que ya tienes
20
23
 
21
24
  const animationClasses = $derived(getAnimationClasses(props).join(" "));
22
- const baseTransform = $derived(combineTransforms(props));
23
- const animationStyle = $derived(getAnimationStyle(props));
25
+ const timingStyle = $derived(getAnimationStyle(props)); // duration/delay/easing
24
26
 
25
- const _ariaHidden = $derived(props.decorative ? "true" : undefined);
26
- const _ariaLabel = $derived(
27
- props.decorative ? undefined : props.ariaLabel || undefined
28
- );
29
- const _ariaLabelledby = $derived(
30
- !props.decorative && props.title ? props.titleId : undefined
27
+ // ⚠️ Solo CSS transforms semánticos (chevron/morph/slide).
28
+ // Quitamos rotate/flip del combine para no duplicar (rotate/flip van en <g transform>).
29
+ const cssTransformOnly = $derived(
30
+ combineTransforms({
31
+ ...props,
32
+ rotate: undefined as any,
33
+ flipH: false,
34
+ flipV: false,
35
+ })
31
36
  );
32
37
 
33
- const transformStr = $derived(() =>
34
- baseTransform
35
- ? `transform: ${baseTransform}; transform-origin: center;`
36
- : ""
38
+ // Sólo variable para spin (sin animation: inline)
39
+ const spinStyle = $derived(
40
+ (() => {
41
+ const s = props.spin;
42
+ if (!s) return "";
43
+ const dur = s === true ? "1s" : typeof s === "number" ? `${s}ms` : s;
44
+ return `--bz-spin: ${dur};`;
45
+ })()
37
46
  );
38
47
 
39
- const spinStr = $derived(() => {
40
- const s = props.spin;
41
- if (!s) return "";
42
- const dur = s === true ? "1s" : typeof s === "number" ? `${s}ms` : s;
43
- return `animation: __icon_spin ${dur} linear infinite;`;
44
- });
45
-
48
+ // Estilo final inline (añadimos transform-origin/box, timing y variable de spin)
46
49
  const style = $derived(
47
- `${props.style || ""}${props.style && !props.style.endsWith(";") ? ";" : ""}${transformStr}${spinStr}${animationStyle}`.trim()
50
+ `${props.style || ""}${props.style && !props.style.endsWith(";") ? ";" : ""}` +
51
+ (cssTransformOnly ? `transform: ${cssTransformOnly};` : "") +
52
+ `transform-origin: center;` + // deja 'transform-box' fuera si TS te marca error
53
+ (spinStyle ? spinStyle : "") +
54
+ (timingStyle ? timingStyle : "") +
55
+ (props.color ? `color: ${props.color};` : "") // ← ★ clave para currentColor
48
56
  );
49
57
 
50
- // finalSize es un VALOR, no una función
58
+ // A11y derivados
59
+ const ariaHidden = $derived(props.decorative ? "true" : undefined);
60
+ const ariaLabel = $derived(
61
+ props.decorative ? undefined : props.ariaLabel || undefined
62
+ );
63
+ const ariaLabelledby = $derived(
64
+ !props.decorative && props.title ? props.titleId : undefined
65
+ );
66
+
67
+ // Size final como string para width/height
51
68
  const finalSize = $derived(
52
69
  typeof common.size === "number" ? `${common.size}px` : common.size
53
70
  );
54
71
 
55
- // evita que attrs pisen width/height
72
+ // Atributos seguros (evitar que pisen width/height del svg)
56
73
  const safeAttrs = $derived(() => {
57
74
  const a = { ...(props.attrs ?? {}) } as Record<string, any>;
58
75
  delete a.width;
59
- delete a.height; // opcional: delete a.style si te meten width/height por style
76
+ delete a.height;
60
77
  return a;
61
78
  });
62
79
 
63
80
  const finalClass = $derived(
64
81
  `${klass} ${animationClasses} ${props.chevronState ? "bz-icon-chevron" : ""}`.trim()
65
82
  );
83
+
84
+ // ====== ROTATE / FLIPS en <g transform> (SVG nativo, centrado) ======
85
+ function getViewBoxCenter(vb: string) {
86
+ const parts = vb.trim().split(/\s+/).map(Number);
87
+ const [minX, minY, w, h] = parts.length === 4 ? parts : [0, 0, 24, 24];
88
+ return { cx: minX + w / 2, cy: minY + h / 2 };
89
+ }
90
+
91
+ const { cx, cy } = $derived(getViewBoxCenter(common.viewBox));
92
+
93
+ const svgTransform = $derived(() => {
94
+ const cmds: string[] = [];
95
+
96
+ // rotate
97
+ if (props.rotate != null) {
98
+ const r =
99
+ typeof props.rotate === "number"
100
+ ? props.rotate
101
+ : parseFloat(String(props.rotate));
102
+ if (!Number.isNaN(r)) cmds.push(`rotate(${r} ${cx} ${cy})`);
103
+ }
104
+
105
+ // flips
106
+ if (props.flipH || props.flipV) {
107
+ const sx = props.flipH ? -1 : 1;
108
+ const sy = props.flipV ? -1 : 1;
109
+ cmds.push(
110
+ `translate(${cx} ${cy}) scale(${sx} ${sy}) translate(${-cx} ${-cy})`
111
+ );
112
+ }
113
+
114
+ return cmds.join(" ");
115
+ });
116
+
117
+ const visualColor = $derived(() => {
118
+ if (!props.color) return visual;
119
+
120
+ const v = { ...visual };
121
+
122
+ if (mode === "solid") {
123
+ v.fill = props.color; // ← Fuerza el color aquí
124
+ } else {
125
+ v.stroke = props.color;
126
+ }
127
+
128
+ console.log("Final visual color:", v); // ← Debug temporal
129
+ return v;
130
+ });
66
131
  </script>
67
132
 
68
133
  <svg
@@ -74,27 +139,21 @@
74
139
  preserveAspectRatio={common.preserveAspectRatio}
75
140
  class={finalClass}
76
141
  role="img"
77
- aria-hidden={_ariaHidden}
78
- aria-label={_ariaLabel}
79
- aria-labelledby={_ariaLabelledby}
142
+ aria-hidden={ariaHidden}
143
+ aria-label={ariaLabel}
144
+ aria-labelledby={ariaLabelledby}
80
145
  focusable="false"
81
146
  {style}
82
- fill={visual.fill}
83
- stroke={visual.stroke}
84
- stroke-width={visual.strokeWidth}
147
+ fill={visualColor().fill}
148
+ stroke={visualColor().stroke}
149
+ stroke-width={visualColor().strokeWidth}
85
150
  stroke-linecap={props.strokeLinecap}
86
151
  stroke-linejoin={props.strokeLinejoin}
87
152
  vector-effect={props.nonScalingStroke ? "non-scaling-stroke" : undefined}
88
153
  data-testid={props.testId}
89
154
  >
90
155
  {#if props.title}<title id={props.titleId}>{props.title}</title>{/if}
91
- {@render props.children?.()}
156
+ <g transform={svgTransform()}>
157
+ {@render props.children?.()}
158
+ </g>
92
159
  </svg>
93
-
94
- <style>
95
- @keyframes __icon_spin {
96
- to {
97
- transform: rotate(360deg);
98
- }
99
- }
100
- </style>
@@ -1,4 +1,4 @@
1
- import { IconComponent, IconName } from "./icons/registry";
1
+ import { IconComponent, IconName } from "./types";
2
2
  export declare const bzIcons: Record<string, IconName>;
3
3
  export declare class IconAPI {
4
4
  static getValid(...names: string[]): Array<{
@@ -102,7 +102,7 @@ export declare const iconStats: {
102
102
  readonly categories: number;
103
103
  readonly animated: number;
104
104
  readonly byCategory: {
105
- [k: string]: 12 | 2 | 9 | 3 | 10 | 4 | 8 | 7 | 6 | 5;
105
+ [k: string]: 12 | 2 | 4 | 3 | 9 | 10 | 8 | 7 | 6 | 5;
106
106
  };
107
107
  readonly mostUsedCategory: string;
108
108
  readonly shortcuts: number;
package/dist/icons-api.js CHANGED
@@ -1,4 +1,3 @@
1
- // 📁 src/lib/icons/icon-api.ts - MANTENIENDO bzIcons como nombre original
2
1
  import { iconRegistry } from "./icons/registry";
3
2
  // 🎯 MANTENER TU NOMBRE ORIGINAL: bzIcons
4
3
  export const bzIcons = {
package/dist/index.d.ts CHANGED
@@ -4,8 +4,9 @@ export { combineTransforms, getAnimationClasses, getAnimationStyle, getChevronTr
4
4
  export { batchStyleUpdates, EASING_PRESETS, getPrefersReducedMotion, optimizeEasing, } from "./utils/performance.js";
5
5
  export { iconEffects } from "./effects/icon-effects.js";
6
6
  export { getInjectionInfo, injectIconEffectsCSS, injectIconEffectsCSSFromFile, injectIconEffectsCSSLegacy, injectIconEffectsCSSOptimized, } from "./styles/css-injection.js";
7
- export { default as DynamicIcon, default as Icon } from "./DynamicIcon.svelte";
8
- export { default as BaseIcon } from "./Icon.svelte";
7
+ export { default as DynamicIcon } from "./DynamicIcon.svelte";
8
+ export { default as Icon } from "./Icon.svelte";
9
+ export { default as BaseIcon } from "./IconBase.svelte";
9
10
  export { bzIcons, IconAPI, iconCategories, iconShortcuts, iconStats, type BzIconKey, type IconCategory, type IconShortcutCategory, } from "./icons-api.js";
10
11
  export { iconRegistry, type IconComponent, type IconName, } from "./icons/registry.js";
11
12
  export { default as AnimatedArrowLeft } from "./icons/AnimatedArrowLeft.svelte";
package/dist/index.js CHANGED
@@ -8,8 +8,9 @@ export { iconEffects } from "./effects/icon-effects.js";
8
8
  // CSS Injection
9
9
  export { getInjectionInfo, injectIconEffectsCSS, injectIconEffectsCSSFromFile, injectIconEffectsCSSLegacy, injectIconEffectsCSSOptimized, } from "./styles/css-injection.js";
10
10
  // 🎯 COMPONENTES
11
- export { default as DynamicIcon, default as Icon } from "./DynamicIcon.svelte"; // Componente dinámico principal
12
- export { default as BaseIcon } from "./Icon.svelte"; // Componente base original
11
+ export { default as DynamicIcon } from "./DynamicIcon.svelte";
12
+ export { default as Icon } from "./Icon.svelte"; // wrapper que usa iconRegistry
13
+ export { default as BaseIcon } from "./IconBase.svelte"; // donde vive el <svg>
13
14
  // 🆕 NUEVA API DE ICONOS
14
15
  export { bzIcons, IconAPI, iconCategories, iconShortcuts, iconStats, } from "./icons-api.js";
15
16
  // Registry original (para casos avanzados)
@@ -1,9 +1,9 @@
1
- /** API PRINCIPAL - Inyección híbrida inteligente */
1
+ /** API principal (singleton + carrera segura) */
2
2
  export declare function injectIconEffectsCSS(): Promise<void>;
3
- /** API adicional para casos específicos */
3
+ /** API explícita virtual/tradicional */
4
4
  export declare function injectVirtualIconCSS(): Promise<void>;
5
5
  export declare function injectTraditionalIconCSS(): void;
6
- /** Utility - Info del método usado */
6
+ /** Info */
7
7
  export declare function getInjectionInfo(): {
8
8
  injected: boolean;
9
9
  method: "virtual" | "traditional" | null;
@@ -2,6 +2,7 @@
2
2
  let cssInjected = false;
3
3
  let virtualStyleSheet = null;
4
4
  let injectionMethod = null;
5
+ let injectOncePromise = null;
5
6
  const CSS_CONTENT = `
6
7
  :root {
7
8
  --bz-icon-bounce-amt: 18%;
@@ -12,10 +13,10 @@ const CSS_CONTENT = `
12
13
  --bz-icon-wiggle-angle: 3deg;
13
14
  }
14
15
 
15
- @keyframes bz-icon-spin {
16
- to { transform: rotate(360deg); }
17
- }
16
+ /* ✅ keyframes estándar para spin */
17
+ @keyframes __icon_spin { to { transform: rotate(360deg); } }
18
18
 
19
+ /* ===== Keyframes de efectos ===== */
19
20
  @keyframes bz-icon-bounce {
20
21
  0% { transform: translateY(0); }
21
22
  35% { transform: translateY(calc(var(--bz-icon-bounce-amt) * -1)); }
@@ -80,7 +81,17 @@ const CSS_CONTENT = `
80
81
  100% { transform: translateX(0); opacity: 1; }
81
82
  }
82
83
 
83
- :where(.bz-icon-spin) { animation: bz-icon-spin 900ms linear infinite; }
84
+ /* ===== Clases de efectos ===== */
85
+
86
+ /* ✅ Spin performante por variable */
87
+ :where(.bz-icon--spin) {
88
+ animation-name: __icon_spin;
89
+ animation-duration: var(--bz-spin, 1s);
90
+ animation-timing-function: linear;
91
+ animation-iteration-count: infinite;
92
+ }
93
+
94
+ /* Otras animaciones */
84
95
  :where(.bz-icon-bounce) { animation: bz-icon-bounce 400ms ease; }
85
96
  :where(.bz-icon-pulse) { animation: bz-icon-pulse 1200ms cubic-bezier(.2,.8,.2,1) infinite; }
86
97
  :where(.bz-icon-wiggle) { animation: bz-icon-wiggle 200ms ease-in-out; }
@@ -90,35 +101,25 @@ const CSS_CONTENT = `
90
101
  :where(.bz-icon-fade-in) { animation: bz-icon-fade-in 200ms ease-out; }
91
102
  :where(.bz-icon-slide-in) { animation: bz-icon-slide-in-up 200ms ease-out; }
92
103
 
104
+ /* Estados utilitarios */
93
105
  :where(.bz-icon-chevron) {
94
106
  transition: transform 200ms cubic-bezier(.2,.8,.2,1);
95
107
  }
108
+ :where(.bz-icon-morph-play) { transform: scale(1.05); transition: all 150ms ease; }
109
+ :where(.bz-icon-morph-pause) { transform: scale(0.95); transition: all 150ms ease; }
110
+ :where(.bz-icon-morph-close) { transform: rotate(45deg); transition: all 200ms ease; }
111
+ :where(.bz-icon-morph-menu) { transform: scale(1); transition: all 200ms ease; }
96
112
 
97
- :where(.bz-icon-morph-play) {
98
- transform: scale(1.05);
99
- transition: all 150ms ease;
100
- }
101
- :where(.bz-icon-morph-pause) {
102
- transform: scale(0.95);
103
- transition: all 150ms ease;
104
- }
105
- :where(.bz-icon-morph-close) {
106
- transform: rotate(45deg);
107
- transition: all 200ms ease;
108
- }
109
- :where(.bz-icon-morph-menu) {
110
- transform: scale(1);
111
- transition: all 200ms ease;
112
- }
113
-
113
+ /* A11y */
114
114
  :where([data-bz-kb-focus="true"]:focus-visible) {
115
115
  outline: 2px solid var(--bz-icon-ring);
116
116
  outline-offset: 2px;
117
117
  border-radius: var(--bz-icon-ring-radius);
118
118
  }
119
119
 
120
+ /* Reduce motion */
120
121
  @media (prefers-reduced-motion: reduce) {
121
- :where(.bz-icon-spin),
122
+ :where(.bz-icon--spin),
122
123
  :where(.bz-icon-bounce),
123
124
  :where(.bz-icon-pulse),
124
125
  :where(.bz-icon-wiggle),
@@ -126,16 +127,15 @@ const CSS_CONTENT = `
126
127
  :where(.bz-icon-heartbeat),
127
128
  :where(.bz-icon-scale-in),
128
129
  :where(.bz-icon-slide-in) {
129
- animation: none;
130
+ animation: none !important;
131
+ animation-duration: 0s !important;
132
+ animation-iteration-count: 0 !important;
130
133
  }
131
-
132
134
  :where(.bz-icon-chevron),
133
- :where([class*="bz-icon-morph"]) {
134
- transition: none;
135
- }
135
+ :where([class*="bz-icon-morph"]) { transition: none !important; }
136
136
  }
137
137
  `;
138
- /** Detecta si estamos en desarrollo (compatible con todos los bundlers) */
138
+ /** Detecta si estamos en desarrollo (compatible) */
139
139
  function isDevelopment() {
140
140
  if (typeof window === "undefined")
141
141
  return false;
@@ -146,11 +146,7 @@ function isDevelopment() {
146
146
  window.location.protocol === "file:" ||
147
147
  window.location.search.includes("debug"));
148
148
  }
149
- // Luego úsala en los logs:
150
- if (isDevelopment()) {
151
- console.debug("🚀 Blazir Icons: Virtual CSS injected");
152
- }
153
- /** Detecta si el navegador soporta Constructable Stylesheets */
149
+ /** Soporte constructable stylesheets */
154
150
  function supportsConstructableStylesheets() {
155
151
  if (typeof window === "undefined")
156
152
  return false;
@@ -158,7 +154,7 @@ function supportsConstructableStylesheets() {
158
154
  "CSSStyleSheet" in window &&
159
155
  "replace" in CSSStyleSheet.prototype);
160
156
  }
161
- /** Inyección Virtual CSS para navegadores modernos */
157
+ /** Inyección Virtual CSS */
162
158
  async function injectVirtualCSS() {
163
159
  if (virtualStyleSheet || cssInjected)
164
160
  return;
@@ -171,17 +167,16 @@ async function injectVirtualCSS() {
171
167
  ];
172
168
  cssInjected = true;
173
169
  injectionMethod = "virtual";
174
- if (isDevelopment()) {
170
+ if (isDevelopment())
175
171
  console.debug("🚀 Blazir Icons: Virtual CSS injected (optimized)");
176
- }
177
172
  }
178
173
  catch (error) {
179
174
  console.warn("Virtual CSS failed, falling back to traditional:", error);
180
175
  virtualStyleSheet = null;
181
- return injectTraditionalCSS();
176
+ injectTraditionalCSS();
182
177
  }
183
178
  }
184
- /** Fallback tradicional para navegadores legacy */
179
+ /** Fallback tradicional */
185
180
  function injectTraditionalCSS() {
186
181
  if (cssInjected || typeof document === "undefined")
187
182
  return;
@@ -195,22 +190,21 @@ function injectTraditionalCSS() {
195
190
  document.head.insertBefore(style, document.head.firstChild);
196
191
  cssInjected = true;
197
192
  injectionMethod = "traditional";
198
- if (isDevelopment()) {
193
+ if (isDevelopment())
199
194
  console.debug("🔄 Blazir Icons: Traditional CSS injected (fallback)");
200
- }
201
195
  }
202
- /** API PRINCIPAL - Inyección híbrida inteligente */
203
- export async function injectIconEffectsCSS() {
196
+ /** API principal (singleton + carrera segura) */
197
+ export function injectIconEffectsCSS() {
204
198
  if (cssInjected || typeof window === "undefined")
205
- return;
206
- if (supportsConstructableStylesheets()) {
207
- await injectVirtualCSS();
208
- }
209
- else {
210
- injectTraditionalCSS();
211
- }
212
- }
213
- /** API adicional para casos específicos */
199
+ return Promise.resolve();
200
+ if (injectOncePromise)
201
+ return injectOncePromise;
202
+ injectOncePromise = supportsConstructableStylesheets()
203
+ ? injectVirtualCSS()
204
+ : (injectTraditionalCSS(), Promise.resolve());
205
+ return injectOncePromise;
206
+ }
207
+ /** API explícita virtual/tradicional */
214
208
  export async function injectVirtualIconCSS() {
215
209
  if (!supportsConstructableStylesheets()) {
216
210
  throw new Error("Constructable Stylesheets not supported");
@@ -220,7 +214,7 @@ export async function injectVirtualIconCSS() {
220
214
  export function injectTraditionalIconCSS() {
221
215
  injectTraditionalCSS();
222
216
  }
223
- /** Utility - Info del método usado */
217
+ /** Info */
224
218
  export function getInjectionInfo() {
225
219
  return {
226
220
  injected: cssInjected,
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { IconName } from "./icons/registry.js";
1
+ import type { IconName } from "./icons/registry.js";
2
2
  export type IconMode = "solid" | "outline" | "duotone";
3
3
  export type IconProps = {
4
4
  size?: number | string;
@@ -7,7 +7,7 @@ export declare function getMorphTransform(morphTo: IconProps["morphTo"]): string
7
7
  export declare function getSlideTransform(direction: IconProps["slideDirection"]): string;
8
8
  /** Combina todas las transformaciones */
9
9
  export declare function combineTransforms(props: Partial<IconProps>): string;
10
- /** Genera clases de animación basadas en props */
10
+ /** Clases de animación */
11
11
  export declare function getAnimationClasses(props: Partial<IconProps>): string[];
12
- /** Genera estilos de timing de animación */
12
+ /** Estilos de timing (no interfieren con spin) */
13
13
  export declare function getAnimationStyle(props: Partial<IconProps>): string;
@@ -40,31 +40,26 @@ export function getSlideTransform(direction) {
40
40
  /** Combina todas las transformaciones */
41
41
  export function combineTransforms(props) {
42
42
  const transforms = [];
43
- // Rotación base
44
43
  if (props.rotate) {
45
44
  const rot = typeof props.rotate === "number" ? `${props.rotate}deg` : props.rotate;
46
45
  transforms.push(`rotate(${rot})`);
47
46
  }
48
- // Flips
49
47
  if (props.flipH)
50
48
  transforms.push("scaleX(-1)");
51
49
  if (props.flipV)
52
50
  transforms.push("scaleY(-1)");
53
- // Chevron state
54
51
  const chevronTransform = getChevronTransform(props.chevronState);
55
52
  if (chevronTransform)
56
53
  transforms.push(chevronTransform);
57
- // Morph state
58
54
  const morphTransform = getMorphTransform(props.morphTo);
59
55
  if (morphTransform)
60
56
  transforms.push(morphTransform);
61
- // Slide
62
57
  const slideTransform = getSlideTransform(props.slideDirection);
63
58
  if (slideTransform)
64
59
  transforms.push(slideTransform);
65
60
  return transforms.length ? transforms.join(" ") : "";
66
61
  }
67
- /** Genera clases de animación basadas en props */
62
+ /** Clases de animación */
68
63
  export function getAnimationClasses(props) {
69
64
  const classes = [];
70
65
  if (props.scaleIn)
@@ -81,11 +76,12 @@ export function getAnimationClasses(props) {
81
76
  classes.push("bz-icon-heartbeat");
82
77
  if (props.pulse)
83
78
  classes.push("bz-icon-pulse");
79
+ // ✅ clase correcta de spin
84
80
  if (props.spin)
85
- classes.push("bz-icon-spin");
81
+ classes.push("bz-icon--spin");
86
82
  return classes;
87
83
  }
88
- /** Genera estilos de timing de animación */
84
+ /** Estilos de timing (no interfieren con spin) */
89
85
  export function getAnimationStyle(props) {
90
86
  const parts = [];
91
87
  if (props.animationDuration) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genarou/blazir-icons",
3
- "version": "1.1.5",
3
+ "version": "1.1.7",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "publishConfig": {