@yoamigo.com/core 0.2.0 → 0.2.2

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,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React$1, { ReactNode } from 'react';
2
+ import React__default, { ReactNode } from 'react';
3
3
 
4
4
  type EditMode = 'read-only' | 'inline-edit';
5
5
  interface ContentStore {
@@ -28,9 +28,9 @@ interface YaLinkProps {
28
28
  href?: string;
29
29
  className?: string;
30
30
  /** Inline styles to apply to the link element */
31
- style?: React$1.CSSProperties;
31
+ style?: React__default.CSSProperties;
32
32
  as?: 'a' | 'span';
33
- children?: React$1.ReactNode;
33
+ children?: React__default.ReactNode;
34
34
  /** Available pages for href dropdown (injected by template) */
35
35
  availablePages?: PageInfo[];
36
36
  /** Optional click handler called after navigation */
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React, { ReactNode, CSSProperties } from 'react';
3
- export { C as ContentStoreProviderProd, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, Y as YaLink, f as YaLinkProps, u as useContentStoreProd } from './MarkdownText-BUTYfqXS.js';
2
+ import * as React$1 from 'react';
3
+ import React__default, { ReactNode, CSSProperties } from 'react';
4
+ export { C as ContentStoreProviderProd, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, Y as YaLink, f as YaLinkProps, u as useContentStoreProd } from './MarkdownText-kV5IiAma.js';
4
5
  export { Link, LinkProps, NavigateFunction, Router, RouterProps, useNavigate } from './router.js';
5
6
  export { Route, Switch, useParams } from 'wouter';
6
7
  export { A as AssetResolverFn, C as ContentRegistry, c as contentRegistry, a as getAllContent, g as getContent, h as hasContent, r as registerContent, b as resolveAssetUrl, s as setAssetResolver } from './asset-resolver-BnIvDkVv.js';
@@ -44,7 +45,7 @@ interface YaTextProps {
44
45
  className?: string;
45
46
  as?: YaTextElement;
46
47
  /** Optional fallback content (used if fieldId not in store) */
47
- children?: React.ReactNode;
48
+ children?: React__default.ReactNode;
48
49
  }
49
50
  declare module '@tiptap/core' {
50
51
  interface Commands<ReturnType> {
@@ -125,7 +126,9 @@ interface YaVideoProps {
125
126
  objectFit?: 'cover' | 'contain' | 'fill';
126
127
  /** Loading strategy */
127
128
  loading?: 'lazy' | 'eager';
128
- /** Fallback for backward compatibility */
129
+ /** Default video value (used when nothing in content store) */
130
+ defaultValue?: VideoFieldValue;
131
+ /** Fallback for backward compatibility (deprecated: use defaultValue) */
129
132
  fallbackSrc?: string;
130
133
  /** Fallback poster image */
131
134
  fallbackPoster?: string;
@@ -134,7 +137,7 @@ interface YaVideoProps {
134
137
  * Serialize video field value for storage
135
138
  */
136
139
  declare function serializeVideoValue(value: VideoFieldValue): string;
137
- declare function YaVideo({ fieldId, className, aspectRatio: propAspectRatio, objectFit: propObjectFit, loading, fallbackSrc, fallbackPoster, }: YaVideoProps): react_jsx_runtime.JSX.Element;
140
+ declare function YaVideo({ fieldId, className, aspectRatio: propAspectRatio, objectFit: propObjectFit, loading, defaultValue, fallbackSrc, fallbackPoster, }: YaVideoProps): react_jsx_runtime.JSX.Element;
138
141
 
139
142
  interface BackgroundImageConfig {
140
143
  src: string;
@@ -191,6 +194,39 @@ interface SafeHtmlProps {
191
194
  */
192
195
  declare function SafeHtml({ content, className, mode }: SafeHtmlProps): react_jsx_runtime.JSX.Element;
193
196
 
197
+ interface SafeTriangleBelowProps {
198
+ /** Ref to the trigger element */
199
+ triggerRef: React.RefObject<HTMLElement | null>;
200
+ /** Ref to the popover element */
201
+ popoverRef: React.RefObject<HTMLElement | null>;
202
+ /** Whether the popover is currently visible */
203
+ isVisible: boolean;
204
+ /** Called when mouse leaves the safe zone */
205
+ onLeave?: () => void;
206
+ }
207
+ /**
208
+ * SafeTriangleBelow creates a dynamic SVG triangle between the cursor and a popover
209
+ * that appears below the trigger, preventing the popover from closing when users
210
+ * move diagonally toward it.
211
+ *
212
+ * Based on the "Safe Triangle" pattern:
213
+ * @see https://www.smashingmagazine.com/2023/08/better-context-menus-safe-triangles/
214
+ *
215
+ * This variant is for popovers that appear BELOW the trigger (vs SafeTriangle which
216
+ * is for tooltips appearing to the RIGHT).
217
+ *
218
+ * Usage:
219
+ * ```tsx
220
+ * <SafeTriangleBelow
221
+ * triggerRef={triggerRef}
222
+ * popoverRef={popoverRef}
223
+ * isVisible={isOpen}
224
+ * onLeave={() => setIsOpen(false)}
225
+ * />
226
+ * ```
227
+ */
228
+ declare function SafeTriangleBelow({ triggerRef, popoverRef, isVisible, onLeave, }: SafeTriangleBelowProps): React$1.ReactPortal | null;
229
+
194
230
  /**
195
231
  * Animation state for a single field
196
232
  */
@@ -580,4 +616,60 @@ interface AnimatedTextOptions {
580
616
  */
581
617
  declare function useAnimatedText(fieldId: string, content: string, options?: AnimatedTextOptions): AnimatedTextResult;
582
618
 
583
- export { type AIEditContextValue, AIEditProvider, type AnimatedTextOptions, type AnimatedTextResult, type AnimationConfig, type AnimationMetadata, type AnimationOptions, type AnimationPhase, type AnimationResult, type AnimationState, type AnimationStrategy, type BackgroundConfig, type BackgroundImageConfig, type ContentStoreContextType, type ContentStoreMode, ContentStoreProvider, type ImageFieldValue, type ImageValue, type LinkValue, type OverlayConfig, SafeHtml, type SafeHtmlProps, type TextAnimationMetadata, type TextDiff, type VideoFieldValue, YaContainer, type YaContainerProps, YaImage, type YaImageProps, YaText, type YaTextProps, YaVideo, type YaVideoProps, buildIntermediateText, calculateAnimationTiming, computeTextDiff, containsHtml, getTextCursorPosition, imageCrossfadeStrategy, linkTransitionStrategy, parseBackgroundConfig, serializeBackgroundConfig, serializeImageValue, serializeVideoValue, stripHtml, textTypingStrategy, useAIEditAnimation, useAIEditContext, useAIEditContextOptional, useAnimatedText, useContentStore };
619
+ interface UseSafeTriangleOptions {
620
+ /** Delay before showing popover (ms) */
621
+ showDelay?: number;
622
+ /** Delay before hiding popover after mouse leaves (ms) */
623
+ hideDelay?: number;
624
+ /** Whether the hook is enabled (for edit mode check) */
625
+ enabled?: boolean;
626
+ }
627
+ interface UseSafeTriangleReturn<T extends HTMLElement, U extends HTMLElement> {
628
+ /** Ref to attach to the trigger element */
629
+ triggerRef: React.RefObject<T | null>;
630
+ /** Ref to attach to the popover element */
631
+ popoverRef: React.RefObject<U | null>;
632
+ /** Whether the popover should be visible */
633
+ isVisible: boolean;
634
+ /** Event handlers to spread on the trigger container */
635
+ handlers: {
636
+ onMouseEnter: () => void;
637
+ onMouseLeave: () => void;
638
+ onFocus: () => void;
639
+ };
640
+ /** Props to spread on the SafeTriangleBelow component */
641
+ triangleProps: {
642
+ triggerRef: React.RefObject<T | null>;
643
+ popoverRef: React.RefObject<U | null>;
644
+ isVisible: boolean;
645
+ onLeave: () => void;
646
+ };
647
+ /** Manually show the popover */
648
+ show: () => void;
649
+ /** Manually hide the popover */
650
+ hide: () => void;
651
+ }
652
+ /**
653
+ * Hook for managing safe triangle popover state.
654
+ * Handles show/hide delays and provides all necessary refs and handlers.
655
+ *
656
+ * @example
657
+ * ```tsx
658
+ * const { triggerRef, popoverRef, isVisible, handlers, triangleProps } = useSafeTriangle()
659
+ *
660
+ * return (
661
+ * <div>
662
+ * <a ref={triggerRef} {...handlers}>
663
+ * Hover me
664
+ * </a>
665
+ * {isVisible && (
666
+ * <div ref={popoverRef}>Popover content</div>
667
+ * )}
668
+ * <SafeTriangleBelow {...triangleProps} />
669
+ * </div>
670
+ * )
671
+ * ```
672
+ */
673
+ declare function useSafeTriangle<T extends HTMLElement = HTMLElement, U extends HTMLElement = HTMLDivElement>(options?: UseSafeTriangleOptions): UseSafeTriangleReturn<T, U>;
674
+
675
+ export { type AIEditContextValue, AIEditProvider, type AnimatedTextOptions, type AnimatedTextResult, type AnimationConfig, type AnimationMetadata, type AnimationOptions, type AnimationPhase, type AnimationResult, type AnimationState, type AnimationStrategy, type BackgroundConfig, type BackgroundImageConfig, type ContentStoreContextType, type ContentStoreMode, ContentStoreProvider, type ImageFieldValue, type ImageValue, type LinkValue, type OverlayConfig, SafeHtml, type SafeHtmlProps, SafeTriangleBelow, type TextAnimationMetadata, type TextDiff, type VideoFieldValue, YaContainer, type YaContainerProps, YaImage, type YaImageProps, YaText, type YaTextProps, YaVideo, type YaVideoProps, buildIntermediateText, calculateAnimationTiming, computeTextDiff, containsHtml, getTextCursorPosition, imageCrossfadeStrategy, linkTransitionStrategy, parseBackgroundConfig, serializeBackgroundConfig, serializeImageValue, serializeVideoValue, stripHtml, textTypingStrategy, useAIEditAnimation, useAIEditContext, useAIEditContextOptional, useAnimatedText, useContentStore, useSafeTriangle };
package/dist/index.js CHANGED
@@ -2917,6 +2917,7 @@ function YaVideo({
2917
2917
  aspectRatio: propAspectRatio,
2918
2918
  objectFit: propObjectFit,
2919
2919
  loading = "lazy",
2920
+ defaultValue,
2920
2921
  fallbackSrc,
2921
2922
  fallbackPoster
2922
2923
  }) {
@@ -2928,7 +2929,8 @@ function YaVideo({
2928
2929
  const [isSmallVideo, setIsSmallVideo] = useState7(false);
2929
2930
  const [isInView, setIsInView] = useState7(loading === "eager");
2930
2931
  const rawValue = getValue(fieldId);
2931
- const videoData = parseVideoValue(rawValue);
2932
+ const parsedValue = parseVideoValue(rawValue);
2933
+ const videoData = parsedValue.src ? parsedValue : defaultValue || parsedValue;
2932
2934
  const src = videoData.src || fallbackSrc || "";
2933
2935
  const poster = videoData.poster || fallbackPoster || "";
2934
2936
  const objectFit = videoData.objectFit || propObjectFit || "cover";
@@ -3228,8 +3230,8 @@ function YaVideo({
3228
3230
  }
3229
3231
 
3230
3232
  // src/components/YaLink.tsx
3231
- import { useEffect as useEffect8, useRef as useRef9, useState as useState8, useCallback as useCallback9 } from "react";
3232
- import { createPortal as createPortal4 } from "react-dom";
3233
+ import { useEffect as useEffect10, useRef as useRef10, useState as useState10, useCallback as useCallback10 } from "react";
3234
+ import { createPortal as createPortal5 } from "react-dom";
3233
3235
  import { useEditor as useEditor2, EditorContent as EditorContent2 } from "@tiptap/react";
3234
3236
  import { BubbleMenu as BubbleMenu2 } from "@tiptap/react/menus";
3235
3237
  import StarterKit2 from "@tiptap/starter-kit";
@@ -3237,11 +3239,169 @@ import { TextStyle as TextStyle2 } from "@tiptap/extension-text-style";
3237
3239
  import { Extension as Extension2 } from "@tiptap/core";
3238
3240
  import { Link as WouterLink, useLocation } from "wouter";
3239
3241
 
3242
+ // src/components/SafeTriangleBelow.tsx
3243
+ import { useEffect as useEffect8, useState as useState8 } from "react";
3244
+ import { createPortal as createPortal4 } from "react-dom";
3245
+ import { jsx as jsx9 } from "react/jsx-runtime";
3246
+ function SafeTriangleBelow({
3247
+ triggerRef,
3248
+ popoverRef,
3249
+ isVisible,
3250
+ onLeave
3251
+ }) {
3252
+ const [mousePos, setMousePos] = useState8({ x: 0, y: 0 });
3253
+ const [mounted, setMounted] = useState8(false);
3254
+ useEffect8(() => {
3255
+ setMounted(true);
3256
+ }, []);
3257
+ useEffect8(() => {
3258
+ if (!isVisible) return;
3259
+ const handleMouseMove = (e) => {
3260
+ setMousePos({ x: e.clientX, y: e.clientY });
3261
+ };
3262
+ document.addEventListener("mousemove", handleMouseMove);
3263
+ return () => document.removeEventListener("mousemove", handleMouseMove);
3264
+ }, [isVisible]);
3265
+ if (!mounted || !isVisible || !triggerRef.current || !popoverRef.current) {
3266
+ return null;
3267
+ }
3268
+ const popoverRect = popoverRef.current.getBoundingClientRect();
3269
+ const triggerRect = triggerRef.current.getBoundingClientRect();
3270
+ if (mousePos.y >= popoverRect.top) {
3271
+ return null;
3272
+ }
3273
+ const leftBound = Math.min(triggerRect.left, popoverRect.left) - 20;
3274
+ const rightBound = Math.max(triggerRect.right, popoverRect.right) + 20;
3275
+ if (mousePos.x < leftBound || mousePos.x > rightBound) {
3276
+ return null;
3277
+ }
3278
+ const svgTop = mousePos.y;
3279
+ const svgHeight = Math.max(popoverRect.top - mousePos.y, 1);
3280
+ const svgLeft = Math.min(mousePos.x, popoverRect.left);
3281
+ const svgWidth = Math.max(popoverRect.right - svgLeft, mousePos.x - svgLeft, 1);
3282
+ const cursorX = mousePos.x - svgLeft;
3283
+ const popoverLeftX = popoverRect.left - svgLeft;
3284
+ const popoverRightX = popoverRect.right - svgLeft;
3285
+ const path = `M ${cursorX},0 L ${popoverLeftX},${svgHeight} L ${popoverRightX},${svgHeight} z`;
3286
+ return createPortal4(
3287
+ /* @__PURE__ */ jsx9(
3288
+ "svg",
3289
+ {
3290
+ style: {
3291
+ position: "fixed",
3292
+ width: svgWidth,
3293
+ height: svgHeight,
3294
+ top: svgTop,
3295
+ left: svgLeft,
3296
+ pointerEvents: "none",
3297
+ zIndex: 9998
3298
+ },
3299
+ children: /* @__PURE__ */ jsx9(
3300
+ "path",
3301
+ {
3302
+ d: path,
3303
+ fill: "transparent",
3304
+ style: { pointerEvents: "auto" },
3305
+ onMouseLeave: onLeave
3306
+ }
3307
+ )
3308
+ }
3309
+ ),
3310
+ document.body
3311
+ );
3312
+ }
3313
+
3314
+ // src/hooks/useSafeTriangle.ts
3315
+ import { useState as useState9, useRef as useRef9, useCallback as useCallback9, useEffect as useEffect9 } from "react";
3316
+ function useSafeTriangle(options = {}) {
3317
+ const { showDelay = 0, hideDelay = 150, enabled = true } = options;
3318
+ const [isVisible, setIsVisible] = useState9(false);
3319
+ const [isHovering, setIsHovering] = useState9(false);
3320
+ const triggerRef = useRef9(null);
3321
+ const popoverRef = useRef9(null);
3322
+ const showTimeoutRef = useRef9(null);
3323
+ const hideTimeoutRef = useRef9(null);
3324
+ useEffect9(() => {
3325
+ return () => {
3326
+ if (showTimeoutRef.current) clearTimeout(showTimeoutRef.current);
3327
+ if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current);
3328
+ };
3329
+ }, []);
3330
+ const show = useCallback9(() => {
3331
+ if (!enabled) return;
3332
+ if (hideTimeoutRef.current) {
3333
+ clearTimeout(hideTimeoutRef.current);
3334
+ hideTimeoutRef.current = null;
3335
+ }
3336
+ setIsVisible(true);
3337
+ }, [enabled]);
3338
+ const hide = useCallback9(() => {
3339
+ if (showTimeoutRef.current) {
3340
+ clearTimeout(showTimeoutRef.current);
3341
+ showTimeoutRef.current = null;
3342
+ }
3343
+ setIsVisible(false);
3344
+ setIsHovering(false);
3345
+ }, []);
3346
+ const handleMouseEnter = useCallback9(() => {
3347
+ if (!enabled) return;
3348
+ setIsHovering(true);
3349
+ if (hideTimeoutRef.current) {
3350
+ clearTimeout(hideTimeoutRef.current);
3351
+ hideTimeoutRef.current = null;
3352
+ }
3353
+ if (showDelay > 0) {
3354
+ showTimeoutRef.current = setTimeout(() => {
3355
+ setIsVisible(true);
3356
+ }, showDelay);
3357
+ } else {
3358
+ setIsVisible(true);
3359
+ }
3360
+ }, [showDelay, enabled]);
3361
+ const handleMouseLeave = useCallback9(() => {
3362
+ setIsHovering(false);
3363
+ if (showTimeoutRef.current) {
3364
+ clearTimeout(showTimeoutRef.current);
3365
+ showTimeoutRef.current = null;
3366
+ }
3367
+ hideTimeoutRef.current = setTimeout(() => {
3368
+ setIsVisible(false);
3369
+ }, hideDelay);
3370
+ }, [hideDelay]);
3371
+ const handleFocus = useCallback9(() => {
3372
+ if (!enabled) return;
3373
+ setIsVisible(true);
3374
+ }, [enabled]);
3375
+ const handleTriangleLeave = useCallback9(() => {
3376
+ if (!isHovering) {
3377
+ setIsVisible(false);
3378
+ }
3379
+ }, [isHovering]);
3380
+ return {
3381
+ triggerRef,
3382
+ popoverRef,
3383
+ isVisible,
3384
+ handlers: {
3385
+ onMouseEnter: handleMouseEnter,
3386
+ onMouseLeave: handleMouseLeave,
3387
+ onFocus: handleFocus
3388
+ },
3389
+ triangleProps: {
3390
+ triggerRef,
3391
+ popoverRef,
3392
+ isVisible,
3393
+ onLeave: handleTriangleLeave
3394
+ },
3395
+ show,
3396
+ hide
3397
+ };
3398
+ }
3399
+
3240
3400
  // src/components/ya-link.css
3241
3401
  styleInject('.ya-link-wrapper {\n position: relative;\n display: inline;\n}\n.ya-link-editable {\n cursor: pointer;\n transition: outline 0.15s ease;\n}\n.ya-link-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n}\nbody.builder-selector-active .ya-link-editable:hover {\n outline: none;\n cursor: inherit;\n}\n.ya-link-editing {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 4px;\n border-radius: 4px;\n position: relative;\n}\n.ya-link-actions {\n display: flex;\n gap: 8px;\n position: absolute;\n bottom: -60px;\n right: 0;\n z-index: 10;\n background: rgba(26, 26, 26, 0.95);\n padding: 8px 10px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n.ya-link-btn {\n padding: 6px 14px;\n font-size: 12px;\n font-weight: 500;\n border-radius: 6px;\n cursor: pointer;\n transition: all 0.15s ease;\n border: none;\n}\n.ya-link-btn-cancel {\n background: #333333;\n color: #ffffff;\n border: 1px solid #555555;\n}\n.ya-link-btn-cancel:hover {\n background: #444444;\n color: #ffffff;\n border-color: #666666;\n}\n.ya-link-btn-save {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-link-btn-save:hover {\n background: #c4956a;\n}\n.ya-href-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 10;\n min-width: 280px;\n max-width: 320px;\n background: #1a1a1a;\n border-radius: 12px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);\n transform: translateX(-50%);\n animation: ya-href-popover-fade-in 0.15s ease;\n overflow: hidden;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n}\n@keyframes ya-href-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-href-popover::before {\n content: "";\n position: absolute;\n top: -6px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 8px solid transparent;\n border-right: 8px solid transparent;\n border-bottom: 8px solid #1a1a1a;\n}\n.ya-href-popover-header {\n padding: 12px 16px;\n font-size: 13px;\n font-weight: 600;\n color: #ffffff;\n border-bottom: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-href-popover-section {\n padding: 12px 16px;\n}\n.ya-href-popover-label {\n display: block;\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.6);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin-bottom: 8px;\n}\n.ya-href-collapsible-header {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 0;\n background: transparent;\n border: none;\n cursor: pointer;\n transition: color 0.15s ease;\n}\n.ya-href-collapsible-header:hover {\n color: rgba(255, 255, 255, 0.8);\n}\n.ya-href-chevron {\n font-size: 8px;\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-popover-pages {\n display: flex;\n flex-direction: column;\n gap: 4px;\n max-height: 200px;\n overflow-y: auto;\n}\n.ya-href-page-btn {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 4px;\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid transparent;\n border-radius: 8px;\n color: #e0e0e0;\n font-size: 13px;\n font-weight: 500;\n text-align: left;\n cursor: pointer;\n transition: all 0.15s ease;\n}\n.ya-href-page-btn:hover {\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(255, 255, 255, 0.2);\n}\n.ya-href-page-btn.is-selected {\n background: #D4A574;\n color: #1a1a1a;\n}\n.ya-href-page-btn.is-selected .ya-href-page-path {\n color: rgba(26, 26, 26, 0.6);\n}\n.ya-href-page-path {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n font-family: monospace;\n word-break: break-all;\n}\n.ya-href-external-toggle {\n display: block;\n width: 100%;\n padding: 10px 16px;\n background: transparent;\n border: none;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n color: #D4A574;\n font-size: 12px;\n font-weight: 500;\n text-align: center;\n cursor: pointer;\n transition: background 0.15s ease;\n}\n.ya-href-external-toggle:hover {\n background: rgba(255, 255, 255, 0.05);\n}\n.ya-href-url-input {\n width: 100%;\n padding: 10px 12px;\n background: rgba(255, 255, 255, 0.05);\n border: 1px solid rgba(255, 255, 255, 0.2);\n border-radius: 8px;\n color: #ffffff;\n font-size: 13px;\n outline: none;\n transition: border-color 0.15s ease;\n}\n.ya-href-url-input::placeholder {\n color: rgba(255, 255, 255, 0.4);\n}\n.ya-href-url-input:focus {\n border-color: var(--color-primary, #D4A574);\n}\n.ya-href-popover-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 12px 16px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n.ya-link-edit-popover {\n position: absolute;\n top: 100%;\n left: 50%;\n margin-top: 8px;\n z-index: 10;\n background: #2a2a2a;\n border-radius: 6px;\n padding: 4px;\n display: flex;\n gap: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transform: translateX(-50%);\n animation: ya-edit-popover-fade-in 0.1s ease;\n font-family:\n system-ui,\n -apple-system,\n BlinkMacSystemFont,\n "Segoe UI",\n sans-serif;\n white-space: nowrap;\n}\n@keyframes ya-edit-popover-fade-in {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n.ya-link-edit-popover::before {\n content: "";\n position: absolute;\n top: -5px;\n left: 50%;\n transform: translateX(-50%);\n border-left: 6px solid transparent;\n border-right: 6px solid transparent;\n border-bottom: 6px solid #2a2a2a;\n}\n.ya-link-edit-popover button {\n background: #3a3a3a;\n border: none;\n color: #fff;\n padding: 6px 12px;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 500;\n transition: background 0.15s ease;\n}\n.ya-link-edit-popover button:hover {\n background: #4a4a4a;\n}\n');
3242
3402
 
3243
3403
  // src/components/YaLink.tsx
3244
- import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
3404
+ import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
3245
3405
  function isInternalPath(path) {
3246
3406
  if (!path) return false;
3247
3407
  if (path.startsWith("#")) return false;
@@ -3342,8 +3502,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3342
3502
  const { getValue, setValue, mode, saveToWorker, getPages } = useContentStore();
3343
3503
  const [, navigate] = useLocation();
3344
3504
  const pages = availablePages ?? getPages();
3345
- const [sections, setSections] = useState8([]);
3346
- const [sectionsExpanded, setSectionsExpanded] = useState8(false);
3505
+ const [sections, setSections] = useState10([]);
3506
+ const [sectionsExpanded, setSectionsExpanded] = useState10(false);
3347
3507
  const textFieldId = `${fieldId}.text`;
3348
3508
  const hrefFieldId = `${fieldId}.href`;
3349
3509
  const storeText = getValue(textFieldId);
@@ -3354,16 +3514,25 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3354
3514
  const isExternal = isExternalHref(href);
3355
3515
  const effectiveTarget = target ?? (isExternal ? "_blank" : void 0);
3356
3516
  const effectiveRel = rel ?? (isExternal ? "noopener noreferrer" : void 0);
3357
- const [editingMode, setEditingMode] = useState8(null);
3358
- const [showEditPopover, setShowEditPopover] = useState8(false);
3359
- const [originalText, setOriginalText] = useState8(text);
3360
- const [originalHref, setOriginalHref] = useState8(href);
3361
- const [currentHref, setCurrentHref] = useState8(href);
3362
- const [isExternalUrl, setIsExternalUrl] = useState8(false);
3363
- const [externalUrl, setExternalUrl] = useState8("");
3364
- const containerRef = useRef9(null);
3365
- const hrefPopoverRef = useRef9(null);
3366
- const hidePopoverTimeoutRef = useRef9(null);
3517
+ const [editingMode, setEditingMode] = useState10(null);
3518
+ const [originalText, setOriginalText] = useState10(text);
3519
+ const [originalHref, setOriginalHref] = useState10(href);
3520
+ const [currentHref, setCurrentHref] = useState10(href);
3521
+ const [isExternalUrl, setIsExternalUrl] = useState10(false);
3522
+ const [externalUrl, setExternalUrl] = useState10("");
3523
+ const containerRef = useRef10(null);
3524
+ const hrefPopoverRef = useRef10(null);
3525
+ const {
3526
+ popoverRef: editPopoverRef,
3527
+ isVisible: showEditPopover,
3528
+ handlers: safeTriangleHandlers,
3529
+ triangleProps,
3530
+ hide: hideEditPopover
3531
+ } = useSafeTriangle({
3532
+ enabled: mode === "inline-edit" && !editingMode,
3533
+ hideDelay: 150
3534
+ });
3535
+ const triggerRef = containerRef;
3367
3536
  const editor = useEditor2({
3368
3537
  extensions: [
3369
3538
  StarterKit2.configure({
@@ -3386,26 +3555,19 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3386
3555
  }
3387
3556
  }
3388
3557
  });
3389
- useEffect8(() => {
3558
+ useEffect10(() => {
3390
3559
  if (editor && editingMode !== "text") {
3391
3560
  if (editor.getHTML() !== text) {
3392
3561
  editor.commands.setContent(text);
3393
3562
  }
3394
3563
  }
3395
3564
  }, [text, editor, editingMode]);
3396
- useEffect8(() => {
3565
+ useEffect10(() => {
3397
3566
  if (editingMode !== "link") {
3398
3567
  setCurrentHref(href);
3399
3568
  }
3400
3569
  }, [href, editingMode]);
3401
- useEffect8(() => {
3402
- return () => {
3403
- if (hidePopoverTimeoutRef.current) {
3404
- clearTimeout(hidePopoverTimeoutRef.current);
3405
- }
3406
- };
3407
- }, []);
3408
- useEffect8(() => {
3570
+ useEffect10(() => {
3409
3571
  if (editingMode !== "link") return;
3410
3572
  const handleClickOutside = (event) => {
3411
3573
  const target2 = event.target;
@@ -3419,7 +3581,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3419
3581
  document.addEventListener("mousedown", handleClickOutside);
3420
3582
  return () => document.removeEventListener("mousedown", handleClickOutside);
3421
3583
  }, [editingMode, originalHref]);
3422
- const handleSaveText = useCallback9(() => {
3584
+ const handleSaveText = useCallback10(() => {
3423
3585
  if (!editor) return;
3424
3586
  let html = editor.getHTML();
3425
3587
  html = html.replace(/<\/p><p>/g, "<br><br>").replace(/^<p>/, "").replace(/<\/p>$/, "");
@@ -3427,26 +3589,26 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3427
3589
  saveToWorker?.(textFieldId, html);
3428
3590
  setEditingMode(null);
3429
3591
  }, [editor, textFieldId, setValue, saveToWorker]);
3430
- const handleSaveLink = useCallback9(() => {
3592
+ const handleSaveLink = useCallback10(() => {
3431
3593
  setValue(hrefFieldId, currentHref);
3432
3594
  saveToWorker?.(hrefFieldId, currentHref);
3433
3595
  setEditingMode(null);
3434
3596
  setIsExternalUrl(false);
3435
3597
  setExternalUrl("");
3436
3598
  }, [hrefFieldId, currentHref, setValue, saveToWorker]);
3437
- const handleCancelText = useCallback9(() => {
3599
+ const handleCancelText = useCallback10(() => {
3438
3600
  if (editor) {
3439
3601
  editor.commands.setContent(originalText);
3440
3602
  }
3441
3603
  setEditingMode(null);
3442
3604
  }, [editor, originalText]);
3443
- const handleCancelLink = useCallback9(() => {
3605
+ const handleCancelLink = useCallback10(() => {
3444
3606
  setCurrentHref(originalHref);
3445
3607
  setEditingMode(null);
3446
3608
  setIsExternalUrl(false);
3447
3609
  setExternalUrl("");
3448
3610
  }, [originalHref]);
3449
- const handleClick = useCallback9(
3611
+ const handleClick = useCallback10(
3450
3612
  (e) => {
3451
3613
  const selectModeEnabled = window.__builderSelectModeEnabled;
3452
3614
  if (selectModeEnabled) {
@@ -3478,43 +3640,22 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3478
3640
  },
3479
3641
  [href, navigate, onClick]
3480
3642
  );
3481
- const handleMouseEnter = useCallback9(() => {
3482
- if (hidePopoverTimeoutRef.current) {
3483
- clearTimeout(hidePopoverTimeoutRef.current);
3484
- hidePopoverTimeoutRef.current = null;
3485
- }
3486
- if (mode === "inline-edit" && !editingMode) {
3487
- setShowEditPopover(true);
3488
- }
3489
- }, [mode, editingMode]);
3490
- const handleMouseLeave = useCallback9(() => {
3491
- hidePopoverTimeoutRef.current = window.setTimeout(() => {
3492
- if (!editingMode) {
3493
- setShowEditPopover(false);
3494
- }
3495
- }, 150);
3496
- }, [editingMode]);
3497
- const handleFocus = useCallback9(() => {
3498
- if (mode === "inline-edit" && !editingMode) {
3499
- setShowEditPopover(true);
3500
- }
3501
- }, [mode, editingMode]);
3502
- const startEditText = useCallback9(() => {
3503
- setShowEditPopover(false);
3643
+ const startEditText = useCallback10(() => {
3644
+ hideEditPopover();
3504
3645
  setEditingMode("text");
3505
3646
  setOriginalText(text);
3506
3647
  setTimeout(() => {
3507
3648
  editor?.chain().focus().selectAll().run();
3508
3649
  }, 20);
3509
- }, [text, editor]);
3510
- const startEditLink = useCallback9(() => {
3511
- setShowEditPopover(false);
3650
+ }, [text, editor, hideEditPopover]);
3651
+ const startEditLink = useCallback10(() => {
3652
+ hideEditPopover();
3512
3653
  setEditingMode("link");
3513
3654
  setOriginalHref(href);
3514
3655
  setCurrentHref(href);
3515
3656
  setSections(discoverSectionsFromDOM());
3516
- }, [href]);
3517
- const handleKeyDown = useCallback9(
3657
+ }, [href, hideEditPopover]);
3658
+ const handleKeyDown = useCallback10(
3518
3659
  (event) => {
3519
3660
  if (editingMode !== "text") return;
3520
3661
  if (event.key === "Enter" && !event.shiftKey) {
@@ -3535,7 +3676,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3535
3676
  },
3536
3677
  [editingMode, handleSaveText, handleCancelText]
3537
3678
  );
3538
- const handleFontSizeChange = useCallback9(
3679
+ const handleFontSizeChange = useCallback10(
3539
3680
  (e) => {
3540
3681
  if (!editor) return;
3541
3682
  const size = e.target.value;
@@ -3547,7 +3688,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3547
3688
  },
3548
3689
  [editor]
3549
3690
  );
3550
- const handleFontWeightChange = useCallback9(
3691
+ const handleFontWeightChange = useCallback10(
3551
3692
  (e) => {
3552
3693
  if (!editor) return;
3553
3694
  const weight = e.target.value;
@@ -3559,11 +3700,11 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3559
3700
  },
3560
3701
  [editor]
3561
3702
  );
3562
- const handlePageSelect = useCallback9((path) => {
3703
+ const handlePageSelect = useCallback10((path) => {
3563
3704
  setCurrentHref(path);
3564
3705
  setIsExternalUrl(false);
3565
3706
  }, []);
3566
- const handleExternalUrlApply = useCallback9(() => {
3707
+ const handleExternalUrlApply = useCallback10(() => {
3567
3708
  if (externalUrl) {
3568
3709
  setCurrentHref(externalUrl);
3569
3710
  }
@@ -3579,9 +3720,9 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3579
3720
  return attrs.fontWeight || "";
3580
3721
  };
3581
3722
  if (mode === "read-only") {
3582
- const content = isIconMode ? children : /* @__PURE__ */ jsx9(SafeHtml, { content: text, mode });
3723
+ const content = isIconMode ? children : /* @__PURE__ */ jsx10(SafeHtml, { content: text, mode });
3583
3724
  if (isInternalPath(href)) {
3584
- return /* @__PURE__ */ jsx9(
3725
+ return /* @__PURE__ */ jsx10(
3585
3726
  WouterLink,
3586
3727
  {
3587
3728
  href,
@@ -3593,7 +3734,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3593
3734
  }
3594
3735
  );
3595
3736
  }
3596
- return /* @__PURE__ */ jsx9(
3737
+ return /* @__PURE__ */ jsx10(
3597
3738
  Component,
3598
3739
  {
3599
3740
  ref: containerRef,
@@ -3609,7 +3750,7 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3609
3750
  );
3610
3751
  }
3611
3752
  return /* @__PURE__ */ jsxs5("span", { className: "ya-link-wrapper", children: [
3612
- /* @__PURE__ */ jsx9(
3753
+ /* @__PURE__ */ jsx10(
3613
3754
  Component,
3614
3755
  {
3615
3756
  ref: containerRef,
@@ -3621,15 +3762,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3621
3762
  "data-ya-restricted": "true",
3622
3763
  "data-field-id": fieldId,
3623
3764
  onClick: handleClick,
3624
- onMouseEnter: handleMouseEnter,
3625
- onMouseLeave: handleMouseLeave,
3626
- onFocus: handleFocus,
3765
+ onMouseEnter: safeTriangleHandlers.onMouseEnter,
3766
+ onMouseLeave: safeTriangleHandlers.onMouseLeave,
3767
+ onFocus: safeTriangleHandlers.onFocus,
3627
3768
  onKeyDown: handleKeyDown,
3628
3769
  children: isIconMode ? (
3629
3770
  // Icon mode: render children directly, no text editing
3630
3771
  children
3631
3772
  ) : editor ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3632
- createPortal4(
3773
+ createPortal5(
3633
3774
  /* @__PURE__ */ jsxs5(
3634
3775
  BubbleMenu2,
3635
3776
  {
@@ -3638,27 +3779,27 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3638
3779
  options: { offset: 6, placement: "top" },
3639
3780
  className: "ya-bubble-menu",
3640
3781
  children: [
3641
- /* @__PURE__ */ jsx9(
3782
+ /* @__PURE__ */ jsx10(
3642
3783
  "button",
3643
3784
  {
3644
3785
  type: "button",
3645
3786
  onClick: () => editor.chain().focus().toggleBold().run(),
3646
3787
  className: `ya-bubble-btn ${editor.isActive("bold") ? "is-active" : ""}`,
3647
3788
  title: "Bold",
3648
- children: /* @__PURE__ */ jsx9("strong", { children: "B" })
3789
+ children: /* @__PURE__ */ jsx10("strong", { children: "B" })
3649
3790
  }
3650
3791
  ),
3651
- /* @__PURE__ */ jsx9(
3792
+ /* @__PURE__ */ jsx10(
3652
3793
  "button",
3653
3794
  {
3654
3795
  type: "button",
3655
3796
  onClick: () => editor.chain().focus().toggleItalic().run(),
3656
3797
  className: `ya-bubble-btn ${editor.isActive("italic") ? "is-active" : ""}`,
3657
3798
  title: "Italic",
3658
- children: /* @__PURE__ */ jsx9("em", { children: "I" })
3799
+ children: /* @__PURE__ */ jsx10("em", { children: "I" })
3659
3800
  }
3660
3801
  ),
3661
- /* @__PURE__ */ jsx9("span", { className: "ya-bubble-divider" }),
3802
+ /* @__PURE__ */ jsx10("span", { className: "ya-bubble-divider" }),
3662
3803
  /* @__PURE__ */ jsxs5(
3663
3804
  "select",
3664
3805
  {
@@ -3667,8 +3808,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3667
3808
  className: "ya-bubble-select",
3668
3809
  title: "Font Size",
3669
3810
  children: [
3670
- /* @__PURE__ */ jsx9("option", { value: "", children: "Size" }),
3671
- Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx9("option", { value: size, children: name }, name))
3811
+ /* @__PURE__ */ jsx10("option", { value: "", children: "Size" }),
3812
+ Object.entries(SIZE_PRESETS2).map(([name, size]) => /* @__PURE__ */ jsx10("option", { value: size, children: name }, name))
3672
3813
  ]
3673
3814
  }
3674
3815
  ),
@@ -3680,8 +3821,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3680
3821
  className: "ya-bubble-select",
3681
3822
  title: "Font Weight",
3682
3823
  children: [
3683
- /* @__PURE__ */ jsx9("option", { value: "", children: "Weight" }),
3684
- Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx9("option", { value: weight, children: name }, name))
3824
+ /* @__PURE__ */ jsx10("option", { value: "", children: "Weight" }),
3825
+ Object.entries(WEIGHT_PRESETS2).map(([name, weight]) => /* @__PURE__ */ jsx10("option", { value: weight, children: name }, name))
3685
3826
  ]
3686
3827
  }
3687
3828
  )
@@ -3691,21 +3832,39 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3691
3832
  document.body
3692
3833
  ),
3693
3834
  editingMode === "text" ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3694
- /* @__PURE__ */ jsx9(EditorContent2, { editor }),
3835
+ /* @__PURE__ */ jsx10(EditorContent2, { editor }),
3695
3836
  /* @__PURE__ */ jsxs5("div", { className: "ya-link-actions", children: [
3696
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
3697
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
3837
+ /* @__PURE__ */ jsx10("button", { type: "button", onClick: handleCancelText, className: "ya-link-btn ya-link-btn-cancel", children: "Cancel" }),
3838
+ /* @__PURE__ */ jsx10("button", { type: "button", onClick: handleSaveText, className: "ya-link-btn ya-link-btn-save", children: "Save" })
3698
3839
  ] })
3699
- ] }) : /* @__PURE__ */ jsx9(SafeHtml, { content: text, mode })
3700
- ] }) : /* @__PURE__ */ jsx9(SafeHtml, { content: text, mode })
3840
+ ] }) : /* @__PURE__ */ jsx10(SafeHtml, { content: text, mode })
3841
+ ] }) : /* @__PURE__ */ jsx10(SafeHtml, { content: text, mode })
3842
+ }
3843
+ ),
3844
+ showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs5(
3845
+ "div",
3846
+ {
3847
+ ref: editPopoverRef,
3848
+ className: "ya-link-edit-popover",
3849
+ onMouseEnter: safeTriangleHandlers.onMouseEnter,
3850
+ onMouseLeave: safeTriangleHandlers.onMouseLeave,
3851
+ children: [
3852
+ !isIconMode && /* @__PURE__ */ jsx10("button", { type: "button", onClick: startEditText, children: "Edit text" }),
3853
+ /* @__PURE__ */ jsx10("button", { type: "button", onClick: startEditLink, children: "Edit link" })
3854
+ ]
3855
+ }
3856
+ ),
3857
+ /* @__PURE__ */ jsx10(
3858
+ SafeTriangleBelow,
3859
+ {
3860
+ triggerRef,
3861
+ popoverRef: editPopoverRef,
3862
+ isVisible: showEditPopover && !editingMode && mode === "inline-edit",
3863
+ onLeave: triangleProps.onLeave
3701
3864
  }
3702
3865
  ),
3703
- showEditPopover && !editingMode && mode === "inline-edit" && /* @__PURE__ */ jsxs5("div", { className: "ya-link-edit-popover", onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [
3704
- !isIconMode && /* @__PURE__ */ jsx9("button", { type: "button", onClick: startEditText, children: "Edit text" }),
3705
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: startEditLink, children: "Edit link" })
3706
- ] }),
3707
3866
  editingMode === "link" && /* @__PURE__ */ jsxs5("div", { ref: hrefPopoverRef, className: "ya-href-popover", children: [
3708
- /* @__PURE__ */ jsx9("div", { className: "ya-href-popover-header", children: "Link destination" }),
3867
+ /* @__PURE__ */ jsx10("div", { className: "ya-href-popover-header", children: "Link destination" }),
3709
3868
  !isExternalUrl ? /* @__PURE__ */ jsxs5(Fragment3, { children: [
3710
3869
  sections.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3711
3870
  /* @__PURE__ */ jsxs5(
@@ -3715,14 +3874,14 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3715
3874
  className: "ya-href-popover-label ya-href-collapsible-header",
3716
3875
  onClick: () => setSectionsExpanded(!sectionsExpanded),
3717
3876
  children: [
3718
- /* @__PURE__ */ jsx9("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
3877
+ /* @__PURE__ */ jsx10("span", { className: "ya-href-chevron", children: sectionsExpanded ? "\u25BC" : "\u25B6" }),
3719
3878
  "Scroll to section (",
3720
3879
  sections.length,
3721
3880
  ")"
3722
3881
  ]
3723
3882
  }
3724
3883
  ),
3725
- sectionsExpanded && /* @__PURE__ */ jsx9("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs5(
3884
+ sectionsExpanded && /* @__PURE__ */ jsx10("div", { className: "ya-href-popover-pages", children: sections.map((section) => /* @__PURE__ */ jsxs5(
3726
3885
  "button",
3727
3886
  {
3728
3887
  type: "button",
@@ -3730,15 +3889,15 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3730
3889
  onClick: () => handlePageSelect(section.path),
3731
3890
  children: [
3732
3891
  section.label,
3733
- /* @__PURE__ */ jsx9("span", { className: "ya-href-page-path", children: section.path })
3892
+ /* @__PURE__ */ jsx10("span", { className: "ya-href-page-path", children: section.path })
3734
3893
  ]
3735
3894
  },
3736
3895
  section.path
3737
3896
  )) })
3738
3897
  ] }),
3739
3898
  pages.length > 0 && /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3740
- /* @__PURE__ */ jsx9("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
3741
- /* @__PURE__ */ jsx9("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs5(
3899
+ /* @__PURE__ */ jsx10("label", { className: "ya-href-popover-label", children: "Navigate to page" }),
3900
+ /* @__PURE__ */ jsx10("div", { className: "ya-href-popover-pages", children: pages.map((page) => /* @__PURE__ */ jsxs5(
3742
3901
  "button",
3743
3902
  {
3744
3903
  type: "button",
@@ -3746,13 +3905,13 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3746
3905
  onClick: () => handlePageSelect(page.path),
3747
3906
  children: [
3748
3907
  page.label,
3749
- /* @__PURE__ */ jsx9("span", { className: "ya-href-page-path", children: page.path })
3908
+ /* @__PURE__ */ jsx10("span", { className: "ya-href-page-path", children: page.path })
3750
3909
  ]
3751
3910
  },
3752
3911
  page.path
3753
3912
  )) })
3754
3913
  ] }),
3755
- /* @__PURE__ */ jsx9(
3914
+ /* @__PURE__ */ jsx10(
3756
3915
  "button",
3757
3916
  {
3758
3917
  type: "button",
@@ -3766,8 +3925,8 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3766
3925
  )
3767
3926
  ] }) : /* @__PURE__ */ jsxs5(Fragment3, { children: [
3768
3927
  /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-section", children: [
3769
- /* @__PURE__ */ jsx9("label", { className: "ya-href-popover-label", children: "External URL" }),
3770
- /* @__PURE__ */ jsx9(
3928
+ /* @__PURE__ */ jsx10("label", { className: "ya-href-popover-label", children: "External URL" }),
3929
+ /* @__PURE__ */ jsx10(
3771
3930
  "input",
3772
3931
  {
3773
3932
  type: "url",
@@ -3779,25 +3938,25 @@ function YaLink({ fieldId, href: defaultHref = "#", className, style, as: Compon
3779
3938
  }
3780
3939
  )
3781
3940
  ] }),
3782
- /* @__PURE__ */ jsx9("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
3941
+ /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-href-external-toggle", onClick: () => setIsExternalUrl(false), children: "\u2190 Back to pages" })
3783
3942
  ] }),
3784
3943
  /* @__PURE__ */ jsxs5("div", { className: "ya-href-popover-actions", children: [
3785
- /* @__PURE__ */ jsx9("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
3786
- isExternalUrl ? /* @__PURE__ */ jsx9("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx9("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
3944
+ /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-link-btn ya-link-btn-cancel", onClick: handleCancelLink, children: "Cancel" }),
3945
+ isExternalUrl ? /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleExternalUrlApply, children: "Apply" }) : /* @__PURE__ */ jsx10("button", { type: "button", className: "ya-link-btn ya-link-btn-save", onClick: handleSaveLink, children: "Save" })
3787
3946
  ] })
3788
3947
  ] })
3789
3948
  ] });
3790
3949
  }
3791
3950
 
3792
3951
  // src/components/YaContainer.tsx
3793
- import { useCallback as useCallback10, useEffect as useEffect9, useRef as useRef10, useState as useState9 } from "react";
3794
- import { createPortal as createPortal5 } from "react-dom";
3952
+ import { useCallback as useCallback11, useEffect as useEffect11, useRef as useRef11, useState as useState11 } from "react";
3953
+ import { createPortal as createPortal6 } from "react-dom";
3795
3954
 
3796
3955
  // src/components/ya-container.css
3797
3956
  styleInject('.ya-container {\n position: relative;\n}\n.ya-container-has-overlay::after {\n content: "";\n position: absolute;\n inset: 0;\n background: var(--ya-overlay-color, transparent);\n opacity: var(--ya-overlay-opacity, 0);\n pointer-events: none;\n z-index: 0;\n}\n.ya-container > *:not(.ya-container-toolbar) {\n position: relative;\n z-index: 1;\n}\n.ya-container-editable {\n transition: outline 0.15s ease;\n}\n.ya-container-editable:hover {\n outline: 2px dashed var(--color-primary, #D4A574);\n outline-offset: -2px;\n}\nbody.builder-selector-active .ya-container-editable:hover {\n outline: none;\n}\n.ya-container-selected {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: -3px;\n}\n.ya-container-toolbar {\n display: flex;\n gap: 4px;\n background: rgba(26, 26, 26, 0.95);\n padding: 6px 8px;\n border-radius: 8px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);\n z-index: 9999;\n animation: ya-container-toolbar-fade-in 0.15s ease;\n}\n@keyframes ya-container-toolbar-fade-in {\n from {\n opacity: 0;\n transform: translateY(-4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n.ya-container-toolbar button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n background: #3a3a3a;\n border: none;\n border-radius: 6px;\n color: #ffffff;\n cursor: pointer;\n transition: background 0.15s ease, transform 0.1s ease;\n}\n.ya-container-toolbar button:hover {\n background: #4a4a4a;\n transform: scale(1.05);\n}\n.ya-container-toolbar button:active {\n transform: scale(0.98);\n}\n.ya-container-toolbar button.active {\n background: var(--color-primary, #D4A574);\n color: #1a1a1a;\n}\n.ya-container-toolbar button svg {\n width: 16px;\n height: 16px;\n}\n.ya-container-toolbar button[aria-label="Clear background"] {\n background: #3a2a2a;\n}\n.ya-container-toolbar button[aria-label="Clear background"]:hover {\n background: #5a3a3a;\n}\n.ya-container:focus-visible {\n outline: 3px solid var(--color-primary, #D4A574);\n outline-offset: -3px;\n}\n.ya-container-toolbar button:focus-visible {\n outline: 2px solid var(--color-primary, #D4A574);\n outline-offset: 2px;\n}\n.ya-container-drop-target {\n outline: 2px dashed var(--ya-drop-color, #3b82f6) !important;\n outline-offset: -2px;\n}\n.ya-container-drop-target .ya-container-toolbar {\n display: none !important;\n}\n.ya-container-drop-hover {\n outline: 3px solid var(--ya-drop-color, #3b82f6) !important;\n outline-offset: -3px;\n}\n.ya-container-drop-hover::before {\n content: "";\n position: absolute;\n inset: 0;\n background: rgba(59, 130, 246, 0.08);\n pointer-events: none;\n z-index: 10;\n animation: ya-container-drop-pulse 1s ease-in-out infinite;\n}\n@keyframes ya-container-drop-pulse {\n 0%, 100% {\n background: rgba(59, 130, 246, 0.05);\n }\n 50% {\n background: rgba(59, 130, 246, 0.12);\n }\n}\n');
3798
3957
 
3799
3958
  // src/components/YaContainer.tsx
3800
- import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
3959
+ import { jsx as jsx11, jsxs as jsxs6 } from "react/jsx-runtime";
3801
3960
  function parseBackgroundConfig(value) {
3802
3961
  if (!value) {
3803
3962
  return { type: "none" };
@@ -3839,8 +3998,8 @@ function deriveContainerLabel(element) {
3839
3998
  return tagLabels[tagName] || "Section";
3840
3999
  }
3841
4000
  function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearClick, hasBackground }) {
3842
- const [position, setPosition] = useState9(null);
3843
- useEffect9(() => {
4001
+ const [position, setPosition] = useState11(null);
4002
+ useEffect11(() => {
3844
4003
  const updatePosition = () => {
3845
4004
  if (containerRef.current) {
3846
4005
  const rect = containerRef.current.getBoundingClientRect();
@@ -3859,7 +4018,7 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3859
4018
  };
3860
4019
  }, [containerRef]);
3861
4020
  if (!position) return null;
3862
- return createPortal5(
4021
+ return createPortal6(
3863
4022
  /* @__PURE__ */ jsxs6(
3864
4023
  "div",
3865
4024
  {
@@ -3871,7 +4030,7 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3871
4030
  },
3872
4031
  onClick: (e) => e.stopPropagation(),
3873
4032
  children: [
3874
- /* @__PURE__ */ jsx10(
4033
+ /* @__PURE__ */ jsx11(
3875
4034
  "button",
3876
4035
  {
3877
4036
  type: "button",
@@ -3879,13 +4038,13 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3879
4038
  "aria-label": "Edit background image",
3880
4039
  title: "Background Image",
3881
4040
  children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3882
- /* @__PURE__ */ jsx10("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
3883
- /* @__PURE__ */ jsx10("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
3884
- /* @__PURE__ */ jsx10("polyline", { points: "21 15 16 10 5 21" })
4041
+ /* @__PURE__ */ jsx11("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
4042
+ /* @__PURE__ */ jsx11("circle", { cx: "8.5", cy: "8.5", r: "1.5" }),
4043
+ /* @__PURE__ */ jsx11("polyline", { points: "21 15 16 10 5 21" })
3885
4044
  ] })
3886
4045
  }
3887
4046
  ),
3888
- /* @__PURE__ */ jsx10(
4047
+ /* @__PURE__ */ jsx11(
3889
4048
  "button",
3890
4049
  {
3891
4050
  type: "button",
@@ -3893,12 +4052,12 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3893
4052
  "aria-label": "Edit background color",
3894
4053
  title: "Background Color",
3895
4054
  children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3896
- /* @__PURE__ */ jsx10("circle", { cx: "12", cy: "12", r: "10" }),
3897
- /* @__PURE__ */ jsx10("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
4055
+ /* @__PURE__ */ jsx11("circle", { cx: "12", cy: "12", r: "10" }),
4056
+ /* @__PURE__ */ jsx11("path", { d: "M12 2a10 10 0 0 1 0 20", fill: "currentColor" })
3898
4057
  ] })
3899
4058
  }
3900
4059
  ),
3901
- /* @__PURE__ */ jsx10(
4060
+ /* @__PURE__ */ jsx11(
3902
4061
  "button",
3903
4062
  {
3904
4063
  type: "button",
@@ -3906,13 +4065,13 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3906
4065
  "aria-label": "Ask AI for help",
3907
4066
  title: "AI Assist",
3908
4067
  children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3909
- /* @__PURE__ */ jsx10("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
3910
- /* @__PURE__ */ jsx10("path", { d: "M2 17l10 5 10-5" }),
3911
- /* @__PURE__ */ jsx10("path", { d: "M2 12l10 5 10-5" })
4068
+ /* @__PURE__ */ jsx11("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
4069
+ /* @__PURE__ */ jsx11("path", { d: "M2 17l10 5 10-5" }),
4070
+ /* @__PURE__ */ jsx11("path", { d: "M2 12l10 5 10-5" })
3912
4071
  ] })
3913
4072
  }
3914
4073
  ),
3915
- hasBackground && /* @__PURE__ */ jsx10(
4074
+ hasBackground && /* @__PURE__ */ jsx11(
3916
4075
  "button",
3917
4076
  {
3918
4077
  type: "button",
@@ -3920,8 +4079,8 @@ function Toolbar({ containerRef, onImageClick, onColorClick, onAIClick, onClearC
3920
4079
  "aria-label": "Clear background",
3921
4080
  title: "Clear Background",
3922
4081
  children: /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
3923
- /* @__PURE__ */ jsx10("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
3924
- /* @__PURE__ */ jsx10("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
4082
+ /* @__PURE__ */ jsx11("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
4083
+ /* @__PURE__ */ jsx11("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
3925
4084
  ] })
3926
4085
  }
3927
4086
  )
@@ -3940,11 +4099,11 @@ function YaContainer({
3940
4099
  defaultBackground
3941
4100
  }) {
3942
4101
  const { getValue, setValue, saveToWorker, mode } = useContentStore();
3943
- const containerRef = useRef10(null);
3944
- const [isHovered, setIsHovered] = useState9(false);
3945
- const [isSelected, setIsSelected] = useState9(false);
3946
- const [isDropMode, setIsDropMode] = useState9(false);
3947
- const [isDropHover, setIsDropHover] = useState9(false);
4102
+ const containerRef = useRef11(null);
4103
+ const [isHovered, setIsHovered] = useState11(false);
4104
+ const [isSelected, setIsSelected] = useState11(false);
4105
+ const [isDropMode, setIsDropMode] = useState11(false);
4106
+ const [isDropHover, setIsDropHover] = useState11(false);
3948
4107
  const rawValue = getValue(fieldId);
3949
4108
  const backgroundConfig = rawValue ? parseBackgroundConfig(rawValue) : defaultBackground || { type: "none" };
3950
4109
  const hasBackground = backgroundConfig.type !== "none";
@@ -3965,7 +4124,7 @@ function YaContainer({
3965
4124
  overlayCustomProps["--ya-overlay-color"] = backgroundConfig.overlay.color;
3966
4125
  overlayCustomProps["--ya-overlay-opacity"] = backgroundConfig.overlay.opacity;
3967
4126
  }
3968
- const handleImageClick = useCallback10(() => {
4127
+ const handleImageClick = useCallback11(() => {
3969
4128
  if (mode !== "inline-edit") return;
3970
4129
  setIsSelected(true);
3971
4130
  const rect = containerRef.current?.getBoundingClientRect();
@@ -3985,7 +4144,7 @@ function YaContainer({
3985
4144
  "*"
3986
4145
  );
3987
4146
  }, [mode, fieldId, backgroundConfig]);
3988
- const handleColorClick = useCallback10(() => {
4147
+ const handleColorClick = useCallback11(() => {
3989
4148
  if (mode !== "inline-edit") return;
3990
4149
  setIsSelected(true);
3991
4150
  const rect = containerRef.current?.getBoundingClientRect();
@@ -4005,7 +4164,7 @@ function YaContainer({
4005
4164
  "*"
4006
4165
  );
4007
4166
  }, [mode, fieldId, backgroundConfig]);
4008
- const handleAIClick = useCallback10(() => {
4167
+ const handleAIClick = useCallback11(() => {
4009
4168
  if (mode !== "inline-edit") return;
4010
4169
  const label = deriveContainerLabel(containerRef.current);
4011
4170
  window.parent.postMessage(
@@ -4018,14 +4177,14 @@ function YaContainer({
4018
4177
  "*"
4019
4178
  );
4020
4179
  }, [mode, fieldId, backgroundConfig]);
4021
- const handleClearClick = useCallback10(() => {
4180
+ const handleClearClick = useCallback11(() => {
4022
4181
  if (mode !== "inline-edit") return;
4023
4182
  const clearedConfig = { type: "none" };
4024
4183
  const serialized = serializeBackgroundConfig(clearedConfig);
4025
4184
  setValue(fieldId, serialized);
4026
4185
  saveToWorker?.(fieldId, serialized);
4027
4186
  }, [mode, fieldId, setValue, saveToWorker]);
4028
- useEffect9(() => {
4187
+ useEffect11(() => {
4029
4188
  if (mode !== "inline-edit") return;
4030
4189
  const handleMessage2 = (event) => {
4031
4190
  if (event.data?.type === "YA_CONTAINER_EDIT_COMPLETE" && event.data.fieldId === fieldId) {
@@ -4038,7 +4197,7 @@ function YaContainer({
4038
4197
  window.addEventListener("message", handleMessage2);
4039
4198
  return () => window.removeEventListener("message", handleMessage2);
4040
4199
  }, [mode, fieldId]);
4041
- useEffect9(() => {
4200
+ useEffect11(() => {
4042
4201
  if (mode !== "inline-edit") return;
4043
4202
  const handleDropModeMessage = (event) => {
4044
4203
  if (event.data?.type === "DROP_MODE_START") {
@@ -4052,7 +4211,7 @@ function YaContainer({
4052
4211
  window.addEventListener("message", handleDropModeMessage);
4053
4212
  return () => window.removeEventListener("message", handleDropModeMessage);
4054
4213
  }, [mode]);
4055
- const handleDragEnter = useCallback10(
4214
+ const handleDragEnter = useCallback11(
4056
4215
  (e) => {
4057
4216
  if (!isDropMode) return;
4058
4217
  e.preventDefault();
@@ -4076,7 +4235,7 @@ function YaContainer({
4076
4235
  },
4077
4236
  [isDropMode, fieldId]
4078
4237
  );
4079
- const handleDragOver = useCallback10(
4238
+ const handleDragOver = useCallback11(
4080
4239
  (e) => {
4081
4240
  if (!isDropMode) return;
4082
4241
  e.preventDefault();
@@ -4084,7 +4243,7 @@ function YaContainer({
4084
4243
  },
4085
4244
  [isDropMode]
4086
4245
  );
4087
- const handleDragLeave = useCallback10(
4246
+ const handleDragLeave = useCallback11(
4088
4247
  (e) => {
4089
4248
  if (!isDropMode) return;
4090
4249
  e.preventDefault();
@@ -4098,7 +4257,7 @@ function YaContainer({
4098
4257
  },
4099
4258
  [isDropMode]
4100
4259
  );
4101
- const handleDrop = useCallback10(
4260
+ const handleDrop = useCallback11(
4102
4261
  (e) => {
4103
4262
  if (!isDropMode) return;
4104
4263
  e.preventDefault();
@@ -4116,7 +4275,7 @@ function YaContainer({
4116
4275
  },
4117
4276
  [isDropMode, fieldId]
4118
4277
  );
4119
- useEffect9(() => {
4278
+ useEffect11(() => {
4120
4279
  if (!isSelected || mode !== "inline-edit") return;
4121
4280
  let lastRectKey = "";
4122
4281
  let lastTime = 0;
@@ -4151,7 +4310,7 @@ function YaContainer({
4151
4310
  return () => cancelAnimationFrame(rafId);
4152
4311
  }, [isSelected, fieldId, mode]);
4153
4312
  if (mode === "read-only") {
4154
- return /* @__PURE__ */ jsx10(
4313
+ return /* @__PURE__ */ jsx11(
4155
4314
  Tag,
4156
4315
  {
4157
4316
  className: `ya-container ${className || ""}`,
@@ -4196,7 +4355,7 @@ function YaContainer({
4196
4355
  onDrop: handleDrop,
4197
4356
  children: [
4198
4357
  children,
4199
- mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx10(
4358
+ mode === "inline-edit" && (isHovered || isSelected) && !document.body.classList.contains("builder-selector-active") && /* @__PURE__ */ jsx11(
4200
4359
  Toolbar,
4201
4360
  {
4202
4361
  containerRef,
@@ -4213,10 +4372,10 @@ function YaContainer({
4213
4372
  }
4214
4373
 
4215
4374
  // src/components/StaticText.tsx
4216
- import { jsx as jsx11 } from "react/jsx-runtime";
4375
+ import { jsx as jsx12 } from "react/jsx-runtime";
4217
4376
  function MpText({ fieldId, className, as: Component = "span", children }) {
4218
4377
  const content = getContent(fieldId) || (typeof children === "string" ? children : "");
4219
- return /* @__PURE__ */ jsx11(
4378
+ return /* @__PURE__ */ jsx12(
4220
4379
  Component,
4221
4380
  {
4222
4381
  className,
@@ -4227,7 +4386,7 @@ function MpText({ fieldId, className, as: Component = "span", children }) {
4227
4386
  }
4228
4387
 
4229
4388
  // src/components/StaticImage.tsx
4230
- import { jsx as jsx12 } from "react/jsx-runtime";
4389
+ import { jsx as jsx13 } from "react/jsx-runtime";
4231
4390
  function parseImageValue2(value) {
4232
4391
  if (!value) {
4233
4392
  return { src: "" };
@@ -4263,7 +4422,7 @@ function MpImage({
4263
4422
  const altText = imageData.alt || alt || fallbackAlt || "";
4264
4423
  const objectFit = imageData.objectFit || propObjectFit || "cover";
4265
4424
  const objectPosition = getObjectPosition3(imageData) || propObjectPosition || "50% 50%";
4266
- return /* @__PURE__ */ jsx12(
4425
+ return /* @__PURE__ */ jsx13(
4267
4426
  "img",
4268
4427
  {
4269
4428
  src: resolveAssetUrl(src),
@@ -4281,7 +4440,7 @@ function MpImage({
4281
4440
 
4282
4441
  // src/components/MarkdownText.tsx
4283
4442
  import { Fragment as Fragment4 } from "react";
4284
- import { jsx as jsx13 } from "react/jsx-runtime";
4443
+ import { jsx as jsx14 } from "react/jsx-runtime";
4285
4444
  function tokenize(text) {
4286
4445
  const tokens = [];
4287
4446
  let remaining = text;
@@ -4343,13 +4502,13 @@ function tokensToElements(tokens) {
4343
4502
  return tokens.map((token, index) => {
4344
4503
  switch (token.type) {
4345
4504
  case "text":
4346
- return /* @__PURE__ */ jsx13(Fragment4, { children: token.content }, index);
4505
+ return /* @__PURE__ */ jsx14(Fragment4, { children: token.content }, index);
4347
4506
  case "bold":
4348
- return /* @__PURE__ */ jsx13("strong", { children: token.content }, index);
4507
+ return /* @__PURE__ */ jsx14("strong", { children: token.content }, index);
4349
4508
  case "italic":
4350
- return /* @__PURE__ */ jsx13("em", { children: token.content }, index);
4509
+ return /* @__PURE__ */ jsx14("em", { children: token.content }, index);
4351
4510
  case "link":
4352
- return /* @__PURE__ */ jsx13(
4511
+ return /* @__PURE__ */ jsx14(
4353
4512
  "a",
4354
4513
  {
4355
4514
  href: token.url,
@@ -4361,7 +4520,7 @@ function tokensToElements(tokens) {
4361
4520
  index
4362
4521
  );
4363
4522
  case "newline":
4364
- return /* @__PURE__ */ jsx13("br", {}, index);
4523
+ return /* @__PURE__ */ jsx14("br", {}, index);
4365
4524
  default:
4366
4525
  return null;
4367
4526
  }
@@ -4373,15 +4532,15 @@ function parseMarkdownToElements(content) {
4373
4532
  }
4374
4533
  function MarkdownText({ content, className }) {
4375
4534
  const elements = parseMarkdownToElements(content);
4376
- return /* @__PURE__ */ jsx13("span", { className, children: elements });
4535
+ return /* @__PURE__ */ jsx14("span", { className, children: elements });
4377
4536
  }
4378
4537
 
4379
4538
  // src/router/Link.tsx
4380
4539
  import { Link as WouterLink2 } from "wouter";
4381
- import { jsx as jsx14 } from "react/jsx-runtime";
4540
+ import { jsx as jsx15 } from "react/jsx-runtime";
4382
4541
  function Link2({ to, href, children, className, onClick, replace, ...props }) {
4383
4542
  const target = href ?? to ?? "/";
4384
- return /* @__PURE__ */ jsx14(WouterLink2, { href: target, className, onClick, replace, ...props, children });
4543
+ return /* @__PURE__ */ jsx15(WouterLink2, { href: target, className, onClick, replace, ...props, children });
4385
4544
  }
4386
4545
 
4387
4546
  // src/router/useNavigate.ts
@@ -4400,7 +4559,7 @@ function useNavigate() {
4400
4559
 
4401
4560
  // src/router/Router.tsx
4402
4561
  import { Router as WouterRouter } from "wouter";
4403
- import { jsx as jsx15 } from "react/jsx-runtime";
4562
+ import { jsx as jsx16 } from "react/jsx-runtime";
4404
4563
  function detectBasename() {
4405
4564
  if (typeof window === "undefined") return "";
4406
4565
  const sessionMatch = window.location.pathname.match(/^\/session\/[^/]+/);
@@ -4415,7 +4574,7 @@ function detectBasename() {
4415
4574
  }
4416
4575
  function Router({ children, base }) {
4417
4576
  const basename = base ?? detectBasename();
4418
- return /* @__PURE__ */ jsx15(WouterRouter, { base: basename, children });
4577
+ return /* @__PURE__ */ jsx16(WouterRouter, { base: basename, children });
4419
4578
  }
4420
4579
 
4421
4580
  // src/router/index.ts
@@ -4429,6 +4588,7 @@ export {
4429
4588
  Route,
4430
4589
  Router,
4431
4590
  SafeHtml,
4591
+ SafeTriangleBelow,
4432
4592
  MpImage as StaticImage,
4433
4593
  MpText as StaticText,
4434
4594
  Switch,
@@ -4465,5 +4625,6 @@ export {
4465
4625
  useContentStore,
4466
4626
  useContentStore2 as useContentStoreProd,
4467
4627
  useNavigate,
4468
- useParams
4628
+ useParams,
4629
+ useSafeTriangle
4469
4630
  };
package/dist/plugin.js CHANGED
@@ -6,6 +6,37 @@ function yoamigoPlugin(options = {}) {
6
6
  const templateDir = process.cwd();
7
7
  const resolveFromTemplate = (relativePath) => path.resolve(templateDir, relativePath);
8
8
  return [
9
+ // Content HMR plugin - enables hot reloading of content.ts without full page refresh
10
+ {
11
+ name: "yoamigo:content-hmr",
12
+ handleHotUpdate({ file, server }) {
13
+ if (!file.endsWith("/content.ts") && !file.endsWith("\\content.ts")) return;
14
+ server.ws.send({
15
+ type: "custom",
16
+ event: "yoamigo:content-update"
17
+ });
18
+ return [];
19
+ },
20
+ transform(code, id) {
21
+ if (!id.match(/\/main\.tsx?$/) && !id.match(/\\main\.tsx?$/)) return;
22
+ const hmrCode = `
23
+ // YoAmigo Content HMR - injected by yoamigo:content-hmr plugin
24
+ if (import.meta.hot) {
25
+ import.meta.hot.on('yoamigo:content-update', async () => {
26
+ try {
27
+ const { default: newContent } = await import('./content?t=' + Date.now())
28
+ const { registerContent } = await import('@yoamigo.com/core')
29
+ registerContent(newContent)
30
+ window.dispatchEvent(new CustomEvent('content-updated'))
31
+ } catch (err) {
32
+ console.error('[yoamigo:content-hmr] Failed to hot reload content:', err)
33
+ }
34
+ })
35
+ }
36
+ `;
37
+ return { code: code + "\n" + hmrCode, map: null };
38
+ }
39
+ },
9
40
  {
10
41
  name: "yoamigo:config",
11
42
  config(config, { mode }) {
package/dist/prod.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, u as useContentStore } from './MarkdownText-BUTYfqXS.js';
1
+ export { a as ContentStore, E as ContentStoreMode, C as ContentStoreProvider, d as MarkdownText, e as MarkdownTextProps, P as PageInfo, b as StaticImage, c as StaticImageProps, M as StaticText, S as StaticTextProps, b as YaImage, c as YaImageProps, M as YaText, S as YaTextProps, u as useContentStore } from './MarkdownText-kV5IiAma.js';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
- import React from 'react';
3
+ import React__default from 'react';
4
4
  export { Link, LinkProps, NavigateFunction, Router, RouterProps, useNavigate } from './router.js';
5
5
  export { Route, Switch, useParams } from 'wouter';
6
6
  export { A as AssetResolverFn, C as ContentRegistry, c as contentRegistry, a as getAllContent, g as getContent, h as hasContent, r as registerContent, b as resolveAssetUrl, s as setAssetResolver } from './asset-resolver-BnIvDkVv.js';
@@ -10,9 +10,9 @@ interface StaticLinkProps {
10
10
  href?: string;
11
11
  className?: string;
12
12
  /** Inline styles to apply to the link element */
13
- style?: React.CSSProperties;
13
+ style?: React__default.CSSProperties;
14
14
  as?: 'a' | 'span';
15
- children?: React.ReactNode;
15
+ children?: React__default.ReactNode;
16
16
  /** Optional click handler called after navigation */
17
17
  onClick?: () => void;
18
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoamigo.com/core",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Core components, router, and utilities for YoAmigo templates",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",