@yoamigo.com/core 1.3.0 → 1.4.1

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 {
@@ -303,6 +315,18 @@ declare function MarkdownText({ content, className }: MarkdownTextProps): react_
303
315
  * ```
304
316
  */
305
317
 
318
+ /**
319
+ * Audio field value for linking audio assets to content fields.
320
+ * Used by audio players and other audio components.
321
+ */
322
+ interface AudioFieldValue {
323
+ /** Asset ID from the website_assets table */
324
+ assetId: string;
325
+ /** Original filename */
326
+ filename: string;
327
+ /** CDN URL for the audio file */
328
+ url: string;
329
+ }
306
330
  /**
307
331
  * Text content for YaText fields.
308
332
  *
@@ -402,182 +426,85 @@ declare function embed(config: EmbedFieldValue): string;
402
426
  * "footer.twitterLink.href": link("https://twitter.com/username"),
403
427
  */
404
428
  declare function link(href: string): string;
405
-
406
429
  /**
407
- * DynamicIcon Component - Render icons by name with lazy loading
430
+ * Audio field value for linking audio assets to content fields.
408
431
  *
409
- * This component loads Tabler icons dynamically to enable tree-shaking.
410
- * Icons are loaded on-demand and cached for subsequent renders.
432
+ * Used by audio players to link specific tracks to content slots.
433
+ * The assetId is used to look up the audio file from the API.
411
434
  *
412
435
  * @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
- * ```
436
+ * // In content.ts:
437
+ * "player.track1": audio({ assetId: "abc123", filename: "song.mp3", url: "/assets/song.mp3" }),
423
438
  */
439
+ declare function audio(config: AudioFieldValue): string;
424
440
 
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;
441
+ interface UseSafeTriangleOptions {
442
+ /** Delay before showing popover (ms) */
443
+ showDelay?: number;
444
+ /** Delay before hiding popover after mouse leaves (ms) */
445
+ hideDelay?: number;
446
+ /** Whether the hook is enabled (for edit mode check) */
447
+ enabled?: boolean;
448
+ }
449
+ interface UseSafeTriangleReturn<T extends HTMLElement, U extends HTMLElement> {
450
+ /** Ref to attach to the trigger element */
451
+ triggerRef: React.RefObject<T | null>;
452
+ /** Ref to attach to the popover element */
453
+ popoverRef: React.RefObject<U | null>;
454
+ /** Whether the popover should be visible */
455
+ isVisible: boolean;
456
+ /** Event handlers to spread on the trigger container */
457
+ handlers: {
458
+ onMouseEnter: () => void;
459
+ onMouseLeave: () => void;
460
+ onFocus: () => void;
461
+ };
462
+ /** Event handlers to spread on the popover element */
463
+ popoverHandlers: {
464
+ onMouseEnter: () => void;
465
+ onMouseLeave: () => void;
466
+ };
467
+ /** Manually show the popover */
468
+ show: () => void;
469
+ /** Manually hide the popover */
470
+ hide: () => void;
432
471
  }
433
472
  /**
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).
473
+ * Hook for managing safe triangle popover state.
465
474
  *
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.
475
+ * Uses the centralized PopoverManager to coordinate between multiple
476
+ * YaLink/YaIcon instances, ensuring only one popover is active at a time.
475
477
  *
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.
478
+ * ## How It Works
479
+ * 1. Registers this popover instance with PopoverManager on mount
480
+ * 2. Returns handlers to attach to trigger and popover elements
481
+ * 3. PopoverManager calls onShow/onHide callbacks to control `isVisible` state
488
482
  *
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.
483
+ * ## Stale Popover Handling
484
+ * When a popover is hidden, it may remain in the DOM briefly for exit animations
485
+ * (see YaLink's editPopoverState). During this time:
486
+ * - onPopoverEnter: Still fires, PopoverManager uses it to cancel active hide timers
487
+ * - onPopoverLeave: Filtered out here (stale popovers shouldn't start hide timers)
501
488
  *
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.
489
+ * The CSS class `.is-hiding` should have `pointer-events: none` to prevent
490
+ * stale popovers from capturing clicks/hovers meant for the active popover.
514
491
  *
515
492
  * @example
516
- * ```ts
517
- * // Preload social icons before they're needed
518
- * await preloadIcons(['IconBrandTwitter', 'IconBrandFacebook', 'IconBrandInstagram'])
493
+ * ```tsx
494
+ * const { triggerRef, popoverRef, isVisible, handlers, popoverHandlers } = useSafeTriangle()
495
+ *
496
+ * return (
497
+ * <div>
498
+ * <a ref={triggerRef} {...handlers}>
499
+ * Hover me
500
+ * </a>
501
+ * {isVisible && (
502
+ * <div ref={popoverRef} {...popoverHandlers}>Popover content</div>
503
+ * )}
504
+ * </div>
505
+ * )
519
506
  * ```
520
507
  */
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;
508
+ declare function useSafeTriangle<T extends HTMLElement = HTMLElement, U extends HTMLElement = HTMLDivElement>(options?: UseSafeTriangleOptions): UseSafeTriangleReturn<T, U>;
582
509
 
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 };
510
+ export { type AudioFieldValue as A, type YaLinkProps as B, ContentStoreProvider as C, YaContainer as D, type EditMode as E, parseBackgroundConfig as F, serializeBackgroundConfig as G, type YaContainerProps as H, type ImageFieldValue as I, type BackgroundConfig as J, type BackgroundImageConfig as K, MpText as M, type OverlayConfig as O, type PageInfo as P, type StaticTextProps as S, type VideoFieldValue as V, YaImage as Y, audio as a, background as b, useContentStore as c, type ContentStore as d, embed as e, MpImage as f, type StaticImageProps as g, MarkdownText as h, image as i, type MarkdownTextProps as j, type YaImageProps as k, link as l, YaVideo as m, serializeVideoValue as n, type YaVideoProps as o, parseEmbedUrl as p, YaEmbed as q, serializeEmbedValue as r, serializeImageValue as s, text as t, useSafeTriangle as u, video as v, type YaEmbedProps as w, type EmbedFieldValue as x, type EmbedType as y, YaLink 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.1",
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": {