@yoamigo.com/core 1.3.0 → 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.
@@ -1,6 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React__default, { ReactNode, CSSProperties, ComponentType } from 'react';
3
- import { IconProps } from '@tabler/icons-react';
2
+ import React__default, { ReactNode, CSSProperties } from 'react';
4
3
 
5
4
  type EditMode = 'read-only' | 'inline-edit';
6
5
  interface ContentStore {
@@ -201,14 +200,27 @@ interface BackgroundImageConfig {
201
200
  y: number;
202
201
  };
203
202
  }
203
+ interface GradientStop {
204
+ color: string;
205
+ position: number;
206
+ }
207
+ interface GradientConfig {
208
+ /** Gradient type: linear or radial */
209
+ gradientType: 'linear' | 'radial';
210
+ /** Angle in degrees for linear gradients (0 = to top, 90 = to right, 180 = to bottom, 270 = to left) */
211
+ angle?: number;
212
+ /** Color stops for the gradient */
213
+ stops: GradientStop[];
214
+ }
204
215
  interface OverlayConfig {
205
216
  color: string;
206
217
  opacity: number;
207
218
  }
208
219
  interface BackgroundConfig {
209
- type: 'none' | 'color' | 'image';
220
+ type: 'none' | 'color' | 'image' | 'gradient';
210
221
  backgroundColor?: string;
211
222
  backgroundImage?: BackgroundImageConfig;
223
+ gradient?: GradientConfig;
212
224
  overlay?: OverlayConfig;
213
225
  }
