@genarou/blazir-icons 1.1.3 → 1.1.5

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.
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { iconRegistry } from "./icons/registry.js";
3
3
  import type { IconName, IconProps } from "./types.js";
4
+ import { coerceSize } from "./utils/defaults.js";
4
5
 
5
6
  // Props específicas del componente dinámico
6
7
  interface DynamicIconProps extends Omit<IconProps, "children"> {
@@ -12,10 +13,13 @@
12
13
  // Obtener el componente del registry
13
14
  const IconComponent = $derived(iconRegistry[props.name]);
14
15
 
15
- // Extraer solo las props que necesita el icono (sin 'name')
16
+ // 🔧 Extraer solo las props que necesita el icono (sin 'name') y normalizar size
16
17
  const iconProps = $derived(() => {
17
- const { name, ...rest } = props;
18
- return rest;
18
+ const { name, size, ...rest } = props;
19
+ return {
20
+ ...rest,
21
+ size: coerceSize(size, 24), // 🎯 Normalizar size aquí también
22
+ };
19
23
  });
20
24
  </script>
21
25
 
package/dist/Icon.svelte CHANGED
@@ -2,48 +2,39 @@
2
2
  <script lang="ts">
3
3
  import { iconRegistry, type IconName } from "./icons/registry";
4
4
  import type { IconProps } from "./types";
5
+ import { coerceSize } from "./utils/defaults";
5
6
 
6
7
  let {
7
8
  name,
8
- size = $bindable(24),
9
- color = $bindable("#6b7280"),
10
- stroke = $bindable(undefined),
11
- strokeWidth = $bindable(undefined),
12
- fill = $bindable(undefined),
13
- className = $bindable(""),
14
- ariaLabel = $bindable(undefined),
15
- title = $bindable(""),
16
- rotate = $bindable(0),
17
- flipH = $bindable(false),
18
- flipV = $bindable(false),
19
- spin = $bindable(false),
20
- nonScalingStroke = $bindable(false),
21
- preserveAspectRatio = $bindable("xMidYMid meet"),
22
- decorative = $bindable(false),
23
- titleId = $bindable(""),
24
- testId = $bindable(undefined),
25
- attrs = $bindable({}),
26
- animationDuration = $bindable(undefined),
27
- animationDelay = $bindable(undefined),
28
- animationEasing = $bindable(undefined),
29
- ...restProps
9
+ size = 24, // ✅ primitivo
10
+ color = "#6b7280",
11
+ stroke,
12
+ strokeWidth,
13
+ fill,
14
+ className = "",
15
+ ariaLabel,
16
+ title = "",
17
+ rotate = 0,
18
+ flipH = false,
19
+ flipV = false,
20
+ spin = false,
21
+ nonScalingStroke = false,
22
+ preserveAspectRatio = "xMidYMid meet",
23
+ decorative = false,
24
+ titleId = "",
25
+ testId,
26
+ attrs = {},
27
+ animationDuration,
28
+ animationDelay,
29
+ animationEasing,
30
+ ...rest
30
31
  }: { name: IconName } & Partial<IconProps> = $props();
31
32
 
32
33
  const Comp = $derived(iconRegistry[name]);
33
34
 
34
- // Normalizar valores de animación
35
- function normalizeAnimationValue(
36
- value: number | string | undefined
37
- ): string | undefined {
38
- if (typeof value === "number") {
39
- return `${value}ms`;
40
- }
41
- return value;
42
- }
43
-
44
- // Props a pasar - obteniendo valores directamente, no funciones derivadas
45
35
  const passProps = $derived(() => ({
46
- size,
36
+ // ✅ tamaño garantizado como number|string simple
37
+ size: coerceSize(size, 24),
47
38
  color,
48
39
  stroke: color ? (stroke ?? "none") : stroke,
49
40
  fill: color ? (fill ?? color) : fill,
@@ -61,18 +52,21 @@
61
52
  titleId,
62
53
  testId,
63
54
  attrs,
64
- // Normalizar las propiedades de animación
65
- animationDuration: normalizeAnimationValue(animationDuration),
66
- animationDelay: normalizeAnimationValue(animationDelay),
55
+ animationDuration:
56
+ typeof animationDuration === "number"
57
+ ? `${animationDuration}ms`
58
+ : animationDuration,
59
+ animationDelay:
60
+ typeof animationDelay === "number"
61
+ ? `${animationDelay}ms`
62
+ : animationDelay,
67
63
  animationEasing,
68
- ...restProps,
64
+ ...rest,
69
65
  }));
70
66
  </script>
71
67
 
72
68
  {#if Comp}
73
69
  <Comp {...passProps} />
74
70
  {:else}
75
- <span class="inline-block align-middle text-xs text-red-500">
76
- Unknown icon: {name}
77
- </span>
71
+ <span class="inline-block text-xs text-red-500">Unknown icon: {name}</span>
78
72
  {/if}
@@ -3,6 +3,6 @@ import type { IconProps } from "./types";
3
3
  type $$ComponentProps = {
4
4
  name: IconName;
5
5
  } & Partial<IconProps>;
6
- declare const Icon: import("svelte").Component<$$ComponentProps, {}, "size" | "stroke" | "strokeWidth" | "fill" | "className" | "ariaLabel" | "title" | "rotate" | "flipH" | "flipV" | "spin" | "color" | "nonScalingStroke" | "preserveAspectRatio" | "decorative" | "titleId" | "testId" | "attrs" | "animationDuration" | "animationDelay" | "animationEasing">;
6
+ declare const Icon: import("svelte").Component<$$ComponentProps, {}, "">;
7
7
  type Icon = ReturnType<typeof Icon>;
8
8
  export default Icon;
@@ -12,32 +12,29 @@
12
12
  } from "./utils/defaults.js";
13
13
 
14
14
  const props: IconProps & { mode?: IconMode } = $props();
15
- const mode = $derived(props.mode ?? "solid");
16
15
 
16
+ const mode = $derived(props.mode ?? "solid");
17
17
  const klass = $derived(normalizeClass(props));
18
- const common = $derived(commonDefaults(props));
18
+ const common = $derived(commonDefaults(props)); // ✅ ya coercea size
19
19
  const visual = $derived(modeDefaults(mode, props));
20
20
 
21
21
  const animationClasses = $derived(getAnimationClasses(props).join(" "));
22
22
  const baseTransform = $derived(combineTransforms(props));
23
23
  const animationStyle = $derived(getAnimationStyle(props));
24
24
 
25
- const ariaLabel = $derived(props.ariaLabel);
26
- const title = $derived(props.title);
27
- const titleId = $derived(props.titleId);
28
25
  const _ariaHidden = $derived(props.decorative ? "true" : undefined);
29
26
  const _ariaLabel = $derived(
30
- props.decorative ? undefined : ariaLabel || undefined
27
+ props.decorative ? undefined : props.ariaLabel || undefined
31
28
  );
32
29
  const _ariaLabelledby = $derived(
33
- !props.decorative && title ? titleId : undefined
30
+ !props.decorative && props.title ? props.titleId : undefined
34
31
  );
35
32
 
36
- const transformStr = $derived(() => {
37
- return baseTransform
33
+ const transformStr = $derived(() =>
34
+ baseTransform
38
35
  ? `transform: ${baseTransform}; transform-origin: center;`
39
- : "";
40
- });
36
+ : ""
37
+ );
41
38
 
42
39
  const spinStr = $derived(() => {
43
40
  const s = props.spin;
@@ -50,6 +47,19 @@
50
47
  `${props.style || ""}${props.style && !props.style.endsWith(";") ? ";" : ""}${transformStr}${spinStr}${animationStyle}`.trim()
51
48
  );
52
49
 
50
+ // ✅ finalSize es un VALOR, no una función
51
+ const finalSize = $derived(
52
+ typeof common.size === "number" ? `${common.size}px` : common.size
53
+ );
54
+
55
+ // ✅ evita que attrs pisen width/height
56
+ const safeAttrs = $derived(() => {
57
+ const a = { ...(props.attrs ?? {}) } as Record<string, any>;
58
+ delete a.width;
59
+ delete a.height; // opcional: delete a.style si te meten width/height por style
60
+ return a;
61
+ });
62
+
53
63
  const finalClass = $derived(
54
64
  `${klass} ${animationClasses} ${props.chevronState ? "bz-icon-chevron" : ""}`.trim()
55
65
  );
@@ -57,8 +67,9 @@
57
67
 
58
68
  <svg
59
69
  xmlns="http://www.w3.org/2000/svg"
60
- width={typeof common.size === "number" ? `${common.size}px` : common.size}
61
- height={typeof common.size === "number" ? `${common.size}px` : common.size}
70
+ {...safeAttrs}
71
+ width={finalSize}
72
+ height={finalSize}
62
73
  viewBox={common.viewBox}
63
74
  preserveAspectRatio={common.preserveAspectRatio}
64
75
  class={finalClass}
@@ -75,10 +86,9 @@
75
86
  stroke-linejoin={props.strokeLinejoin}
76
87
  vector-effect={props.nonScalingStroke ? "non-scaling-stroke" : undefined}
77
88
  data-testid={props.testId}
78
- {...props.attrs ?? {}}
79
89
  >
80
- {#if title}<title id={titleId}>{title}</title>{/if}
81
- {@render props.children()}
90
+ {#if props.title}<title id={props.titleId}>{props.title}</title>{/if}
91
+ {@render props.children?.()}
82
92
  </svg>
83
93
 
84
94
  <style>
package/dist/actions.js CHANGED
@@ -141,7 +141,7 @@ export function iconEffects(node, opts = {}) {
141
141
  cancelAnimationFrame(rafId);
142
142
  node.removeEventListener("pointerenter", onEnter);
143
143
  node.removeEventListener("pointerleave", onLeave);
144
- node.addEventListener("pointerdown", onDown);
144
+ node.removeEventListener("pointerdown", onDown);
145
145
  node.removeEventListener("pointerup", onUp);
146
146
  node.removeEventListener("keydown", onKeydown);
147
147
  node.removeEventListener("mousedown", onMousedown);
@@ -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]: 2 | 9 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 12;
105
+ [k: string]: 12 | 2 | 9 | 3 | 10 | 4 | 8 | 7 | 6 | 5;
106
106
  };
107
107
  readonly mostUsedCategory: string;
108
108
  readonly shortcuts: number;
@@ -1,6 +1,27 @@
1
1
  import type { IconMode, IconProps } from "../types.js";
2
- /** Prioriza `class` sobre `className` (sin mutar el objeto) */
3
- export declare function normalizeClass(p: Partial<IconProps>): string;
2
+ export declare const SIZE_TOKENS: {
3
+ readonly xs: 12;
4
+ readonly sm: 16;
5
+ readonly md: 20;
6
+ readonly lg: 24;
7
+ readonly xl: 32;
8
+ readonly "2xl": 40;
9
+ readonly "3xl": 48;
10
+ };
11
+ export type SizeToken = keyof typeof SIZE_TOKENS;
12
+ /**
13
+ * 🔧 Coerce size con soporte para:
14
+ * - Números: 24, 32
15
+ * - Strings con unidades: "1.5rem", "24px", "100%"
16
+ * - Tokens semánticos: "sm", "lg", "xl"
17
+ * - Bindables/Proxies: unwrapping automático
18
+ */
19
+ export declare function coerceSize(v: any, fallback?: number): number | string;
20
+ /** Prioriza class sobre className (sin mutar el objeto) */
21
+ export declare function normalizeClass(p: Partial<{
22
+ class?: string;
23
+ className?: string;
24
+ }>): string;
4
25
  /** Convierte ancho de trazo string->number con fallback */
5
26
  export declare function coerceStrokeWidth(v: IconProps["strokeWidth"], fallback?: number): number | undefined;
6
27
  /** Aplica defaults solo cuando la prop está undefined */
@@ -19,8 +40,14 @@ export declare function modeDefaults(mode: IconMode, props: Partial<IconProps>):
19
40
  strokeLinecap: any;
20
41
  strokeLinejoin: any;
21
42
  };
22
- /** Defaults comunes no visuales */
23
- export declare function commonDefaults(p: Partial<IconProps>): {
43
+ /**
44
+ * 🎯 Defaults comunes con size coercionado
45
+ */
46
+ export declare function commonDefaults(p: Partial<{
47
+ size?: number | string;
48
+ viewBox?: string;
49
+ preserveAspectRatio?: string;
50
+ }>): {
24
51
  size: string | number;
25
52
  viewBox: string;
26
53
  preserveAspectRatio: string;
@@ -1,4 +1,48 @@
1
- /** Prioriza `class` sobre `className` (sin mutar el objeto) */
1
+ // 🎯 TOKENS DE TAMAÑO - Expandible y consistente
2
+ export const SIZE_TOKENS = {
3
+ xs: 12,
4
+ sm: 16,
5
+ md: 20,
6
+ lg: 24,
7
+ xl: 32,
8
+ "2xl": 40,
9
+ "3xl": 48,
10
+ };
11
+ /**
12
+ * 🔧 Coerce size con soporte para:
13
+ * - Números: 24, 32
14
+ * - Strings con unidades: "1.5rem", "24px", "100%"
15
+ * - Tokens semánticos: "sm", "lg", "xl"
16
+ * - Bindables/Proxies: unwrapping automático
17
+ */
18
+ export function coerceSize(v, fallback = 24) {
19
+ if (v == null)
20
+ return fallback;
21
+ if (typeof v === "number")
22
+ return v;
23
+ if (typeof v === "string") {
24
+ if (v in SIZE_TOKENS)
25
+ return SIZE_TOKENS[v];
26
+ if (/^\d+(\.\d+)?(px|em|rem|%|vh|vw|ch|ex)$/.test(v))
27
+ return v; // “24px”, “1.25rem”, “100%”
28
+ const num = parseFloat(v);
29
+ if (!Number.isNaN(num))
30
+ return num; // “24” => 24
31
+ return v; // otros strings, respétalos
32
+ }
33
+ // Unwrap bindables/proxies si llegan
34
+ try {
35
+ const unwrapped = v.value ?? v;
36
+ if (unwrapped !== v)
37
+ return coerceSize(unwrapped, fallback);
38
+ const n = Number(v);
39
+ if (!Number.isNaN(n))
40
+ return n;
41
+ }
42
+ catch { }
43
+ return fallback;
44
+ }
45
+ /** Prioriza class sobre className (sin mutar el objeto) */
2
46
  export function normalizeClass(p) {
3
47
  return (p.class ?? p.className ?? "");
4
48
  }
@@ -44,10 +88,12 @@ export function modeDefaults(mode, props) {
44
88
  };
45
89
  }
46
90
  }
47
- /** Defaults comunes no visuales */
91
+ /**
92
+ * 🎯 Defaults comunes con size coercionado
93
+ */
48
94
  export function commonDefaults(p) {
49
95
  return {
50
- size: p.size ?? 24,
96
+ size: coerceSize(p.size, 24),
51
97
  viewBox: p.viewBox ?? "0 0 24 24",
52
98
  preserveAspectRatio: p.preserveAspectRatio ?? "xMidYMid meet",
53
99
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genarou/blazir-icons",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "publishConfig": {