@genarou/blazir-icons 1.2.8 → 1.2.11
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 +206 -60
- package/dist/Icon.svelte.d.ts +1 -0
- package/dist/IconBase.svelte +43 -67
- package/dist/icons/Ai.svelte +6 -16
- package/dist/icons/Chat.svelte +18 -0
- package/dist/icons/Chat.svelte.d.ts +4 -0
- package/dist/icons/Contact.svelte +18 -0
- package/dist/icons/Contact.svelte.d.ts +4 -0
- package/dist/icons/Dashboard.svelte +3 -8
- package/dist/icons/DashboardOutlined.svelte +23 -0
- package/dist/icons/DashboardOutlined.svelte.d.ts +4 -0
- package/dist/icons/Download.svelte +5 -12
- package/dist/icons/EmailAnimated.svelte +34 -29
- package/dist/icons/Excel.svelte +18 -0
- package/dist/icons/Excel.svelte.d.ts +4 -0
- package/dist/icons/Filter.svelte +18 -0
- package/dist/icons/Filter.svelte.d.ts +4 -0
- package/dist/icons/Image.svelte +9 -14
- package/dist/icons/Pay.svelte +19 -0
- package/dist/icons/Pay.svelte.d.ts +4 -0
- package/dist/icons/Paypal.svelte +21 -0
- package/dist/icons/Paypal.svelte.d.ts +4 -0
- package/dist/icons/PowerPoint.svelte +18 -0
- package/dist/icons/PowerPoint.svelte.d.ts +4 -0
- package/dist/icons/Send.svelte +18 -0
- package/dist/icons/Send.svelte.d.ts +4 -0
- package/dist/icons/Word.svelte +19 -0
- package/dist/icons/Word.svelte.d.ts +4 -0
- package/dist/icons/registry.d.ts +10 -0
- package/dist/icons/registry.js +20 -1
- package/dist/icons-api.d.ts +11 -4
- package/dist/icons-api.js +11 -4
- package/dist/index.d.ts +0 -111
- package/dist/index.js +0 -114
- package/package.json +1 -1
package/dist/Icon.svelte
CHANGED
|
@@ -9,94 +9,233 @@
|
|
|
9
9
|
import type { IconProps } from "./types";
|
|
10
10
|
import { coerceSize } from "./utils/defaults";
|
|
11
11
|
|
|
12
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
13
|
+
// POOLS (1 IO por root scrolleable, 1 RO global)
|
|
14
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
15
|
+
type RootKey = Element | undefined;
|
|
16
|
+
type Entry = {
|
|
17
|
+
el: HTMLElement;
|
|
18
|
+
onViewportChange?: (v: boolean) => void;
|
|
19
|
+
onSizeChange?: (w: number, h: number) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
class IntersectionPool {
|
|
23
|
+
private pools = new Map<
|
|
24
|
+
RootKey,
|
|
25
|
+
{ io: IntersectionObserver; entries: Set<Entry> }
|
|
26
|
+
>();
|
|
27
|
+
|
|
28
|
+
register(root: RootKey, entry: Entry) {
|
|
29
|
+
let pool = this.pools.get(root);
|
|
30
|
+
if (!pool) {
|
|
31
|
+
const io = new IntersectionObserver(
|
|
32
|
+
(entries) => {
|
|
33
|
+
const p = this.pools.get(root);
|
|
34
|
+
if (!p) return;
|
|
35
|
+
for (const e of entries) {
|
|
36
|
+
const tgt = e.target as HTMLElement;
|
|
37
|
+
for (const item of p.entries) {
|
|
38
|
+
if (item.el === tgt) {
|
|
39
|
+
item.onViewportChange?.(e.isIntersecting);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{ root: root as Element | undefined, rootMargin: "200px" }
|
|
46
|
+
);
|
|
47
|
+
pool = { io, entries: new Set() };
|
|
48
|
+
this.pools.set(root, pool);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
pool.entries.add(entry);
|
|
52
|
+
pool.io.observe(entry.el);
|
|
53
|
+
|
|
54
|
+
return () => {
|
|
55
|
+
const p = this.pools.get(root);
|
|
56
|
+
if (!p) return;
|
|
57
|
+
p.io.unobserve(entry.el);
|
|
58
|
+
p.entries.delete(entry);
|
|
59
|
+
if (p.entries.size === 0) {
|
|
60
|
+
p.io.disconnect();
|
|
61
|
+
this.pools.delete(root);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
class ResizePool {
|
|
68
|
+
private ro: ResizeObserver | null = null;
|
|
69
|
+
private entries = new Set<Entry>();
|
|
70
|
+
|
|
71
|
+
private ensure() {
|
|
72
|
+
if (this.ro || typeof ResizeObserver === "undefined") return;
|
|
73
|
+
this.ro = new ResizeObserver((ros) => {
|
|
74
|
+
for (const r of ros) {
|
|
75
|
+
const tgt = r.target as HTMLElement;
|
|
76
|
+
for (const item of this.entries) {
|
|
77
|
+
if (item.el === tgt) {
|
|
78
|
+
item.onSizeChange?.(tgt.offsetWidth, tgt.offsetHeight);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
register(entry: Entry) {
|
|
87
|
+
this.ensure();
|
|
88
|
+
this.entries.add(entry);
|
|
89
|
+
this.ro?.observe(entry.el);
|
|
90
|
+
entry.onSizeChange?.(entry.el.offsetWidth, entry.el.offsetHeight); // inicial
|
|
91
|
+
return () => {
|
|
92
|
+
this.ro?.unobserve(entry.el);
|
|
93
|
+
this.entries.delete(entry);
|
|
94
|
+
if (this.entries.size === 0) {
|
|
95
|
+
this.ro?.disconnect();
|
|
96
|
+
this.ro = null;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const IO_POOL = new IntersectionPool();
|
|
103
|
+
const RO_POOL = new ResizePool();
|
|
104
|
+
|
|
105
|
+
function getScrollRoot(el: HTMLElement | null): Element | undefined {
|
|
106
|
+
let p: HTMLElement | null = el?.parentElement ?? null;
|
|
107
|
+
while (p) {
|
|
108
|
+
const s = getComputedStyle(p);
|
|
109
|
+
if (/(auto|scroll)/.test(`${s.overflow}${s.overflowX}${s.overflowY}`))
|
|
110
|
+
return p;
|
|
111
|
+
p = p.parentElement;
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
117
|
+
// PROPS
|
|
118
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
12
119
|
interface DynamicIconProps extends Omit<IconProps, "children"> {
|
|
13
120
|
name: IconName;
|
|
14
121
|
preset?: IconPreset;
|
|
15
122
|
variant?: IconVariant;
|
|
123
|
+
skeleton?: boolean;
|
|
16
124
|
}
|
|
17
125
|
|
|
18
126
|
const props: DynamicIconProps = $props();
|
|
127
|
+
const inputProps = $derived(() => ({ skeleton: false, ...props }));
|
|
19
128
|
|
|
20
|
-
|
|
21
|
-
const isHovered = $derived(
|
|
22
|
-
internalHovered || (props.parentHoverContext?.hovered ?? false)
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
const Comp = $derived.by(() => iconRegistry[props.name]);
|
|
26
|
-
|
|
27
|
-
// Preset y variant (opcionales)
|
|
129
|
+
const Comp = $derived.by(() => iconRegistry[inputProps().name]);
|
|
28
130
|
const presetProps = $derived(() =>
|
|
29
|
-
|
|
131
|
+
inputProps().preset ? iconPresets[inputProps().preset!] : {}
|
|
30
132
|
);
|
|
31
133
|
const variantProps = $derived(() =>
|
|
32
|
-
|
|
134
|
+
inputProps().variant ? iconVariants[inputProps().variant!] : {}
|
|
33
135
|
);
|
|
136
|
+
const mergedProps = $derived(() => ({
|
|
137
|
+
...presetProps(),
|
|
138
|
+
...variantProps(),
|
|
139
|
+
...inputProps(),
|
|
140
|
+
}));
|
|
34
141
|
|
|
35
|
-
//
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const effectiveColor = $derived(() => {
|
|
40
|
-
const baseColor = mergedProps.color || "currentColor";
|
|
41
|
-
if (isHovered && mergedProps.hoverColor) return mergedProps.hoverColor;
|
|
42
|
-
return baseColor;
|
|
43
|
-
});
|
|
142
|
+
// 🔹 No pasar `skeleton` al hijo
|
|
143
|
+
const childProps = $derived(() => {
|
|
144
|
+
const { skeleton, animationDuration, animationDelay, ...rest } =
|
|
145
|
+
mergedProps();
|
|
44
146
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
value?: number | string
|
|
48
|
-
): string | undefined =>
|
|
49
|
-
value === undefined
|
|
50
|
-
? undefined
|
|
51
|
-
: typeof value === "number"
|
|
52
|
-
? `${value}ms`
|
|
53
|
-
: value;
|
|
54
|
-
|
|
55
|
-
// Props finales para el Icono concreto
|
|
56
|
-
const iconProps = $derived(() => {
|
|
57
|
-
const {
|
|
58
|
-
name,
|
|
59
|
-
preset,
|
|
60
|
-
variant,
|
|
61
|
-
size,
|
|
62
|
-
color,
|
|
63
|
-
hoverColor,
|
|
64
|
-
activeColor,
|
|
65
|
-
parentHoverContext,
|
|
66
|
-
animationDuration,
|
|
67
|
-
animationDelay,
|
|
68
|
-
...rest
|
|
69
|
-
} = mergedProps;
|
|
147
|
+
const toMsString = (v?: string | number) =>
|
|
148
|
+
v === undefined ? undefined : typeof v === "number" ? `${v}ms` : v;
|
|
70
149
|
|
|
71
150
|
return {
|
|
72
151
|
...rest,
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
animationDuration: normalizeAnimationValue(animationDuration),
|
|
76
|
-
animationDelay: normalizeAnimationValue(animationDelay),
|
|
152
|
+
animationDuration: toMsString(animationDuration),
|
|
153
|
+
animationDelay: toMsString(animationDelay),
|
|
77
154
|
};
|
|
78
155
|
});
|
|
79
156
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
157
|
+
const boxSize = $derived(() => {
|
|
158
|
+
const s = coerceSize(mergedProps().size, 24);
|
|
159
|
+
return typeof s === "number" ? `${s}px` : s;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
163
|
+
// Lazy-mount con pooling
|
|
164
|
+
// ───────────────────────────────────────────────────────────────────────────
|
|
165
|
+
let hostEl: HTMLElement | null = $state(null);
|
|
166
|
+
let isVisible = $state(false);
|
|
167
|
+
let inViewport = false,
|
|
168
|
+
hasSize = false;
|
|
169
|
+
let unregIO: (() => void) | null = null,
|
|
170
|
+
unregRO: (() => void) | null = null;
|
|
171
|
+
|
|
172
|
+
function tryMount() {
|
|
173
|
+
if (!isVisible && inViewport && hasSize) {
|
|
174
|
+
isVisible = true;
|
|
175
|
+
unregIO?.();
|
|
176
|
+
unregIO = null;
|
|
177
|
+
unregRO?.();
|
|
178
|
+
unregRO = null;
|
|
179
|
+
}
|
|
85
180
|
}
|
|
181
|
+
|
|
182
|
+
$effect(() => {
|
|
183
|
+
if (
|
|
184
|
+
typeof window === "undefined" ||
|
|
185
|
+
typeof IntersectionObserver === "undefined"
|
|
186
|
+
) {
|
|
187
|
+
isVisible = true;
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!hostEl || isVisible) return;
|
|
191
|
+
|
|
192
|
+
const root = getScrollRoot(hostEl) ?? undefined;
|
|
193
|
+
unregIO = IO_POOL.register(root, {
|
|
194
|
+
el: hostEl,
|
|
195
|
+
onViewportChange: (v) => {
|
|
196
|
+
inViewport = v;
|
|
197
|
+
tryMount();
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
202
|
+
unregRO = RO_POOL.register({
|
|
203
|
+
el: hostEl,
|
|
204
|
+
onSizeChange: (w, h) => {
|
|
205
|
+
hasSize = w > 0 && h > 0;
|
|
206
|
+
tryMount();
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
hasSize = hostEl.offsetWidth > 0 && hostEl.offsetHeight > 0;
|
|
211
|
+
tryMount();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return () => {
|
|
215
|
+
unregIO?.();
|
|
216
|
+
unregIO = null;
|
|
217
|
+
unregRO?.();
|
|
218
|
+
unregRO = null;
|
|
219
|
+
};
|
|
220
|
+
});
|
|
86
221
|
</script>
|
|
87
222
|
|
|
88
223
|
{#if Comp}
|
|
89
224
|
<span
|
|
225
|
+
bind:this={hostEl}
|
|
90
226
|
class="bz-icon-wrapper"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
onmouseleave={handleMouseLeave}
|
|
227
|
+
style={`inline-size:${boxSize};block-size:${boxSize};`}
|
|
228
|
+
data-mounted={isVisible ? "true" : "false"}
|
|
94
229
|
>
|
|
95
|
-
|
|
230
|
+
{#if isVisible}
|
|
231
|
+
<Comp {...childProps()} />
|
|
232
|
+
{:else if mergedProps().skeleton}
|
|
233
|
+
<span class="bz-icon-skeleton" aria-hidden="true"></span>
|
|
234
|
+
{/if}
|
|
96
235
|
</span>
|
|
97
236
|
{:else}
|
|
98
|
-
<span class="bz-icon-error" data-icon={
|
|
99
|
-
⚠️ Icon not found: {
|
|
237
|
+
<span class="bz-icon-error" data-icon={inputProps().name}>
|
|
238
|
+
⚠️ Icon not found: {inputProps().name}
|
|
100
239
|
</span>
|
|
101
240
|
{/if}
|
|
102
241
|
|
|
@@ -107,12 +246,19 @@
|
|
|
107
246
|
justify-content: center;
|
|
108
247
|
line-height: 1;
|
|
109
248
|
}
|
|
249
|
+
.bz-icon-skeleton {
|
|
250
|
+
width: 100%;
|
|
251
|
+
height: 100%;
|
|
252
|
+
border-radius: var(--ui-radius, 0.25rem);
|
|
253
|
+
background: color-mix(in oklab, currentColor 12%, transparent);
|
|
254
|
+
opacity: 0.5;
|
|
255
|
+
}
|
|
110
256
|
.bz-icon-error {
|
|
111
257
|
display: inline-block;
|
|
112
258
|
width: 1em;
|
|
113
259
|
height: 1em;
|
|
114
260
|
background: var(--danger-color, #ef4444);
|
|
115
|
-
color: var(--danger-foreground,
|
|
261
|
+
color: var(--danger-foreground, #fff);
|
|
116
262
|
text-align: center;
|
|
117
263
|
line-height: 1;
|
|
118
264
|
font-size: 0.75rem;
|
package/dist/Icon.svelte.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ interface DynamicIconProps extends Omit<IconProps, "children"> {
|
|
|
5
5
|
name: IconName;
|
|
6
6
|
preset?: IconPreset;
|
|
7
7
|
variant?: IconVariant;
|
|
8
|
+
skeleton?: boolean;
|
|
8
9
|
}
|
|
9
10
|
declare const Icon: import("svelte").Component<DynamicIconProps, {}, "">;
|
|
10
11
|
type Icon = ReturnType<typeof Icon>;
|
package/dist/IconBase.svelte
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
<!-- src/lib/IconBase.svelte -->
|
|
2
1
|
<script lang="ts">
|
|
3
2
|
import { type IconEffectOptions, iconEffects } from "./effects.js";
|
|
4
3
|
import type { IconMode, IconProps } from "./types.js";
|
|
@@ -13,16 +12,9 @@
|
|
|
13
12
|
normalizeClass,
|
|
14
13
|
} from "./utils/defaults.js";
|
|
15
14
|
|
|
16
|
-
// ───────────────────────────────────────────────────────────────────────────
|
|
17
|
-
// Helpers
|
|
18
|
-
// ───────────────────────────────────────────────────────────────────────────
|
|
19
|
-
function uid(): string {
|
|
20
|
-
return Math.random().toString(36).slice(2);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Normaliza duración en ms: acepta number, '200ms' o '0.2s'
|
|
24
15
|
const DEFAULT_MS = 180;
|
|
25
16
|
const DEFAULT_EASING = "cubic-bezier(.2,.8,.2,1)";
|
|
17
|
+
|
|
26
18
|
function normalizeMs(v?: number | string): number {
|
|
27
19
|
if (v == null) return DEFAULT_MS;
|
|
28
20
|
if (typeof v === "number") return v;
|
|
@@ -33,42 +25,31 @@
|
|
|
33
25
|
return Number.isFinite(n) ? n : DEFAULT_MS;
|
|
34
26
|
}
|
|
35
27
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const props: IconProps & { mode?: IconMode } = $props();
|
|
28
|
+
function uid(): string {
|
|
29
|
+
return Math.random().toString(36).slice(2);
|
|
30
|
+
}
|
|
40
31
|
|
|
41
|
-
|
|
32
|
+
const props: IconProps & { mode?: IconMode } = $props();
|
|
42
33
|
let internalHovered = $state(false);
|
|
43
34
|
const isHovered = $derived(
|
|
44
35
|
internalHovered || (props.parentHoverContext?.hovered ?? false)
|
|
45
36
|
);
|
|
46
37
|
|
|
47
|
-
// ── Color por defecto dark-first con fallbacks ─────────────────────────────
|
|
48
|
-
// 1) --icon-fg (si existe)
|
|
49
|
-
// 2) --ui-muted-fg (definido distinto en claro/oscuro)
|
|
50
|
-
// 3) currentColor (último fallback)
|
|
51
38
|
const DEFAULT_ICON_COLOR = "var(--icon-fg, var(--ui-muted-fg, currentColor))";
|
|
52
|
-
|
|
53
39
|
const effectiveColor = $derived(
|
|
54
40
|
(isHovered && props.hoverColor ? props.hoverColor : props.color) ??
|
|
55
41
|
DEFAULT_ICON_COLOR
|
|
56
42
|
);
|
|
57
43
|
|
|
58
|
-
// ── Modo / clases / defaults compartidos ───────────────────────────────────
|
|
59
44
|
const mode = $derived(props.mode ?? "solid");
|
|
60
45
|
const klass = $derived(normalizeClass(props));
|
|
61
46
|
const common = $derived(commonDefaults(props));
|
|
62
47
|
|
|
63
|
-
// Pasar color efectivo al pipeline visual
|
|
64
48
|
const propsWithEffectiveColor = $derived({ ...props, color: effectiveColor });
|
|
65
49
|
const visual = $derived(modeDefaults(mode, propsWithEffectiveColor));
|
|
66
|
-
|
|
67
|
-
// ── Animaciones (clases + timing inline) ───────────────────────────────────
|
|
68
50
|
const animationClasses = $derived(getAnimationClasses(props).join(" "));
|
|
69
51
|
const timingStyle = $derived(getAnimationStyle(props));
|
|
70
52
|
|
|
71
|
-
// ── Transform sólo via CSS (no colisionar con transform del <g>) ──────────
|
|
72
53
|
const cssTransformOnly = $derived(
|
|
73
54
|
combineTransforms({
|
|
74
55
|
...props,
|
|
@@ -78,7 +59,6 @@
|
|
|
78
59
|
})
|
|
79
60
|
);
|
|
80
61
|
|
|
81
|
-
// ── Duración de spin como custom prop ──────────────────────────────────────
|
|
82
62
|
const spinDuration = $derived(
|
|
83
63
|
props.spin
|
|
84
64
|
? props.spin === true
|
|
@@ -89,7 +69,6 @@
|
|
|
89
69
|
: null
|
|
90
70
|
);
|
|
91
71
|
|
|
92
|
-
// ── Transición global (color/fill/stroke/transform/opacity) ───────────────
|
|
93
72
|
const hoverMs = $derived(
|
|
94
73
|
normalizeMs(props.transitionMs ?? props.animationDuration)
|
|
95
74
|
);
|
|
@@ -97,29 +76,22 @@
|
|
|
97
76
|
props.transitionEasing ?? props.animationEasing ?? DEFAULT_EASING
|
|
98
77
|
);
|
|
99
78
|
|
|
100
|
-
// ── style final (string) ───────────────────────────────────────────────────
|
|
101
79
|
const style = $derived(() => {
|
|
102
80
|
const parts: string[] = [];
|
|
103
81
|
if (props.style)
|
|
104
82
|
parts.push(props.style.endsWith(";") ? props.style : `${props.style};`);
|
|
105
|
-
if (cssTransformOnly) parts.push(`transform
|
|
106
|
-
parts.push("transform-origin:
|
|
107
|
-
if (spinDuration) parts.push(`--bz-spin
|
|
83
|
+
if (cssTransformOnly) parts.push(`transform:${cssTransformOnly};`);
|
|
84
|
+
parts.push("transform-origin:center;");
|
|
85
|
+
if (spinDuration) parts.push(`--bz-spin:${spinDuration};`);
|
|
108
86
|
if (timingStyle) parts.push(timingStyle);
|
|
109
|
-
|
|
110
|
-
if (effectiveColor) parts.push(`color: ${effectiveColor};`);
|
|
111
|
-
// Transición universal y suave
|
|
87
|
+
if (effectiveColor) parts.push(`color:${effectiveColor};`);
|
|
112
88
|
parts.push(
|
|
113
|
-
`transition:
|
|
114
|
-
`
|
|
115
|
-
` stroke ${hoverMs}ms ${hoverEase},` +
|
|
116
|
-
` transform ${hoverMs}ms ${hoverEase},` +
|
|
117
|
-
` opacity ${hoverMs}ms ${hoverEase};`
|
|
89
|
+
`transition:color ${hoverMs}ms ${hoverEase},fill ${hoverMs}ms ${hoverEase},` +
|
|
90
|
+
`stroke ${hoverMs}ms ${hoverEase},transform ${hoverMs}ms ${hoverEase},opacity ${hoverMs}ms ${hoverEase};`
|
|
118
91
|
);
|
|
119
92
|
return parts.join(" ");
|
|
120
93
|
});
|
|
121
94
|
|
|
122
|
-
// ── A11y ───────────────────────────────────────────────────────────────────
|
|
123
95
|
const ariaHidden = $derived(props.decorative ? "true" : undefined);
|
|
124
96
|
const computedTitleId = $derived(
|
|
125
97
|
props.title ? (props.titleId ?? `bz-icon-title-${uid()}`) : undefined
|
|
@@ -131,12 +103,9 @@
|
|
|
131
103
|
!props.decorative && props.title ? computedTitleId : undefined
|
|
132
104
|
);
|
|
133
105
|
|
|
134
|
-
// ── Tamaño final ───────────────────────────────────────────────────────────
|
|
135
106
|
const finalSize = $derived(
|
|
136
107
|
typeof common.size === "number" ? `${common.size}px` : common.size
|
|
137
108
|
);
|
|
138
|
-
|
|
139
|
-
// ── Attrs seguros (no permitir width/height externos) ──────────────────────
|
|
140
109
|
const safeAttrs = $derived(() => {
|
|
141
110
|
const a = { ...(props.attrs ?? {}) };
|
|
142
111
|
delete (a as any).width;
|
|
@@ -144,21 +113,15 @@
|
|
|
144
113
|
return a;
|
|
145
114
|
});
|
|
146
115
|
|
|
147
|
-
// ── Clase final ────────────────────────────────────────────────────────────
|
|
148
116
|
const finalClass = $derived(
|
|
149
|
-
|
|
117
|
+
`bz-icon ${klass} ${animationClasses} ${props.chevronState ? "bz-icon-chevron" : ""}`.trim()
|
|
150
118
|
);
|
|
151
119
|
|
|
152
|
-
// ── Centro del viewBox para rot/flip exactos en SVG ────────────────────────
|
|
153
120
|
function getViewBoxCenter(vb: string) {
|
|
154
|
-
const
|
|
155
|
-
const [minX, minY, w, h] = parts.length === 4 ? parts : [0, 0, 24, 24];
|
|
121
|
+
const [minX, minY, w, h] = vb.trim().split(/\s+/).map(Number);
|
|
156
122
|
return { cx: minX + w / 2, cy: minY + h / 2 };
|
|
157
123
|
}
|
|
158
124
|
const center = $derived(getViewBoxCenter(common.viewBox));
|
|
159
|
-
const cx = $derived(center.cx);
|
|
160
|
-
const cy = $derived(center.cy);
|
|
161
|
-
|
|
162
125
|
const svgTransform = $derived(() => {
|
|
163
126
|
const cmds: string[] = [];
|
|
164
127
|
if (props.rotate != null) {
|
|
@@ -166,32 +129,21 @@
|
|
|
166
129
|
typeof props.rotate === "number"
|
|
167
130
|
? props.rotate
|
|
168
131
|
: parseFloat(String(props.rotate));
|
|
169
|
-
if (!isNaN(r)) cmds.push(`rotate(${r} ${cx} ${cy})`);
|
|
132
|
+
if (!isNaN(r)) cmds.push(`rotate(${r} ${center.cx} ${center.cy})`);
|
|
170
133
|
}
|
|
171
134
|
if (props.flipH || props.flipV) {
|
|
172
|
-
const sx = props.flipH ? -1 : 1
|
|
173
|
-
|
|
135
|
+
const sx = props.flipH ? -1 : 1,
|
|
136
|
+
sy = props.flipV ? -1 : 1;
|
|
174
137
|
cmds.push(
|
|
175
|
-
`translate(${cx} ${cy}) scale(${sx} ${sy}) translate(${-cx} ${-cy})`
|
|
138
|
+
`translate(${center.cx} ${center.cy}) scale(${sx} ${sy}) translate(${-center.cx} ${-center.cy})`
|
|
176
139
|
);
|
|
177
140
|
}
|
|
178
141
|
return cmds.join(" ");
|
|
179
142
|
});
|
|
180
143
|
|
|
181
|
-
// ── Hover handlers ─────────────────────────────────────────────────────────
|
|
182
|
-
function handleMouseEnter() {
|
|
183
|
-
internalHovered = true;
|
|
184
|
-
}
|
|
185
|
-
function handleMouseLeave() {
|
|
186
|
-
internalHovered = false;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// ── Efectos declarativos (props.effects > attrs.* retrocompat) ─────────────
|
|
190
144
|
let svgRef: SVGSVGElement | null = $state(null);
|
|
191
|
-
|
|
192
145
|
$effect(() => {
|
|
193
146
|
if (!svgRef) return;
|
|
194
|
-
|
|
195
147
|
const effectsOpts: IconEffectOptions = { ...(props.effects ?? {}) };
|
|
196
148
|
const a = props.attrs ?? {};
|
|
197
149
|
if (a.spinOnHover) effectsOpts.spinOnHover = true;
|
|
@@ -203,13 +155,18 @@
|
|
|
203
155
|
if (a.heartbeatOnActive) effectsOpts.heartbeatOnActive = true;
|
|
204
156
|
if (a.hoverScale) effectsOpts.hoverScale = a.hoverScale;
|
|
205
157
|
if (a.pressScale) effectsOpts.pressScale = a.pressScale;
|
|
206
|
-
|
|
207
|
-
// Importante: IconBase ya define transition en style(); iconEffects no la pisa.
|
|
208
158
|
if (Object.keys(effectsOpts).length > 0) {
|
|
209
159
|
const controller = iconEffects(svgRef, effectsOpts);
|
|
210
160
|
return () => controller.destroy();
|
|
211
161
|
}
|
|
212
162
|
});
|
|
163
|
+
|
|
164
|
+
function handleMouseEnter() {
|
|
165
|
+
internalHovered = true;
|
|
166
|
+
}
|
|
167
|
+
function handleMouseLeave() {
|
|
168
|
+
internalHovered = false;
|
|
169
|
+
}
|
|
213
170
|
</script>
|
|
214
171
|
|
|
215
172
|
<svg
|
|
@@ -242,3 +199,22 @@
|
|
|
242
199
|
{@render props.children?.()}
|
|
243
200
|
</g>
|
|
244
201
|
</svg>
|
|
202
|
+
|
|
203
|
+
<style>
|
|
204
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
205
|
+
.bz-icon {
|
|
206
|
+
animation: bzIconIn 0.18s cubic-bezier(0.2, 0.8, 0.2, 1) both;
|
|
207
|
+
will-change: opacity, transform;
|
|
208
|
+
}
|
|
209
|
+
@keyframes bzIconIn {
|
|
210
|
+
from {
|
|
211
|
+
opacity: 0;
|
|
212
|
+
transform: translateY(2px) scale(0.985);
|
|
213
|
+
}
|
|
214
|
+
to {
|
|
215
|
+
opacity: 1;
|
|
216
|
+
transform: none;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
</style>
|
package/dist/icons/Ai.svelte
CHANGED
|
@@ -1,28 +1,18 @@
|
|
|
1
|
-
<!-- src/lib/icons/GearSpark.svelte -->
|
|
2
1
|
<script lang="ts">
|
|
3
2
|
import IconBase from "../IconBase.svelte";
|
|
4
3
|
import type { IconProps } from "../types";
|
|
5
4
|
|
|
6
5
|
const props: IconProps = $props();
|
|
7
|
-
const ariaLabel = props.ariaLabel ?? "Gear Spark";
|
|
8
|
-
const title = props.title ?? "";
|
|
9
6
|
</script>
|
|
10
7
|
|
|
11
8
|
<IconBase
|
|
12
9
|
{...props}
|
|
13
|
-
mode=
|
|
10
|
+
mode="solid"
|
|
14
11
|
viewBox="0 0 24 24"
|
|
15
|
-
{ariaLabel}
|
|
16
|
-
{title}
|
|
12
|
+
ariaLabel={props.ariaLabel ?? "File settings icon"}
|
|
13
|
+
title={props.title ?? ""}
|
|
17
14
|
>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
d="m12.594 23.258l-.012.002l-.071.035l-.02.004l-.014-.004l-.071-.036q-.016-.004-.024.006l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.016-.018m.264-.113l-.014.002l-.184.093l-.01.01l-.003.011l.018.43l.005.012l.008.008l.201.092q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.003-.011l.018-.43l-.003-.012l-.01-.01z"
|
|
22
|
-
/>
|
|
23
|
-
<path
|
|
24
|
-
fill="currentColor"
|
|
25
|
-
d="M9.107 5.448c.598-1.75 3.016-1.803 3.725-.159l.06.16l.807 2.36a4 4 0 0 0 2.276 2.411l.217.081l2.36.806c1.75.598 1.803 3.016.16 3.725l-.16.06l-2.36.807a4 4 0 0 0-2.412 2.276l-.081.216l-.806 2.361c-.598 1.75-3.016 1.803-3.724.16l-.062-.16l-.806-2.36a4 4 0 0 0-2.276-2.412l-.216-.081l-2.36-.806c-1.751-.598-1.804-3.016-.16-3.724l.16-.062l2.36-.806A4 4 0 0 0 8.22 8.025l.081-.216zM19 2a1 1 0 0 1 .898.56l.048.117l.35 1.026l1.027.35a1 1 0 0 1 .118 1.845l-.118.048l-1.026.35l-.35 1.027a1 1 0 0 1-1.845.117l-.048-.117l-.35-1.026l-1.027-.35a1 1 0 0 1-.118-1.845l.118-.048l1.026-.35l.35-1.027A1 1 0 0 1 19 2"
|
|
26
|
-
/>
|
|
27
|
-
</g>
|
|
15
|
+
<path
|
|
16
|
+
d="m20.467 8.694l.246-.566a4.36 4.36 0 0 1 2.22-2.25l.759-.339a.53.53 0 0 0 0-.963l-.717-.319a4.37 4.37 0 0 1-2.251-2.326l-.253-.611a.506.506 0 0 0-.942 0l-.253.61a4.37 4.37 0 0 1-2.25 2.327l-.718.32a.53.53 0 0 0 0 .962l.76.338a4.36 4.36 0 0 1 2.219 2.251l.246.566c.18.414.753.414.934 0M5.8 16h2.154l.6-1.5h2.892l.6 1.5H14.2L11 8H9zm4.2-5.115l.646 1.615H9.354zM15 16V8h2v8zM3 3a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1v-9h-2v8H4V5h10V3z"
|
|
17
|
+
/>
|
|
28
18
|
</IconBase>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconBase from "../IconBase.svelte";
|
|
3
|
+
import type { IconProps } from "../types";
|
|
4
|
+
|
|
5
|
+
const props: IconProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<IconBase
|
|
9
|
+
{...props}
|
|
10
|
+
mode="solid"
|
|
11
|
+
viewBox="0 0 24 24"
|
|
12
|
+
ariaLabel={props.ariaLabel ?? "Chat bubble icon"}
|
|
13
|
+
title={props.title ?? ""}
|
|
14
|
+
>
|
|
15
|
+
<path
|
|
16
|
+
d="M9 22a1 1 0 0 1-1-1v-3H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6.1l-3.7 3.71c-.2.19-.45.29-.7.29zm8-11V9h-2v2zm-4 0V9h-2v2zm-4 0V9H7v2z"
|
|
17
|
+
/>
|
|
18
|
+
</IconBase>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import IconBase from "../IconBase.svelte";
|
|
3
|
+
import type { IconProps } from "../types";
|
|
4
|
+
|
|
5
|
+
const props: IconProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<IconBase
|
|
9
|
+
{...props}
|
|
10
|
+
mode="solid"
|
|
11
|
+
viewBox="0 0 24 24"
|
|
12
|
+
ariaLabel={props.ariaLabel ?? "Control panel icon"}
|
|
13
|
+
title={props.title ?? ""}
|
|
14
|
+
>
|
|
15
|
+
<path
|
|
16
|
+
d="M4 2a1 1 0 0 0-1 1v2h2V4h14v16H5v-1H3v2a1 1 0 0 0 1 1h16a1 1 0 0 0 1-1V3a1 1 0 0 0-1-1zm5 14a3 3 0 1 1 6 0zm3-4a2 2 0 1 1 0-4a2 2 0 0 1 0 4M6 9V7H2v2zm0 2v2H2v-2zm0 6v-2H2v2z"
|
|
17
|
+
/>
|
|
18
|
+
</IconBase>
|
|
@@ -1,23 +1,18 @@
|
|
|
1
|
-
<!-- src/lib/icons/TableChart.svelte -->
|
|
2
1
|
<script lang="ts">
|
|
3
2
|
import IconBase from "../IconBase.svelte";
|
|
4
3
|
import type { IconProps } from "../types";
|
|
4
|
+
|
|
5
5
|
const props: IconProps = $props();
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<IconBase
|
|
9
9
|
{...props}
|
|
10
|
-
mode="
|
|
10
|
+
mode="solid"
|
|
11
11
|
viewBox="0 0 24 24"
|
|
12
|
-
ariaLabel={props.ariaLabel ?? "
|
|
12
|
+
ariaLabel={props.ariaLabel ?? "Grid view icon"}
|
|
13
13
|
title={props.title ?? ""}
|
|
14
|
-
strokeWidth={props.strokeWidth ?? 1.5}
|
|
15
|
-
strokeLinecap={props.strokeLinecap ?? "round"}
|
|
16
|
-
strokeLinejoin={props.strokeLinejoin ?? "round"}
|
|
17
14
|
>
|
|
18
|
-
<!-- Sin fill: que herede del SVG (outline) -->
|
|
19
15
|
<path
|
|
20
16
|
d="M4 13h6c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v8c0 .55.45 1 1 1m0 8h6c.55 0 1-.45 1-1v-4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1m10 0h6c.55 0 1-.45 1-1v-8c0-.55-.45-1-1-1h-6c-.55 0-1 .45-1 1v8c0 .55.45 1 1 1M13 4v4c0 .55.45 1 1 1h6c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1h-6c-.55 0-1 .45-1 1"
|
|
21
|
-
fill="none"
|
|
22
17
|
/>
|
|
23
18
|
</IconBase>
|