@genarou/blazir-icons 1.3.4 → 1.4.0

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.
Files changed (194) hide show
  1. package/LICENSE +34 -33
  2. package/NOTICE +14 -0
  3. package/README.md +153 -213
  4. package/dist/Icon.svelte +21 -23
  5. package/dist/Icon.svelte.d.ts +5 -5
  6. package/dist/IconLazy.svelte +297 -0
  7. package/dist/IconLazy.svelte.d.ts +22 -0
  8. package/dist/effects.js +16 -29
  9. package/dist/icons/Ai.svelte +2 -2
  10. package/dist/icons/Alternate.svelte +2 -2
  11. package/dist/icons/AnimatedArrowLeft.svelte +1 -1
  12. package/dist/icons/ArrowDown.svelte +18 -0
  13. package/dist/icons/ArrowDown.svelte.d.ts +4 -0
  14. package/dist/icons/ArrowLeft.svelte +18 -0
  15. package/dist/icons/ArrowLeft.svelte.d.ts +4 -0
  16. package/dist/icons/Attachment.svelte +1 -1
  17. package/dist/icons/Bag.svelte +1 -1
  18. package/dist/icons/Bank.svelte +1 -1
  19. package/dist/icons/Bell.svelte +1 -1
  20. package/dist/icons/Blaze.svelte +1 -1
  21. package/dist/icons/Box.svelte +1 -1
  22. package/dist/icons/BoxAdd.svelte +1 -1
  23. package/dist/icons/Buy.svelte +1 -1
  24. package/dist/icons/Calendar.svelte +1 -1
  25. package/dist/icons/CalendarEdit.svelte +1 -1
  26. package/dist/icons/CalendarPlus.svelte +1 -1
  27. package/dist/icons/Camera.svelte +1 -1
  28. package/dist/icons/Cart.svelte +1 -1
  29. package/dist/icons/CategoryAdd.svelte +1 -1
  30. package/dist/icons/CategorySearch.svelte +1 -1
  31. package/dist/icons/Chart.svelte +1 -1
  32. package/dist/icons/ChartDoc.svelte +1 -1
  33. package/dist/icons/Check.svelte +1 -1
  34. package/dist/icons/CheckList.svelte +2 -2
  35. package/dist/icons/CheckO.svelte +1 -1
  36. package/dist/icons/ChevronLeft.svelte +15 -0
  37. package/dist/icons/ChevronLeft.svelte.d.ts +4 -0
  38. package/dist/icons/ChevronRight.svelte +15 -0
  39. package/dist/icons/ChevronRight.svelte.d.ts +4 -0
  40. package/dist/icons/ChevronUp.svelte +15 -0
  41. package/dist/icons/ChevronUp.svelte.d.ts +4 -0
  42. package/dist/icons/CircleCheck.svelte +2 -2
  43. package/dist/icons/CircleExclamation.svelte +2 -2
  44. package/dist/icons/CircleExclamationOutlined.svelte +2 -2
  45. package/dist/icons/CircleInfo.svelte +2 -2
  46. package/dist/icons/CircleInfoOutlined.svelte +2 -2
  47. package/dist/icons/CircleQuestion.svelte +1 -1
  48. package/dist/icons/CircleQuestionOutlined.svelte +2 -2
  49. package/dist/icons/Close.svelte +2 -2
  50. package/dist/icons/CloudCheck.svelte +1 -1
  51. package/dist/icons/CloudUpload.svelte +18 -0
  52. package/dist/icons/CloudUpload.svelte.d.ts +4 -0
  53. package/dist/icons/Code.svelte +18 -0
  54. package/dist/icons/Code.svelte.d.ts +4 -0
  55. package/dist/icons/Colors.svelte +1 -1
  56. package/dist/icons/Contact.svelte +1 -1
  57. package/dist/icons/Csv.svelte +1 -1
  58. package/dist/icons/Dashboard.svelte +1 -1
  59. package/dist/icons/Db.svelte +1 -1
  60. package/dist/icons/DoughnutChart.svelte +1 -1
  61. package/dist/icons/DownloadAnimated.svelte +1 -1
  62. package/dist/icons/Earth.svelte +1 -1
  63. package/dist/icons/Edit.svelte +2 -2
  64. package/dist/icons/EditOutline.svelte +2 -2
  65. package/dist/icons/EmailAnimated.svelte +3 -3
  66. package/dist/icons/Error.svelte +1 -1
  67. package/dist/icons/ErrorO.svelte +2 -2
  68. package/dist/icons/Excel.svelte +1 -1
  69. package/dist/icons/ExcelAnimated.svelte +3 -3
  70. package/dist/icons/Exchange.svelte +1 -1
  71. package/dist/icons/ExternalLink.svelte +18 -0
  72. package/dist/icons/ExternalLink.svelte.d.ts +4 -0
  73. package/dist/icons/Eye.svelte +1 -1
  74. package/dist/icons/EyeOff.svelte +2 -2
  75. package/dist/icons/Favorites.svelte +1 -1
  76. package/dist/icons/FileUploadAnimated.svelte +2 -2
  77. package/dist/icons/Filter.svelte +1 -1
  78. package/dist/icons/Fingerprint.svelte +1 -1
  79. package/dist/icons/FormatListGroup.svelte +1 -1
  80. package/dist/icons/Gift.svelte +21 -0
  81. package/dist/icons/Gift.svelte.d.ts +7 -0
  82. package/dist/icons/Globe.svelte +1 -1
  83. package/dist/icons/Grid.svelte +18 -0
  84. package/dist/icons/Grid.svelte.d.ts +4 -0
  85. package/dist/icons/GripVertical.svelte +18 -0
  86. package/dist/icons/GripVertical.svelte.d.ts +4 -0
  87. package/dist/icons/Group.svelte +3 -3
  88. package/dist/icons/HardDrive.svelte +1 -1
  89. package/dist/icons/Heart.svelte +1 -1
  90. package/dist/icons/Height.svelte +1 -1
  91. package/dist/icons/Historic.svelte +1 -1
  92. package/dist/icons/Home.svelte +1 -1
  93. package/dist/icons/Image.svelte +1 -1
  94. package/dist/icons/ImageAnimated.svelte +2 -2
  95. package/dist/icons/Layers.svelte +9 -0
  96. package/dist/icons/Layers.svelte.d.ts +4 -0
  97. package/dist/icons/Link.svelte +1 -1
  98. package/dist/icons/ListDots.svelte +1 -1
  99. package/dist/icons/Location.svelte +1 -1
  100. package/dist/icons/LocationAnimated.svelte +1 -1
  101. package/dist/icons/Lock.svelte +1 -1
  102. package/dist/icons/LockOpen.svelte +1 -1
  103. package/dist/icons/Logout.svelte +1 -1
  104. package/dist/icons/Lose.svelte +1 -1
  105. package/dist/icons/MagnifiyingGlass.svelte +1 -1
  106. package/dist/icons/Maximize.svelte +18 -0
  107. package/dist/icons/Maximize.svelte.d.ts +4 -0
  108. package/dist/icons/MicOff.svelte +9 -0
  109. package/dist/icons/MicOff.svelte.d.ts +4 -0
  110. package/dist/icons/Microphone.svelte +9 -0
  111. package/dist/icons/Microphone.svelte.d.ts +4 -0
  112. package/dist/icons/Minimize.svelte +9 -0
  113. package/dist/icons/Minimize.svelte.d.ts +4 -0
  114. package/dist/icons/Money.svelte +1 -1
  115. package/dist/icons/Moon.svelte +1 -1
  116. package/dist/icons/More.svelte +1 -1
  117. package/dist/icons/Notes.svelte +1 -1
  118. package/dist/icons/ObjectGroup.svelte +1 -12
  119. package/dist/icons/Pay.svelte +1 -1
  120. package/dist/icons/Pdf.svelte +1 -1
  121. package/dist/icons/Percentage.svelte +9 -0
  122. package/dist/icons/Percentage.svelte.d.ts +4 -0
  123. package/dist/icons/Play.svelte +1 -1
  124. package/dist/icons/Plus.svelte +1 -1
  125. package/dist/icons/PointSale.svelte +2 -42
  126. package/dist/icons/Power.svelte +1 -1
  127. package/dist/icons/Product.svelte +1 -1
  128. package/dist/icons/Profit.svelte +2 -2
  129. package/dist/icons/Project.svelte +1 -1
  130. package/dist/icons/Redo.svelte +9 -0
  131. package/dist/icons/Redo.svelte.d.ts +4 -0
  132. package/dist/icons/RegularSpinner.svelte +2 -2
  133. package/dist/icons/RightArrow.svelte +1 -1
  134. package/dist/icons/Rocket.svelte +1 -1
  135. package/dist/icons/SafeSolid.svelte +2 -2
  136. package/dist/icons/Security.svelte +2 -2
  137. package/dist/icons/Send.svelte +1 -1
  138. package/dist/icons/Server.svelte +1 -1
  139. package/dist/icons/Settings.svelte +1 -1
  140. package/dist/icons/Share.svelte +1 -1
  141. package/dist/icons/Shield.svelte +2 -2
  142. package/dist/icons/Sliders.svelte +9 -0
  143. package/dist/icons/Sliders.svelte.d.ts +4 -0
  144. package/dist/icons/Sun.svelte +1 -1
  145. package/dist/icons/Supervisor.svelte +1 -1
  146. package/dist/icons/Swap.svelte +1 -1
  147. package/dist/icons/SyncPhoto.svelte +1 -1
  148. package/dist/icons/Table.svelte +1 -3
  149. package/dist/icons/Tags.svelte +1 -1
  150. package/dist/icons/Team.svelte +2 -2
  151. package/dist/icons/Terminal.svelte +21 -0
  152. package/dist/icons/Terminal.svelte.d.ts +7 -0
  153. package/dist/icons/Timer.svelte +1 -1
  154. package/dist/icons/Tools.svelte +2 -2
  155. package/dist/icons/Truck.svelte +1 -1
  156. package/dist/icons/TruckReturn.svelte +2 -2
  157. package/dist/icons/Undo.svelte +9 -0
  158. package/dist/icons/Undo.svelte.d.ts +4 -0
  159. package/dist/icons/UpDownArrow.svelte +1 -1
  160. package/dist/icons/Upload.svelte +1 -1
  161. package/dist/icons/UploadAnimated.svelte +1 -1
  162. package/dist/icons/UploadLoader.svelte +4 -4
  163. package/dist/icons/User.svelte +1 -1
  164. package/dist/icons/UserMinus.svelte +18 -0
  165. package/dist/icons/UserMinus.svelte.d.ts +4 -0
  166. package/dist/icons/UserPlus.svelte +18 -0
  167. package/dist/icons/UserPlus.svelte.d.ts +4 -0
  168. package/dist/icons/UserShield.svelte +1 -1
  169. package/dist/icons/UserTie.svelte +1 -1
  170. package/dist/icons/Video.svelte +9 -0
  171. package/dist/icons/Video.svelte.d.ts +4 -0
  172. package/dist/icons/Volume.svelte +9 -0
  173. package/dist/icons/Volume.svelte.d.ts +4 -0
  174. package/dist/icons/VolumeOff.svelte +9 -0
  175. package/dist/icons/VolumeOff.svelte.d.ts +4 -0
  176. package/dist/icons/Wallet.svelte +2 -2
  177. package/dist/icons/Word.svelte +1 -1
  178. package/dist/icons/World.svelte +1 -1
  179. package/dist/icons/Xml.svelte +1 -1
  180. package/dist/icons/Zip.svelte +1 -1
  181. package/dist/icons/components.d.ts +200 -0
  182. package/dist/icons/components.js +201 -0
  183. package/dist/icons/lazy-registry.js +57 -53
  184. package/dist/icons/registry.d.ts +30 -0
  185. package/dist/icons/registry.js +79 -20
  186. package/dist/icons-api.d.ts +26 -0
  187. package/dist/icons-api.js +51 -20
  188. package/dist/index.d.ts +2 -0
  189. package/dist/index.js +9 -19
  190. package/dist/presets.js +4 -5
  191. package/dist/smart-cache.js +17 -82
  192. package/package.json +62 -54
  193. package/dist/icons/index.d.ts +0 -2
  194. package/dist/icons/index.js +0 -4
