@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 +20 -12
- package/dist/IconBase.svelte +99 -40
- package/dist/icons-api.d.ts +2 -2
- package/dist/icons-api.js +0 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/styles/hybrid-inject.d.ts +3 -3
- package/dist/styles/hybrid-inject.js +46 -52
- package/dist/types.d.ts +1 -1
- package/dist/utils/animations.d.ts +2 -2
- package/dist/utils/animations.js +4 -8
- package/package.json +1 -1
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,
|
|
10
|
-
color
|
|
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
|
-
|
|
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
|
-
|
|
44
|
+
// ❌ ANTES: const passProps = $derived(() => ({ ... }))
|
|
45
|
+
// ✅ AHORA:
|
|
46
|
+
const passProps = $derived({
|
|
37
47
|
size: coerceSize(size, 24),
|
|
38
|
-
|
|
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}
|
package/dist/IconBase.svelte
CHANGED
|
@@ -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)); //
|
|
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
|
|
23
|
-
const animationStyle = $derived(getAnimationStyle(props));
|
|
25
|
+
const timingStyle = $derived(getAnimationStyle(props)); // duration/delay/easing
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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(";") ? ";" : ""}
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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;
|
|
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={
|
|
78
|
-
aria-label={
|
|
79
|
-
aria-labelledby={
|
|
142
|
+
aria-hidden={ariaHidden}
|
|
143
|
+
aria-label={ariaLabel}
|
|
144
|
+
aria-labelledby={ariaLabelledby}
|
|
80
145
|
focusable="false"
|
|
81
146
|
{style}
|
|
82
|
-
fill={
|
|
83
|
-
stroke={
|
|
84
|
-
stroke-width={
|
|
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
|
-
{
|
|
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>
|
package/dist/icons-api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IconComponent, IconName } from "./
|
|
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 |
|
|
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
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
|
|
8
|
-
export { default as
|
|
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
|
|
12
|
-
export { default as
|
|
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
|
|
1
|
+
/** API principal (singleton + carrera segura) */
|
|
2
2
|
export declare function injectIconEffectsCSS(): Promise<void>;
|
|
3
|
-
/** API
|
|
3
|
+
/** API explícita virtual/tradicional */
|
|
4
4
|
export declare function injectVirtualIconCSS(): Promise<void>;
|
|
5
5
|
export declare function injectTraditionalIconCSS(): void;
|
|
6
|
-
/**
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
176
|
+
injectTraditionalCSS();
|
|
182
177
|
}
|
|
183
178
|
}
|
|
184
|
-
/** Fallback tradicional
|
|
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
|
|
203
|
-
export
|
|
196
|
+
/** API principal (singleton + carrera segura) */
|
|
197
|
+
export function injectIconEffectsCSS() {
|
|
204
198
|
if (cssInjected || typeof window === "undefined")
|
|
205
|
-
return;
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
injectTraditionalCSS();
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
/** API
|
|
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
|
-
/**
|
|
217
|
+
/** Info */
|
|
224
218
|
export function getInjectionInfo() {
|
|
225
219
|
return {
|
|
226
220
|
injected: cssInjected,
|
package/dist/types.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
10
|
+
/** Clases de animación */
|
|
11
11
|
export declare function getAnimationClasses(props: Partial<IconProps>): string[];
|
|
12
|
-
/**
|
|
12
|
+
/** Estilos de timing (no interfieren con spin) */
|
|
13
13
|
export declare function getAnimationStyle(props: Partial<IconProps>): string;
|
package/dist/utils/animations.js
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
|
81
|
+
classes.push("bz-icon--spin");
|
|
86
82
|
return classes;
|
|
87
83
|
}
|
|
88
|
-
/**
|
|
84
|
+
/** Estilos de timing (no interfieren con spin) */
|
|
89
85
|
export function getAnimationStyle(props) {
|
|
90
86
|
const parts = [];
|
|
91
87
|
if (props.animationDuration) {
|