@genarou/blazir-icons 1.2.4 → 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 +63 -51
- package/dist/IconBase.svelte.d.ts +1 -1
- package/dist/icons/Ai.svelte +18 -0
- package/dist/icons/Ai.svelte.d.ts +4 -0
- package/dist/icons/Cart.svelte +28 -0
- package/dist/icons/Cart.svelte.d.ts +4 -0
- package/dist/icons/Category.svelte +57 -0
- package/dist/icons/Category.svelte.d.ts +4 -0
- package/dist/icons/Chat.svelte +18 -0
- package/dist/icons/Chat.svelte.d.ts +4 -0
- package/dist/icons/CheckList.svelte +17 -7
- package/dist/icons/CircleExclamation.svelte +17 -9
- package/dist/icons/CircleExclamationOutlined.svelte +28 -0
- package/dist/icons/CircleExclamationOutlined.svelte.d.ts +4 -0
- package/dist/icons/CircleInfo.svelte +16 -9
- package/dist/icons/CircleInfoOutlined.svelte +28 -0
- package/dist/icons/CircleInfoOutlined.svelte.d.ts +4 -0
- package/dist/icons/CircleQuestion.svelte +11 -10
- package/dist/icons/CircleQuestionOutlined.svelte +32 -0
- package/dist/icons/CircleQuestionOutlined.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/Edit.svelte +28 -0
- package/dist/icons/Edit.svelte.d.ts +4 -0
- package/dist/icons/EditOutline.svelte +16 -14
- package/dist/icons/EmailAnimated.svelte +34 -29
- package/dist/icons/ErrorO.svelte +17 -8
- package/dist/icons/Excel.svelte +6 -31
- package/dist/icons/Filter.svelte +18 -0
- package/dist/icons/Filter.svelte.d.ts +4 -0
- package/dist/icons/Form.svelte +23 -0
- package/dist/icons/Form.svelte.d.ts +4 -0
- package/dist/icons/Image.svelte +9 -14
- package/dist/icons/Notes.svelte +21 -5
- 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/Png.svelte +40 -3
- package/dist/icons/PowerPoint.svelte +18 -0
- package/dist/icons/PowerPoint.svelte.d.ts +4 -0
- package/dist/icons/Print.svelte +47 -0
- package/dist/icons/Print.svelte.d.ts +4 -0
- package/dist/icons/Profit.svelte +28 -0
- package/dist/icons/Profit.svelte.d.ts +4 -0
- package/dist/icons/Send.svelte +18 -0
- package/dist/icons/Send.svelte.d.ts +4 -0
- package/dist/icons/Team.svelte +20 -5
- package/dist/icons/Word.svelte +9 -3
- package/dist/icons/Xml.svelte +22 -3
- package/dist/icons/registry.d.ts +20 -7
- package/dist/icons/registry.js +39 -11
- package/dist/icons-api.d.ts +33 -47
- package/dist/icons-api.js +28 -46
- package/dist/index.d.ts +0 -116
- package/dist/index.js +0 -119
- package/dist/types.d.ts +5 -1
- package/package.json +1 -1
- package/dist/icons/LoadingSquares.svelte +0 -128
- package/dist/icons/LoadingSquares.svelte.d.ts +0 -7
- package/dist/icons/MainComponent.svelte +0 -18
- package/dist/icons/MainComponent.svelte.d.ts +0 -4
- package/dist/icons/Powerpoint.svelte +0 -13
- package/dist/icons/Powerpoint.svelte.d.ts +0 -4
- package/dist/icons/Search.svelte +0 -13
- package/dist/icons/Search.svelte.d.ts +0 -4
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(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,55 +1,55 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { type IconEffectOptions, iconEffects } from "./effects.js";
|
|
3
|
-
import type { IconMode, IconProps } from "./types";
|
|
3
|
+
import type { IconMode, IconProps } from "./types.js";
|
|
4
4
|
import {
|
|
5
5
|
combineTransforms,
|
|
6
6
|
getAnimationClasses,
|
|
7
7
|
getAnimationStyle,
|
|
8
|
-
} from "./utils/animations";
|
|
8
|
+
} from "./utils/animations.js";
|
|
9
9
|
import {
|
|
10
10
|
commonDefaults,
|
|
11
11
|
modeDefaults,
|
|
12
12
|
normalizeClass,
|
|
13
|
-
} from "./utils/defaults";
|
|
13
|
+
} from "./utils/defaults.js";
|
|
14
|
+
|
|
15
|
+
const DEFAULT_MS = 180;
|
|
16
|
+
const DEFAULT_EASING = "cubic-bezier(.2,.8,.2,1)";
|
|
17
|
+
|
|
18
|
+
function normalizeMs(v?: number | string): number {
|
|
19
|
+
if (v == null) return DEFAULT_MS;
|
|
20
|
+
if (typeof v === "number") return v;
|
|
21
|
+
const s = String(v).trim();
|
|
22
|
+
if (s.endsWith("ms")) return parseFloat(s);
|
|
23
|
+
if (s.endsWith("s")) return parseFloat(s) * 1000;
|
|
24
|
+
const n = parseFloat(s);
|
|
25
|
+
return Number.isFinite(n) ? n : DEFAULT_MS;
|
|
26
|
+
}
|
|
14
27
|
|
|
15
|
-
// id simple para <title>
|
|
16
28
|
function uid(): string {
|
|
17
29
|
return Math.random().toString(36).slice(2);
|
|
18
30
|
}
|
|
19
31
|
|
|
20
32
|
const props: IconProps & { mode?: IconMode } = $props();
|
|
21
|
-
|
|
22
|
-
// ── Interacción ────────────────────────────────────────────────────────────
|
|
23
33
|
let internalHovered = $state(false);
|
|
24
34
|
const isHovered = $derived(
|
|
25
35
|
internalHovered || (props.parentHoverContext?.hovered ?? false)
|
|
26
36
|
);
|
|
27
37
|
|
|
28
|
-
// ── Color por defecto dark-first con fallbacks ─────────────────────────────
|
|
29
|
-
// 1) --icon-fg (si existe)
|
|
30
|
-
// 2) --ui-muted-fg (ya lo defines distinto en claro/oscuro)
|
|
31
|
-
// 3) currentColor (último fallback)
|
|
32
38
|
const DEFAULT_ICON_COLOR = "var(--icon-fg, var(--ui-muted-fg, currentColor))";
|
|
33
|
-
|
|
34
39
|
const effectiveColor = $derived(
|
|
35
40
|
(isHovered && props.hoverColor ? props.hoverColor : props.color) ??
|
|
36
41
|
DEFAULT_ICON_COLOR
|
|
37
42
|
);
|
|
38
43
|
|
|
39
|
-
// ── Modo / clases / defaults compartidos ───────────────────────────────────
|
|
40
44
|
const mode = $derived(props.mode ?? "solid");
|
|
41
45
|
const klass = $derived(normalizeClass(props));
|
|
42
46
|
const common = $derived(commonDefaults(props));
|
|
43
47
|
|
|
44
|
-
// Pasar color efectivo al pipeline visual
|
|
45
48
|
const propsWithEffectiveColor = $derived({ ...props, color: effectiveColor });
|
|
46
49
|
const visual = $derived(modeDefaults(mode, propsWithEffectiveColor));
|
|
47
|
-
|
|
48
|
-
// ── Animaciones (clases + timing inline) ───────────────────────────────────
|
|
49
50
|
const animationClasses = $derived(getAnimationClasses(props).join(" "));
|
|
50
51
|
const timingStyle = $derived(getAnimationStyle(props));
|
|
51
52
|
|
|
52
|
-
// ── Transform sólo CSS (no colisionar con transform del <g>) ──────────────
|
|
53
53
|
const cssTransformOnly = $derived(
|
|
54
54
|
combineTransforms({
|
|
55
55
|
...props,
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
})
|
|
60
60
|
);
|
|
61
61
|
|
|
62
|
-
// ── Duración de spin como custom prop ──────────────────────────────────────
|
|
63
62
|
const spinDuration = $derived(
|
|
64
63
|
props.spin
|
|
65
64
|
? props.spin === true
|
|
@@ -70,21 +69,29 @@
|
|
|
70
69
|
: null
|
|
71
70
|
);
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
const hoverMs = $derived(
|
|
73
|
+
normalizeMs(props.transitionMs ?? props.animationDuration)
|
|
74
|
+
);
|
|
75
|
+
const hoverEase = $derived(
|
|
76
|
+
props.transitionEasing ?? props.animationEasing ?? DEFAULT_EASING
|
|
77
|
+
);
|
|
78
|
+
|
|
74
79
|
const style = $derived(() => {
|
|
75
80
|
const parts: string[] = [];
|
|
76
81
|
if (props.style)
|
|
77
82
|
parts.push(props.style.endsWith(";") ? props.style : `${props.style};`);
|
|
78
|
-
if (cssTransformOnly) parts.push(`transform
|
|
79
|
-
parts.push("transform-origin:
|
|
80
|
-
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};`);
|
|
81
86
|
if (timingStyle) parts.push(timingStyle);
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
if (effectiveColor) parts.push(`color:${effectiveColor};`);
|
|
88
|
+
parts.push(
|
|
89
|
+
`transition:color ${hoverMs}ms ${hoverEase},fill ${hoverMs}ms ${hoverEase},` +
|
|
90
|
+
`stroke ${hoverMs}ms ${hoverEase},transform ${hoverMs}ms ${hoverEase},opacity ${hoverMs}ms ${hoverEase};`
|
|
91
|
+
);
|
|
84
92
|
return parts.join(" ");
|
|
85
93
|
});
|
|
86
94
|
|
|
87
|
-
// ── A11y ───────────────────────────────────────────────────────────────────
|
|
88
95
|
const ariaHidden = $derived(props.decorative ? "true" : undefined);
|
|
89
96
|
const computedTitleId = $derived(
|
|
90
97
|
props.title ? (props.titleId ?? `bz-icon-title-${uid()}`) : undefined
|
|
@@ -96,12 +103,9 @@
|
|
|
96
103
|
!props.decorative && props.title ? computedTitleId : undefined
|
|
97
104
|
);
|
|
98
105
|
|
|
99
|
-
// ── Tamaño final ───────────────────────────────────────────────────────────
|
|
100
106
|
const finalSize = $derived(
|
|
101
107
|
typeof common.size === "number" ? `${common.size}px` : common.size
|
|
102
108
|
);
|
|
103
|
-
|
|
104
|
-
// ── Attrs seguros (no permitir width/height externos) ──────────────────────
|
|
105
109
|
const safeAttrs = $derived(() => {
|
|
106
110
|
const a = { ...(props.attrs ?? {}) };
|
|
107
111
|
delete (a as any).width;
|
|
@@ -109,21 +113,15 @@
|
|
|
109
113
|
return a;
|
|
110
114
|
});
|
|
111
115
|
|
|
112
|
-
// ── Clase final ────────────────────────────────────────────────────────────
|
|
113
116
|
const finalClass = $derived(
|
|
114
|
-
|
|
117
|
+
`bz-icon ${klass} ${animationClasses} ${props.chevronState ? "bz-icon-chevron" : ""}`.trim()
|
|
115
118
|
);
|
|
116
119
|
|
|
117
|
-
// ── Centro del viewBox para rot/flip exactos en SVG ────────────────────────
|
|
118
120
|
function getViewBoxCenter(vb: string) {
|
|
119
|
-
const
|
|
120
|
-
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);
|
|
121
122
|
return { cx: minX + w / 2, cy: minY + h / 2 };
|
|
122
123
|
}
|
|
123
124
|
const center = $derived(getViewBoxCenter(common.viewBox));
|
|
124
|
-
const cx = $derived(center.cx);
|
|
125
|
-
const cy = $derived(center.cy);
|
|
126
|
-
|
|
127
125
|
const svgTransform = $derived(() => {
|
|
128
126
|
const cmds: string[] = [];
|
|
129
127
|
if (props.rotate != null) {
|
|
@@ -131,32 +129,21 @@
|
|
|
131
129
|
typeof props.rotate === "number"
|
|
132
130
|
? props.rotate
|
|
133
131
|
: parseFloat(String(props.rotate));
|
|
134
|
-
if (!isNaN(r)) cmds.push(`rotate(${r} ${cx} ${cy})`);
|
|
132
|
+
if (!isNaN(r)) cmds.push(`rotate(${r} ${center.cx} ${center.cy})`);
|
|
135
133
|
}
|
|
136
134
|
if (props.flipH || props.flipV) {
|
|
137
|
-
const sx = props.flipH ? -1 : 1
|
|
138
|
-
|
|
135
|
+
const sx = props.flipH ? -1 : 1,
|
|
136
|
+
sy = props.flipV ? -1 : 1;
|
|
139
137
|
cmds.push(
|
|
140
|
-
`translate(${cx} ${cy}) scale(${sx} ${sy}) translate(${-cx} ${-cy})`
|
|
138
|
+
`translate(${center.cx} ${center.cy}) scale(${sx} ${sy}) translate(${-center.cx} ${-center.cy})`
|
|
141
139
|
);
|
|
142
140
|
}
|
|
143
141
|
return cmds.join(" ");
|
|
144
142
|
});
|
|
145
143
|
|
|
146
|
-
// ── Hover handlers ─────────────────────────────────────────────────────────
|
|
147
|
-
function handleMouseEnter() {
|
|
148
|
-
internalHovered = true;
|
|
149
|
-
}
|
|
150
|
-
function handleMouseLeave() {
|
|
151
|
-
internalHovered = false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// ── Efectos declarativos (props.effects > attrs.* retrocompat) ─────────────
|
|
155
144
|
let svgRef: SVGSVGElement | null = $state(null);
|
|
156
|
-
|
|
157
145
|
$effect(() => {
|
|
158
146
|
if (!svgRef) return;
|
|
159
|
-
|
|
160
147
|
const effectsOpts: IconEffectOptions = { ...(props.effects ?? {}) };
|
|
161
148
|
const a = props.attrs ?? {};
|
|
162
149
|
if (a.spinOnHover) effectsOpts.spinOnHover = true;
|
|
@@ -168,12 +155,18 @@
|
|
|
168
155
|
if (a.heartbeatOnActive) effectsOpts.heartbeatOnActive = true;
|
|
169
156
|
if (a.hoverScale) effectsOpts.hoverScale = a.hoverScale;
|
|
170
157
|
if (a.pressScale) effectsOpts.pressScale = a.pressScale;
|
|
171
|
-
|
|
172
158
|
if (Object.keys(effectsOpts).length > 0) {
|
|
173
159
|
const controller = iconEffects(svgRef, effectsOpts);
|
|
174
160
|
return () => controller.destroy();
|
|
175
161
|
}
|
|
176
162
|
});
|
|
163
|
+
|
|
164
|
+
function handleMouseEnter() {
|
|
165
|
+
internalHovered = true;
|
|
166
|
+
}
|
|
167
|
+
function handleMouseLeave() {
|
|
168
|
+
internalHovered = false;
|
|
169
|
+
}
|
|
177
170
|
</script>
|
|
178
171
|
|
|
179
172
|
<svg
|
|
@@ -206,3 +199,22 @@
|
|
|
206
199
|
{@render props.children?.()}
|
|
207
200
|
</g>
|
|
208
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>
|
|
@@ -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 ?? "File settings icon"}
|
|
13
|
+
title={props.title ?? ""}
|
|
14
|
+
>
|
|
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
|
+
/>
|
|
18
|
+
</IconBase>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!-- src/lib/icons/Cart.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import IconBase from "../IconBase.svelte";
|
|
4
|
+
import type { IconProps } from "../types";
|
|
5
|
+
|
|
6
|
+
const props: IconProps = $props();
|
|
7
|
+
const ariaLabel = props.ariaLabel ?? "Cart";
|
|
8
|
+
const title = props.title ?? "";
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<IconBase
|
|
12
|
+
{...props}
|
|
13
|
+
mode={props.mode ?? "solid"}
|
|
14
|
+
viewBox="0 0 24 24"
|
|
15
|
+
{ariaLabel}
|
|
16
|
+
{title}
|
|
17
|
+
>
|
|
18
|
+
<!-- IconBase controla color/hover/animaciones/transición; aquí solo paths -->
|
|
19
|
+
<g fill="none">
|
|
20
|
+
<path
|
|
21
|
+
d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.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.004-.011l.017-.43l-.003-.012l-.01-.01z"
|
|
22
|
+
/>
|
|
23
|
+
<path
|
|
24
|
+
fill="currentColor"
|
|
25
|
+
d="M9 20a1 1 0 1 1 0 2a1 1 0 0 1 0-2m7 0a1 1 0 1 1 0 2a1 1 0 0 1 0-2M2.2 2.9a1 1 0 0 1 1.295-.269l.105.07l1.708 1.28a2 2 0 0 1 .653.848l.06.171h12.846a2 2 0 0 1 1.998 2.1l-.013.148l-.457 3.655a5 5 0 0 1-4.32 4.34l-.226.023l-7.313.61l.26 1.124H17.5a1 1 0 0 1 .117 1.993L17.5 19H8.796a2 2 0 0 1-1.906-1.393l-.043-.157l-2.74-11.87L2.4 4.3a1 1 0 0 1-.2-1.4"
|
|
26
|
+
/>
|
|
27
|
+
</g>
|
|
28
|
+
</IconBase>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!-- src/lib/icons/GridAlt.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import IconBase from "../IconBase.svelte";
|
|
4
|
+
import type { IconProps } from "../types";
|
|
5
|
+
const props: IconProps = $props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<IconBase {...props} mode="outline" viewBox="0 0 24 24">
|
|
9
|
+
<!-- Cuadro superior derecho (romboado) -->
|
|
10
|
+
<rect
|
|
11
|
+
x="13"
|
|
12
|
+
y="3"
|
|
13
|
+
width="8"
|
|
14
|
+
height="8"
|
|
15
|
+
rx="2"
|
|
16
|
+
ry="2"
|
|
17
|
+
transform="rotate(45 17 7)"
|
|
18
|
+
fill="none"
|
|
19
|
+
stroke="currentColor"
|
|
20
|
+
/>
|
|
21
|
+
|
|
22
|
+
<!-- Cuadro superior izquierdo -->
|
|
23
|
+
<rect
|
|
24
|
+
x="3"
|
|
25
|
+
y="3"
|
|
26
|
+
width="8"
|
|
27
|
+
height="8"
|
|
28
|
+
rx="2"
|
|
29
|
+
ry="2"
|
|
30
|
+
fill="none"
|
|
31
|
+
stroke="currentColor"
|
|
32
|
+
/>
|
|
33
|
+
|
|
34
|
+
<!-- Cuadro inferior derecho -->
|
|
35
|
+
<rect
|
|
36
|
+
x="13"
|
|
37
|
+
y="13"
|
|
38
|
+
width="8"
|
|
39
|
+
height="8"
|
|
40
|
+
rx="2"
|
|
41
|
+
ry="2"
|
|
42
|
+
fill="none"
|
|
43
|
+
stroke="currentColor"
|
|
44
|
+
/>
|
|
45
|
+
|
|
46
|
+
<!-- Cuadro inferior izquierdo -->
|
|
47
|
+
<rect
|
|
48
|
+
x="3"
|
|
49
|
+
y="13"
|
|
50
|
+
width="8"
|
|
51
|
+
height="8"
|
|
52
|
+
rx="2"
|
|
53
|
+
ry="2"
|
|
54
|
+
fill="none"
|
|
55
|
+
stroke="currentColor"
|
|
56
|
+
/>
|
|
57
|
+
</IconBase>
|