package/dist/Icon.svelte CHANGED
@@ -1,37 +1,34 @@
1
1
  <!-- Icon.svelte — Refactored v2 -->
2
2
  <!-- Cache inteligente adaptativo + lazy loading opcional + actions diff -->
3
3
  <script lang="ts">
4
- import type { Component } from 'svelte';
5
- import { coerceSize } from './utils/defaults.js';
6
- import { iconRegistry, type IconName } from './icons/registry.js';
7
- import { iconPresets, iconVariants } from './presets.js';
8
- import type { IconProps } from './types.js';
4
+ import type { Component } from "svelte";
5
+ import { getLoadedIcon, loadIcon } from "./icons/lazy-registry.js";
6
+ import { iconRegistry, type IconName } from "./icons/registry.js";
7
+ import { iconPresets, iconVariants } from "./presets.js";
9
8
  import {
10
- getPresetVariantMerge,
11
9
  arePropsStable,
12
10
  buildStructuralKey,
13
11
  getCachedMergedProps,
12
+ getPresetVariantMerge,
14
13
  setCachedMergedProps,
15
14
  toSizePx,
16
- } from './smart-cache.js';
17
- import {
18
- getLoadedIcon,
19
- loadIcon,
20
- } from './icons/lazy-registry.js';
15
+ } from "./smart-cache.js";
16
+ import type { IconProps } from "./types.js";
17
+ import { coerceSize } from "./utils/defaults.js";
21
18
 