214
226
  interface YaContainerProps {
@@ -403,181 +415,73 @@ declare function embed(config: EmbedFieldValue): string;
403
415
  */
404
416
  declare function link(href: string): string;
405
417
 
406
- /**
407
- * DynamicIcon Component - Render icons by name with lazy loading
408
- *
409
- * This component loads Tabler icons dynamically to enable tree-shaking.
410
- * Icons are loaded on-demand and cached for subsequent renders.
411
- *
412
- * @example
413
- * ```tsx
414
- * // Basic usage
415
- * <DynamicIcon name="IconBrandTwitter" size={24} />
416
- *
417
- * // With custom styling
418
- * <DynamicIcon name="IconHeart" size={20} color="red" stroke={1.5} />
419
- *
420
- * // With fallback while loading
421
- * <DynamicIcon name="IconUser" size={24} fallback={<Spinner />} />
422
- * ```
423
- */
424
-
425
- interface DynamicIconProps extends Omit<IconProps, 'ref'> {
426
- /** Name of the Tabler icon (e.g., "IconBrandTwitter", "IconHeart") */
427
- name: string;
428
- /** Optional fallback element to show while loading */
429
- fallback?: React__default.ReactNode;
430
- /** Additional class name for the icon wrapper */
431
- className?: string;
418
+ interface UseSafeTriangleOptions {
419
+ /** Delay before showing popover (ms) */
420
+ showDelay?: number;
421
+ /** Delay before hiding popover after mouse leaves (ms) */
422
+ hideDelay?: number;
423
+ /** Whether the hook is enabled (for edit mode check) */
424
+ enabled?: boolean;
425
+ }
426
+ interface UseSafeTriangleReturn<T extends HTMLElement, U extends HTMLElement> {
427
+ /** Ref to attach to the trigger element */
428
+ triggerRef: React.RefObject<T | null>;
429
+ /** Ref to attach to the popover element */
430
+ popoverRef: React.RefObject<U | null>;
431
+ /** Whether the popover should be visible */
432
+ isVisible: boolean;
433
+ /** Event handlers to spread on the trigger container */
434
+ handlers: {
435
+ onMouseEnter: () => void;
436
+ onMouseLeave: () => void;
437
+ onFocus: () => void;
438
+ };
439
+ /** Event handlers to spread on the popover element */
440
+ popoverHandlers: {
441
+ onMouseEnter: () => void;
442
+ onMouseLeave: () => void;
443
+ };
444
+ /** Manually show the popover */
445
+ show: () => void;
446
+ /** Manually hide the popover */
447
+ hide: () => void;
432
448
  }
433
449
  /**
434
- * Renders a Tabler icon by name with lazy loading.
435
- *
436
- * The component first checks the cache for an already-loaded icon.
437
- * If not found, it dynamically imports the icon and caches it.
438
- *
439
- * For production builds where specific icons are known ahead of time,
440
- * consider pre-registering icons with `registerIcon()` for faster initial render.
441
- */
442
- declare function DynamicIconComponent({ name, fallback, className, size, stroke, ...props }: DynamicIconProps): React__default.ReactElement | null;
443
- /**
444
- * Memoized DynamicIcon to prevent unnecessary re-renders.
445
- * Re-renders only when name or size/stroke props change.
446
- */
447
- declare const DynamicIcon: React__default.MemoExoticComponent<typeof DynamicIconComponent>;
448
-
449
- /**
450
- * Icon Registry - Dynamic import system with caching
451
- *
452
- * This module provides tree-shakeable icon loading:
453
- * - Pre-register icons for faster initial render (sync)
454
- * - Dynamic import for lazy loading (async)
455
- * - LRU-like cache to prevent memory bloat
456
- */
457
-
458
- type IconComponent = ComponentType<IconProps>;
459
- type IconLoader = () => Promise<{
460
- default: IconComponent;
461
- }>;
462
- /**
463
- * Pre-register an icon with a custom loader.
464
- * Use this for icons that should be available immediately (e.g., commonly used icons).
450
+ * Hook for managing safe triangle popover state.
465
451
  *
466
- * @example
467
- * ```ts
468
- * // Pre-register for faster loading
469
- * registerIcon('IconBrandTwitter', () => import('@tabler/icons-react').then(m => ({ default: m.IconBrandTwitter })))
470
- * ```
471
- */
472
- declare function registerIcon(name: string, loader: IconLoader): void;
473
- /**
474
- * Pre-register multiple icons at once.
452
+ * Uses the centralized PopoverManager to coordinate between multiple
453
+ * YaLink/YaIcon instances, ensuring only one popover is active at a time.
475
454
  *
476
- * @example
477
- * ```ts
478
- * registerIcons({
479
- * IconBrandTwitter: () => import('@tabler/icons-react').then(m => ({ default: m.IconBrandTwitter })),
480
- * IconBrandFacebook: () => import('@tabler/icons-react').then(m => ({ default: m.IconBrandFacebook })),
481
- * })
482
- * ```
483
- */
484
- declare function registerIcons(loaders: Record<string, IconLoader>): void;
485
- /**
486
- * Get a cached icon component synchronously.
487
- * Returns null if the icon hasn't been loaded yet.
455
+ * ## How It Works
456
+ * 1. Registers this popover instance with PopoverManager on mount
457
+ * 2. Returns handlers to attach to trigger and popover elements
458
+ * 3. PopoverManager calls onShow/onHide callbacks to control `isVisible` state
488
459
  *
489
- * @example
490
- * ```ts
491
- * const Icon = getIcon('IconBrandTwitter')
492
- * if (Icon) {
493
- * return <Icon size={24} />
494
- * }
495
- * ```
496
- */
497
- declare function getIcon(name: string): IconComponent | null;
498
- /**
499
- * Load an icon dynamically with caching.
500
- * Uses pre-registered loader if available, otherwise falls back to dynamic import.
460
+ * ## Stale Popover Handling
461
+ * When a popover is hidden, it may remain in the DOM briefly for exit animations
462
+ * (see YaLink's editPopoverState). During this time:
463
+ * - onPopoverEnter: Still fires, PopoverManager uses it to cancel active hide timers
464
+ * - onPopoverLeave: Filtered out here (stale popovers shouldn't start hide timers)
501
465
  *
502
- * @example
503
- * ```ts
504
- * const Icon = await loadIcon('IconBrandTwitter')
505
- * if (Icon) {
506
- * return <Icon size={24} />
507
- * }
508
- * ```
509
- */
510
- declare function loadIcon(name: string): Promise<IconComponent | null>;
511
- /**
512
- * Preload multiple icons in parallel.
513
- * Useful for preloading icons that will be used soon.
466
+ * The CSS class `.is-hiding` should have `pointer-events: none` to prevent
467
+ * stale popovers from capturing clicks/hovers meant for the active popover.
514
468
  *
515
469
  * @example
516
- * ```ts
517
- * // Preload social icons before they're needed
518
- * await preloadIcons(['IconBrandTwitter', 'IconBrandFacebook', 'IconBrandInstagram'])
470
+ * ```tsx
471
+ * const { triggerRef, popoverRef, isVisible, handlers, popoverHandlers } = useSafeTriangle()
472
+ *
473
+ * return (
474
+ * <div>
475
+ * <a ref={triggerRef} {...handlers}>
476
+ * Hover me
477
+ * </a>
478
+ * {isVisible && (
479
+ * <div ref={popoverRef} {...popoverHandlers}>Popover content</div>
480
+ * )}
481
+ * </div>
482
+ * )
519
483
  * ```
520
484
  */
521
- declare function preloadIcons(names: string[]): Promise<void>;
522
- /**
523
- * Check if an icon is loaded and cached.
524
- */
525
- declare function isIconLoaded(name: string): boolean;
526
-
527
- /**
528
- * Icon Metadata - Curated list of commonly used icons
529
- *
530
- * This file contains ONLY metadata (strings) for search/filtering.
531
- * Actual icon components are loaded dynamically via icon-registry.ts
532
- *
533
- * Categories:
534
- * - brand: Social media and brand logos
535
- * - communication: Email, phone, chat
536
- * - media: Play, pause, volume, music
537
- * - navigation: Arrows, menu, home
538
- * - commerce: Cart, payment, shipping
539
- * - ui: Common UI elements
540
- * - files: Documents, folders
541
- * - weather: Weather icons
542
- * - misc: Miscellaneous useful icons
543
- *
544
- * Search Features:
545
- * - Keyword matching (exact substring)
546
- * - Alias matching (common abbreviations, rebrands)
547
- * - Fuzzy matching (typo tolerance via Levenshtein distance)
548
- */
549
- type IconCategory = 'brand' | 'communication' | 'media' | 'navigation' | 'commerce' | 'ui' | 'files' | 'weather' | 'misc';
550
- interface IconMeta {
551
- name: string;
552
- category: IconCategory;
553
- keywords: string[];
554
- }
555
- /**
556
- * Curated list of ~150 commonly used icons
557
- * These cover most website builder use cases
558
- */
559
- declare const ICON_METADATA: IconMeta[];
560
- /**
561
- * Category display names for the icon picker UI
562
- */
563
- declare const ICON_CATEGORIES: Record<IconCategory, string>;
564
- /**
565
- * Get icons by category
566
- */
567
- declare function getIconsByCategory(category: IconCategory): IconMeta[];
568
- /**
569
- * Search icons by keyword, alias, or fuzzy name match
570
- */
571
- declare function searchIcons(query: string): IconMeta[];
572
- /**
573
- * Get icon metadata by name
574
- */
575
- declare function getIconMeta(name: string): IconMeta | undefined;
576
- /**
577
- * Get human-readable label from icon name
578
- * e.g., "IconBrandTwitter" -> "Twitter"
579
- * e.g., "IconShoppingCart" -> "Shopping Cart"
580
- */
581
- declare function getIconLabel(name: string): string;
485
+ declare function useSafeTriangle<T extends HTMLElement = HTMLElement, U extends HTMLElement = HTMLDivElement>(options?: UseSafeTriangleOptions): UseSafeTriangleReturn<T, U>;
582
486
 
583
- export { serializeBackgroundConfig as $, getIconMeta as A, type IconCategory as B, ContentStoreProvider as C, DynamicIcon as D, type EditMode as E, type IconMeta as F, serializeImageValue as G, type YaImageProps as H, type IconComponent as I, type ImageFieldValue as J, YaVideo as K, serializeVideoValue as L, MpText as M, type YaVideoProps as N, YaEmbed as O, type PageInfo as P, serializeEmbedValue as Q, type YaEmbedProps as R, type StaticTextProps as S, type EmbedFieldValue as T, type EmbedType as U, type VideoFieldValue as V, YaLink as W, type YaLinkProps as X, YaImage as Y, YaContainer as Z, parseBackgroundConfig as _, type DynamicIconProps as a, type YaContainerProps as a0, type BackgroundConfig as a1, type BackgroundImageConfig as a2, type OverlayConfig as a3, background as b, registerIcons as c, loadIcon as d, embed as e, isIconLoaded as f, getIcon as g, type IconLoader as h, image as i, getIconLabel as j, type ContentStore as k, link as l, MpImage as m, type StaticImageProps as n, MarkdownText as o, preloadIcons as p, type MarkdownTextProps as q, registerIcon as r, parseEmbedUrl as s, text as t, useContentStore as u, video as v, ICON_METADATA as w, ICON_CATEGORIES as x, getIconsByCategory as y, searchIcons as z };
487
+ export { YaContainer as A, parseBackgroundConfig as B, ContentStoreProvider as C, serializeBackgroundConfig as D, type EditMode as E, type YaContainerProps as F, type BackgroundConfig as G, type BackgroundImageConfig as H, type ImageFieldValue as I, MpText as M, type OverlayConfig as O, type PageInfo as P, type StaticTextProps as S, type VideoFieldValue as V, YaImage as Y, useContentStore as a, background as b, type ContentStore as c, MpImage as d, embed as e, type StaticImageProps as f, MarkdownText as g, type MarkdownTextProps as h, image as i, type YaImageProps as j, YaVideo as k, link as l, serializeVideoValue as m, type YaVideoProps as n, YaEmbed as o, parseEmbedUrl as p, serializeEmbedValue as q, type YaEmbedProps as r, serializeImageValue as s, text as t, useSafeTriangle as u, video as v, type EmbedFieldValue as w, type EmbedType as x, YaLink as y, type YaLinkProps as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoamigo.com/core",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Core components, router, and utilities for YoAmigo templates",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -34,10 +34,18 @@
34
34
  "./icons": {
35
35
  "types": "./dist/icons.d.ts",
36
36
  "import": "./dist/icons.js"
37
+ },
38
+ "./icons/custom": {
39
+ "types": "./dist/icons-custom.d.ts",
40
+ "import": "./dist/icons-custom.js"
37
41
  }
38
42
  },
43
+ "bin": {
44
+ "icon-scanner": "./bin/icon-scanner.cjs"
45
+ },
39
46
  "files": [
40
47
  "dist",
48
+ "bin",
41
49
  "LICENSE",
42
50
  "README.md"
43
51
  ],
@@ -65,6 +73,8 @@
65
73
  "typecheck": "tsc --noEmit",
66
74
  "lint": "eslint src --ext .ts,.tsx",
67
75
  "lint:check": "eslint src --ext .ts,.tsx",
76
+ "generate:icons": "tsx scripts/generate-icon-loaders.ts",
77
+ "prebuild": "pnpm generate:icons",
68
78
  "prepublishOnly": "pnpm build"
69
79
  },
70
80
  "dependencies": {