22
19
  // ============================================================================
23
20
  // TIPOS
24
21
  // ============================================================================
25
22
  type ActionFn<T = HTMLElement, P = any> = (
26
23
  node: T,
27
- params?: P
24
+ params?: P,
28
25
  ) => void | { update?: (p?: P) => void; destroy?: () => void };
29
26
 
30
27
  type ActionEntry<T = HTMLElement> = [ActionFn<T, any>, any?];
31
28
  type IconPresetName = keyof typeof iconPresets;
32
29
  type IconVariantName = keyof typeof iconVariants;
33
30
 
34
- interface DynamicIconProps extends Omit<IconProps, 'children'> {
31
+ interface DynamicIconProps extends Omit<IconProps, "children"> {
35
32
  name?: IconName;
36
33
  preset?: IconPresetName;
37
34
  variant?: IconVariantName;
@@ -57,7 +54,7 @@
57
54
  // --- Modo EAGER (default): usa el registry estático ya cargado ---
58
55
  // Mismo comportamiento que antes: sin latencia, sin skeleton en primer render.
59
56
  const _eagerComp = $derived(
60
- iconName ? (iconRegistry[iconName as IconName] ?? null) : null
57
+ iconName ? (iconRegistry[iconName as IconName] ?? null) : null,
61
58
  );
62
59
 
63
60
  // --- Modo LAZY (opt-in): dynamic import() por ícono ---
@@ -82,8 +79,8 @@
82
79
  // Si es el mismo nombre y ya lo cargamos → no hacer nada
83
80
  if (_lazyCurrentName === name && _lazyComp) return;
84
81
 
85
- // Intentar sincrónico primero (caché de íconos ya cargados)
86
- const synced = getLoadedIcon(name) ?? (iconRegistry[name as IconName] ?? null);
82
+ // Intentar sincrónico primero (caché de íconos ya cargados en esta sesión)
83
+ const synced = getLoadedIcon(name);
87
84
  if (synced) {
88
85
  _lazyComp = synced;
89
86
  _lazyCurrentName = name;
@@ -121,7 +118,7 @@
121
118
  // ============================================================================
122
119
  function toMs(v: unknown): string | undefined {
123
120
  if (v == null) return undefined;
124
- return typeof v === 'number' ? `${v}ms` : String(v);
121
+ return typeof v === "number" ? `${v}ms` : String(v);
125
122
  }
126
123
 
127
124
  // ============================================================================
@@ -202,7 +199,7 @@
202
199
  // ATRIBUTOS DEL HOST
203
200
  // ============================================================================
204
201
  const hostClass = $derived(
205
- p.class ? `bz-icon-wrapper ${p.class}` : 'bz-icon-wrapper'
202
+ p.class ? `bz-icon-wrapper ${p.class}` : "bz-icon-wrapper",
206
203
  );
207
204
 
208
205
  const hostStyle = $derived.by(() => {
@@ -296,7 +293,7 @@
296
293
  >
297
294
  {#key mountKey}
298
295
  <!-- svelte-ignore: cast necesario para componentes dinámicos con props genéricas -->
299
- <Comp {...(child as any)} />
296
+ <Comp {...child as any} />
300
297
  {/key}
301
298
  </span>
302
299
  {:else if isLoading}
@@ -330,8 +327,9 @@
330
327
  transform: translateX(-50%);
331
328
  pointer-events: none;
332
329
  opacity: 0;
333
- transition: opacity 0.15s ease var(--bz-tooltip-delay, 0ms),
334
- transform 0.15s ease var(--bz-tooltip-delay, 0ms);
330
+ transition:
331
+ opacity 0.15s ease var(--bz-tooltip-delay, 0ms),
332
+ transform 0.15s ease var(--bz-tooltip-delay, 0ms);
335
333
  z-index: 9999;
336
334
  }
337
335
 
@@ -346,13 +344,13 @@
346
344
  padding: 5px 9px;
347
345
  border-radius: 6px;
348
346
  white-space: nowrap;
349
- box-shadow: 0 2px 8px rgba(0,0,0,0.18);
347
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
350
348
  transform: translateX(-50%) translateY(3px);
351
349
  }
352
350
 
353
351
  /* Flecha del tooltip */
354
352
  .bz-icon-wrapper[data-bz-tooltip]::before {
355
- content: '';
353
+ content: "";
356
354
  border: 5px solid transparent;
357
355
  border-top-color: var(--bz-tooltip-bg, #1a1a1a);
358
356
  bottom: calc(100% + 0px);
@@ -1,7 +1,7 @@
1
- import type { Component } from 'svelte';
2
- import { type IconName } from './icons/registry.js';
3
- import { iconPresets, iconVariants } from './presets.js';
4
- import type { IconProps } from './types.js';
1
+ import type { Component } from "svelte";
2
+ import { type IconName } from "./icons/registry.js";
3
+ import { iconPresets, iconVariants } from "./presets.js";
4
+ import type { IconProps } from "./types.js";
5
5
  type ActionFn<T = HTMLElement, P = any> = (node: T, params?: P) => void | {
6
6
  update?: (p?: P) => void;
7
7
  destroy?: () => void;
@@ -9,7 +9,7 @@ type ActionFn<T = HTMLElement, P = any> = (node: T, params?: P) => void | {
9
9
  type ActionEntry<T = HTMLElement> = [ActionFn<T, any>, any?];
10
10
  type IconPresetName = keyof typeof iconPresets;
11
11
  type IconVariantName = keyof typeof iconVariants;
12
- interface DynamicIconProps extends Omit<IconProps, 'children'> {
12
+ interface DynamicIconProps extends Omit<IconProps, "children"> {
13
13
  name?: IconName;
14
14
  preset?: IconPresetName;
15
15
  variant?: IconVariantName;
@@ -0,0 +1,297 @@
1
+ <!-- IconLazy.svelte
2
+ Variante zero-bundle del componente dinámico.
3
+ NO importa iconRegistry en runtime — cada ícono se code-splitea
4
+ en su propio chunk por el bundler via dynamic import().
5
+ Úsalo cuando el nombre del ícono se decide en runtime y quieres
6
+ que solo los iconos realmente usados entren al bundle.
7
+ -->
8
+ <script lang="ts">
9
+ import type { Component } from "svelte";
10
+ import { coerceSize } from "./utils/defaults.js";
11
+ // import type → TypeScript lo borra en compilación, cero runtime dep sobre registry
12
+ import { getLoadedIcon, loadIcon } from "./icons/lazy-registry.js";
13
+ import type { IconName } from "./icons/registry.js";
14
+ import { iconPresets, iconVariants } from "./presets.js";
15
+ import {
16
+ arePropsStable,
17
+ buildStructuralKey,
18
+ getCachedMergedProps,
19
+ getPresetVariantMerge,
20
+ setCachedMergedProps,
21
+ toSizePx,
22
+ } from "./smart-cache.js";
23
+ import type { IconProps } from "./types.js";
24
+
25
+ type ActionFn<T = HTMLElement, P = any> = (
26
+ node: T,
27
+ params?: P,
28
+ ) => void | { update?: (p?: P) => void; destroy?: () => void };
29
+
30
+ type ActionEntry<T = HTMLElement> = [ActionFn<T, any>, any?];
31
+ type IconPresetName = keyof typeof iconPresets;
32
+ type IconVariantName = keyof typeof iconVariants;
33
+
34
+ interface LazyIconProps extends Omit<IconProps, "children"> {
35
+ name?: IconName;
36
+ preset?: IconPresetName;
37
+ variant?: IconVariantName;
38
+ class?: string;
39
+ style?: string;
40
+ actions?: ActionEntry[];
41
+ }
42
+
43
+ const p: LazyIconProps = $props();
44
+
45
+ const iconName = $derived(p.name ?? null);
46
+
47
+ // Resolución lazy — solo dynamic import(), nunca el registry estático
48
+ let _comp = $state<Component | null>(null);
49
+ let _loading = $state(false);
50
+ let _currentName = $state<string | null>(null);
51
+
52
+ $effect(() => {
53
+ const name = iconName;
54
+
55
+ if (!name) {
56
+ _comp = null;
57
+ _currentName = null;
58
+ _loading = false;
59
+ return;
60
+ }
61
+
62
+ if (_currentName === name && _comp) return;
63
+
64
+ // Caché en memoria de iconos ya cargados en esta sesión → render síncrono
65
+ const cached = getLoadedIcon(name);
66
+ if (cached) {
67
+ _comp = cached;
68
+ _currentName = name;
69
+ _loading = false;
70
+ return;
71
+ }
72
+
73
+ // Dynamic import — el bundler genera un chunk separado por ícono
74
+ _loading = true;
75
+ _currentName = name;
76
+ loadIcon(name).then((comp) => {
77
+ if (_currentName === name) {
78
+ _comp = comp;
79
+ _loading = false;
80
+ }
81
+ });
82
+ });
83
+
84
+ // PascalCase alias requerido por Svelte para usar como tag de componente
85
+ const Comp = $derived(_comp);
86
+
87
+ const baseProps = $derived(getPresetVariantMerge(p.preset, p.variant));
88
+
89
+ function toMs(v: unknown): string | undefined {
90
+ if (v == null) return undefined;
91
+ return typeof v === "number" ? `${v}ms` : String(v);
92
+ }
93
+
94
+ const child = $derived.by((): IconProps => {
95
+ const {
96
+ class: _cls,
97
+ style: _sty,
98
+ actions: _act,
99
+ preset: _pre,
100
+ variant: _var,
101
+ name: _nm,
102
+ ...userProps
103
+ } = p;
104
+
105
+ const stable = arePropsStable(userProps as Record<string, unknown>);
106
+
107
+ if (stable) {
108
+ const key = buildStructuralKey(userProps as Record<string, unknown>);
109
+ const cached = getCachedMergedProps(key);
110
+ if (cached) return cached;
111
+
112
+ const merged: any = { ...baseProps, ...userProps };
113
+ if (merged.animationDuration !== undefined)
114
+ merged.animationDuration = toMs(merged.animationDuration);
115
+ if (merged.animationDelay !== undefined)
116
+ merged.animationDelay = toMs(merged.animationDelay);
117
+
118
+ const result = Object.freeze(merged) as unknown as IconProps;
119
+ setCachedMergedProps(key, result as Readonly<IconProps>);
120
+ return result;
121
+ }
122
+
123
+ const merged: any = { ...baseProps, ...userProps };
124
+ if (merged.animationDuration !== undefined)
125
+ merged.animationDuration = toMs(merged.animationDuration);
126
+ if (merged.animationDelay !== undefined)
127
+ merged.animationDelay = toMs(merged.animationDelay);
128
+ return merged as IconProps;
129
+ });
130
+
131
+ const boxSize = $derived.by(() => {
132
+ const rawSize = (p as any).size ?? (baseProps as any).size;
133
+ return toSizePx(coerceSize(rawSize, 24));
134
+ });
135
+
136
+ const hostClass = $derived(
137
+ p.class ? `bz-icon-wrapper ${p.class}` : "bz-icon-wrapper",
138
+ );
139
+
140
+ const hostStyle = $derived.by(() => {
141
+ const sz = boxSize;
142
+ const base = `--bz-icon-size:${sz};width:${sz};height:${sz};inline-size:${sz};block-size:${sz};`;
143
+ return p.style ? base + p.style : base;
144
+ });
145
+
146
+ let mountKey = $state(0);
147
+ function onLazyMount() {
148
+ mountKey++;
149
+ }
150
+
151
+ function applyActions(node: HTMLElement, entries: ActionEntry[] = []) {
152
+ if (!entries?.length) return { update() {}, destroy() {} };
153
+
154
+ let prevEntries: ActionEntry[] = entries;
155
+ let handles = entries
156
+ .map(([fn, params]) => fn?.(node, params))
157
+ .filter(Boolean);
158
+
159
+ return {
160
+ update(next: ActionEntry[] = []) {
161
+ if (!next?.length) {
162
+ handles.forEach((h) => h?.destroy?.());
163
+ handles = [];
164
+ prevEntries = [];
165
+ return;
166
+ }
167
+ if (next.length === prevEntries.length) {
168
+ let sameFns = true;
169
+ for (let i = 0; i < next.length; i++) {
170
+ if (next[i][0] !== prevEntries[i][0]) {
171
+ sameFns = false;
172
+ break;
173
+ }
174
+ }
175
+ if (sameFns) {
176
+ handles.forEach((h, i) => h?.update?.(next[i][1]));
177
+ prevEntries = next;
178
+ return;
179
+ }
180
+ }
181
+ handles.forEach((h) => h?.destroy?.());
182
+ prevEntries = next;
183
+ handles = next
184
+ .map(([fn, params]) => fn?.(node, params))
185
+ .filter(Boolean);
186
+ },
187
+ destroy() {
188
+ handles.forEach((h) => h?.destroy?.());
189
+ handles = [];
190
+ prevEntries = [];
191
+ },
192
+ };
193
+ }
194
+ </script>
195
+
196
+ {#if Comp}
197
+ <span
198
+ class={hostClass}
199
+ style={p.tooltipDelay != null
200
+ ? `${hostStyle};--bz-tooltip-delay:${p.tooltipDelay}ms`
201
+ : hostStyle}
202
+ data-bz-tooltip={p.tooltip || undefined}
203
+ use:applyActions={p.actions ?? []}
204
+ onlazyMount={onLazyMount}
205
+ >
206
+ {#key mountKey}
207
+ <Comp {...child as any} />
208
+ {/key}
209
+ </span>
210
+ {:else if _loading}
211
+ <span class="bz-icon-skeleton" aria-hidden="true"></span>
212
+ {:else if iconName}
213
+ <span class="bz-icon-error" data-icon={iconName}
214
+ >⚠️ Icon not found: {iconName}</span
215
+ >
216
+ {:else}
217
+ <span class="bz-icon-skeleton" aria-hidden="true"></span>
218
+ {/if}
219
+
220
+ <style>
221
+ .bz-icon-wrapper {
222
+ cursor: pointer;
223
+ display: inline-flex;
224
+ align-items: center;
225
+ justify-content: center;
226
+ position: relative;
227
+ pointer-events: auto;
228
+ contain: layout style;
229
+ content-visibility: auto;
230
+ }
231
+
232
+ .bz-icon-wrapper[data-bz-tooltip]::before,
233
+ .bz-icon-wrapper[data-bz-tooltip]::after {
234
+ position: absolute;
235
+ bottom: calc(100% + 8px);
236
+ left: 50%;
237
+ transform: translateX(-50%);
238
+ pointer-events: none;
239
+ opacity: 0;
240
+ transition:
241
+ opacity 0.15s ease var(--bz-tooltip-delay, 0ms),
242
+ transform 0.15s ease var(--bz-tooltip-delay, 0ms);
243
+ z-index: 9999;
244
+ }
245
+
246
+ .bz-icon-wrapper[data-bz-tooltip]::after {
247
+ content: attr(data-bz-tooltip);
248
+ background: var(--bz-tooltip-bg, #1a1a1a);
249
+ color: var(--bz-tooltip-color, #fff);
250
+ font-size: 11px;
251
+ font-weight: 500;
252
+ line-height: 1.4;
253
+ padding: 5px 9px;
254
+ border-radius: 6px;
255
+ white-space: nowrap;
256
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
257
+ transform: translateX(-50%) translateY(3px);
258
+ }
259
+
260
+ .bz-icon-wrapper[data-bz-tooltip]::before {
261
+ content: "";
262
+ border: 5px solid transparent;
263
+ border-top-color: var(--bz-tooltip-bg, #1a1a1a);
264
+ bottom: calc(100% + 0px);
265
+ transform: translateX(-50%) translateY(3px);
266
+ }
267
+
268
+ .bz-icon-wrapper[data-bz-tooltip]:hover::after,
269
+ .bz-icon-wrapper[data-bz-tooltip]:hover::before {
270
+ opacity: 1;
271
+ transform: translateX(-50%) translateY(0);
272
+ }
273
+
274
+ .bz-icon-wrapper :global(svg) {
275
+ pointer-events: bounding-box !important;
276
+ }
277
+ .bz-icon-wrapper :global(svg *) {
278
+ pointer-events: none !important;
279
+ }
280
+
281
+ .bz-icon-skeleton {
282
+ width: 100%;
283
+ height: 100%;
284
+ border-radius: var(--ui-radius, 0.25rem);
285
+ background: color-mix(in oklab, currentColor 12%, transparent);
286
+ opacity: 0.5;
287
+ }
288
+
289
+ .bz-icon-error {
290
+ display: inline-block;
291
+ background: var(--danger-color, #ef4444);
292
+ color: var(--danger-foreground, #fff);
293
+ font-size: 0.75rem;
294
+ border-radius: var(--ui-radius, 0.25rem);
295
+ font-weight: 600;
296
+ }
297
+ </style>
@@ -0,0 +1,22 @@
1
+ import type { Component } from "svelte";
2
+ import type { IconName } from "./icons/registry.js";
3
+ import { iconPresets, iconVariants } from "./presets.js";
4
+ import type { IconProps } from "./types.js";
5
+ type ActionFn<T = HTMLElement, P = any> = (node: T, params?: P) => void | {
6
+ update?: (p?: P) => void;
7
+ destroy?: () => void;
8
+ };
9
+ type ActionEntry<T = HTMLElement> = [ActionFn<T, any>, any?];
10
+ type IconPresetName = keyof typeof iconPresets;
11
+ type IconVariantName = keyof typeof iconVariants;
12
+ interface LazyIconProps extends Omit<IconProps, "children"> {
13
+ name?: IconName;
14
+ preset?: IconPresetName;
15
+ variant?: IconVariantName;
16
+ class?: string;
17
+ style?: string;
18
+ actions?: ActionEntry[];
19
+ }
20
+ declare const IconLazy: Component<LazyIconProps, {}, "">;
21
+ type IconLazy = ReturnType<typeof IconLazy>;
22
+ export default IconLazy;
package/dist/effects.js CHANGED
@@ -1,6 +1,3 @@
1
- // ============================================================================
2
- // 🔥 CACHE GLOBAL Y CONSTANTES
3
- // ============================================================================
4
1
  let _prefersReducedMotion = null;
5
2
  let _mediaQueryListenerInitialized = false;
6
3
  const SLIDE_MAP = {
@@ -38,31 +35,29 @@ function getPrefersReducedMotion() {
38
35
  }
39
36
  return _prefersReducedMotion;
40
37
  }
41
- // ============================================================================
42
- // 🔥 FUNCIÓN PRINCIPAL
43
- // ============================================================================
38
+
44
39
  export function iconEffects(node, opts = {}) {
45
40
  const reducedMotion = getPrefersReducedMotion();
46
- // Estados
41
+
47
42
  let hovering = false;
48
43
  let pressing = false;
49
44
  let rafId = 0;
50
45
  let enterTimer = 0;
51
46
  let leaveTimer = 0;
52
- // Detección de tipos (una sola vez)
47
+
53
48
  const isSVG = node instanceof SVGElement;
54
49
  const isHTML = node instanceof HTMLElement;
55
50
  const canTransform = isSVG || isHTML;
56
- // Target para eventos (SVG padre si es <g>)
51
+
57
52
  let target = node;
58
53
  if (node instanceof SVGGElement && node.ownerSVGElement) {
59
54
  target = node.ownerSVGElement;
60
55
  }
61
- // Setup pointer-events
56
+
62
57
  if (target instanceof SVGSVGElement) {
63
58
  target.style.pointerEvents = "bounding-box";
64
59
  }
65
- // Setup inicial — tooltip lo maneja Icon.svelte via data-bz-tooltip + CSS
60
+
66
61
  if (opts.cursor && isHTML)
67
62
  node.style.cursor = opts.cursor;
68
63
  const ms = opts.transitionMs ?? DEFAULTS.transitionMs;
@@ -75,20 +70,18 @@ export function iconEffects(node, opts = {}) {
75
70
  if (opts.pulse && !reducedMotion) {
76
71
  node.classList.add(CLASSES.pulse);
77
72
  }
78
- // ============================================================================
79
- // 🔥 APPLY ANIMATIONS (máxima eficiencia)
80
- // ============================================================================
73
+
81
74
  function apply() {
82
75
  if (rafId)
83
76
  cancelAnimationFrame(rafId);
84
- // 🔥 OPTIMIZACIÓN: Para animaciones de salida, usar requestIdleCallback
77
+
85
78
  const shouldUseIdle = !hovering && !pressing && typeof requestIdleCallback !== "undefined";
86
79
  const applyImmediate = () => {
87
80
  if (reducedMotion)
88
81
  return;
89
82
  const h = hovering;
90
83
  const p = pressing;
91
- // Transform
84
+
92
85
  let t = "";
93
86
  const s = h ? (p && opts.pressScale) || opts.hoverScale || 1 : 1;
94
87
  if (s !== 1)
@@ -99,11 +92,11 @@ export function iconEffects(node, opts = {}) {
99
92
  t += `${t ? " " : ""}${SLIDE_MAP[opts.slideOnHover]}`;
100
93
  if (canTransform)
101
94
  node.style.transform = t;
102
- // Classes (toggles O(1))
95
+
103
96
  node.classList.toggle(CLASSES.spin, h && !!opts.spinOnHover);
104
97
  node.classList.toggle(CLASSES.bounce, h && !!opts.bounceOnHover);
105
98
  node.classList.toggle(CLASSES.wiggle, h && !!opts.wiggleOnHover);
106
- // ✅ heartbeat: hover o active (click/press)
99
+
107
100
  node.classList.toggle(CLASSES.heartbeat, (h && !!opts.heartbeatOnHover) || (p && !!opts.heartbeatOnActive));
108
101
  node.classList.toggle(CLASSES.elastic, p && !!opts.elasticOnClick);
109
102
  if (opts.morphOnHover) {
@@ -118,9 +111,7 @@ export function iconEffects(node, opts = {}) {
118
111
  rafId = requestAnimationFrame(applyImmediate);
119
112
  }
120
113
  }
121
- // ============================================================================
122
- // 🔥 EVENT HANDLERS
123
- // ============================================================================
114
+
124
115
  const onEnter = () => {
125
116
  clearTimeout(leaveTimer);
126
117
  clearTimeout(enterTimer);
@@ -155,9 +146,7 @@ export function iconEffects(node, opts = {}) {
155
146
  if (focusEnabled)
156
147
  target.removeAttribute(kbAttr);
157
148
  };
158
- // ============================================================================
159
- // 🔥 LISTENERS
160
- // ============================================================================
149
+
161
150
  const passive = { passive: true };
162
151
  target.addEventListener("pointerenter", onEnter, passive);
163
152
  target.addEventListener("pointerleave", onLeave, passive);
@@ -165,9 +154,7 @@ export function iconEffects(node, opts = {}) {
165
154
  target.addEventListener("pointerup", onUp, passive);
166
155
  target.addEventListener("keydown", onKey);
167
156
  target.addEventListener("mousedown", onMouse, passive);
168
- // ============================================================================
169
- // 🔥 API
170
- // ============================================================================
157
+
171
158
  return {
172
159
  update(next) {
173
160
  if (!next)
@@ -180,7 +167,7 @@ export function iconEffects(node, opts = {}) {
180
167
  if (next.cursor !== opts.cursor && isHTML) {
181
168
  node.style.cursor = next.cursor || "";
182
169
  }
183
- // Detectar cambios relevantes para re-aplicar
170
+
184
171
  const changed = next.hoverScale !== opts.hoverScale ||
185
172
  next.pressScale !== opts.pressScale ||
186
173
  next.rotateOnHover !== opts.rotateOnHover ||
@@ -191,7 +178,7 @@ export function iconEffects(node, opts = {}) {
191
178
  next.morphOnHover !== opts.morphOnHover ||
192
179
  next.elasticOnClick !== opts.elasticOnClick ||
193
180
  next.heartbeatOnActive !== opts.heartbeatOnActive ||
194
- /** ✅ nuevo */
181
+
195
182
  next.heartbeatOnHover !== opts.heartbeatOnHover;
196
183
  Object.assign(opts, next);
197
184
  if (changed)
@@ -30,7 +30,7 @@
30
30
  stroke="currentColor"
31
31
  stroke-width="1.8"
32
32
  stroke-linecap="round"
33
- d="M9 2v2m6-2v2M9 20v2m6-2v2M2 9h2m-2 6h2M20 9h2m-2 6h2"
33
+ d="M9 2v2m6-2v2M9 20v2m6-2v2M2 9h2m-2 6h2m16-6h2m-2 6h2"
34
34
  />
35
35
 
36
36
  <path
@@ -38,7 +38,7 @@
38
38
  stroke="currentColor"
39
39
  stroke-width="1.5"
40
40
  stroke-linejoin="round"
41
- d="M12 8l3 4-3 4-3-4z"
41
+ d="m12 8 3 4-3 4-3-4z"
42
42
  />
43
43
 
44
44
  <circle cx="12" cy="12" r="1" fill="currentColor" />
@@ -15,12 +15,12 @@
15
15
  {#snippet children()}
16
16
  <path
17
17
  fill="currentColor"
18
- d="M21 5c0-.55-.45-1-1-1H9c-.55 0-1 .45-1 1s.45 1 1 1h5v12c0 .55.45 1 1 1s1-.45 1-1V6h4c.55 0 1-.45 1-1z"
18
+ d="M21 5c0-.55-.45-1-1-1H9c-.55 0-1 .45-1 1s.45 1 1 1h5v12c0 .55.45 1 1 1s1-.45 1-1V6h4c.55 0 1-.45 1-1"
19
19
  />
20
20
 
21
21
  <path
22
22
  fill="currentColor"
23
- d="M11 11c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1h3v6c0 .55.45 1 1 1s1-.45 1-1v-6h1c.55 0 1-.45 1-1z"
23
+ d="M11 11c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1s.45 1 1 1h3v6c0 .55.45 1 1 1s1-.45 1-1v-6h1c.55 0 1-.45 1-1"
24
24
  />
25
25
  {/snippet}
26
26
  </IconBase>
@@ -20,7 +20,7 @@
20
20
  stroke-linecap="round"
21
21
  stroke-linejoin="round"
22
22
  class="bz-arrow-path"
23
- d="M9 6l6 6-6 6"
23
+ d="m9 6 6 6-6 6"
24
24
  />
25
25
  {/snippet}
26
26
  </IconBase>
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import IconBase from "../IconBase.svelte";
3
+ import type { IconProps } from "../types";
4
+ const props: IconProps = $props();
5
+ </script>
6
+
7
+ <IconBase
8
+ {...props}
9
+ mode="solid"
10
+ viewBox="0 0 24 24"
11
+ ariaLabel={props.ariaLabel ?? "Arrow down"}
12
+ title={props.title ?? ""}
13
+ >
14
+ <path
15
+ fill="currentColor"
16
+ d="m20 12-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8z"
17
+ />
18
+ </IconBase>
@@ -0,0 +1,4 @@
1
+ import type { IconProps } from "../types";
2
+ declare const ArrowDown: import("svelte").Component<IconProps, {}, "">;
3
+ type ArrowDown = ReturnType<typeof ArrowDown>;
4
+ export default ArrowDown;
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import IconBase from "../IconBase.svelte";
3
+ import type { IconProps } from "../types";
4
+ const props: IconProps = $props();
5
+ </script>
6
+
7
+ <IconBase
8
+ {...props}
9
+ mode="solid"
10
+ viewBox="0 0 24 24"
11
+ ariaLabel={props.ariaLabel ?? "Arrow left"}
12
+ title={props.title ?? ""}
13
+ >
14
+ <path
15
+ fill="currentColor"
16
+ d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20z"
17
+ />
18
+ </IconBase>