@almadar/ui 5.62.0 → 5.63.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.
- package/dist/avl/index.cjs +490 -147
- package/dist/avl/index.js +490 -147
- package/dist/components/core/atoms/Box.d.ts +2 -0
- package/dist/components/core/molecules/CalendarGrid.d.ts +9 -1
- package/dist/components/core/molecules/PositionedCanvas.d.ts +14 -1
- package/dist/components/core/molecules/ReplyTree.d.ts +13 -1
- package/dist/components/game/molecules/three/index.cjs +64 -0
- package/dist/components/game/molecules/three/index.js +64 -0
- package/dist/components/game/organisms/hooks/useCamera.d.ts +16 -0
- package/dist/components/index.cjs +490 -148
- package/dist/components/index.js +490 -148
- package/dist/components/marketing/organisms/CaseStudyOrganism.d.ts +10 -1
- package/dist/components/marketing/organisms/FeatureGridOrganism.d.ts +10 -1
- package/dist/components/marketing/organisms/HeroOrganism.d.ts +24 -1
- package/dist/components/marketing/organisms/PricingOrganism.d.ts +14 -1
- package/dist/components/marketing/organisms/ShowcaseOrganism.d.ts +14 -1
- package/dist/components/marketing/organisms/StatsOrganism.d.ts +6 -1
- package/dist/components/marketing/organisms/StepFlowOrganism.d.ts +9 -1
- package/dist/components/marketing/organisms/TeamOrganism.d.ts +10 -1
- package/dist/docs/index.cjs +64 -0
- package/dist/docs/index.d.cts +2 -0
- package/dist/docs/index.js +64 -0
- package/dist/hooks/index.cjs +148 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +147 -1
- package/dist/hooks/useCanvasGestures.d.ts +44 -0
- package/dist/hooks/useTapReveal.d.ts +32 -0
- package/dist/marketing/index.cjs +59 -0
- package/dist/marketing/index.d.cts +2 -0
- package/dist/marketing/index.js +59 -0
- package/dist/providers/index.cjs +490 -147
- package/dist/providers/index.js +490 -147
- package/dist/runtime/index.cjs +490 -147
- package/dist/runtime/index.js +490 -147
- package/package.json +2 -2
package/dist/hooks/index.js
CHANGED
|
@@ -2514,6 +2514,152 @@ function usePinchZoom(options = {}) {
|
|
|
2514
2514
|
resetZoom
|
|
2515
2515
|
};
|
|
2516
2516
|
}
|
|
2517
|
+
function localPoint(canvas, clientX, clientY) {
|
|
2518
|
+
if (!canvas) return { x: clientX, y: clientY };
|
|
2519
|
+
const rect = canvas.getBoundingClientRect();
|
|
2520
|
+
return { x: clientX - rect.left, y: clientY - rect.top };
|
|
2521
|
+
}
|
|
2522
|
+
function useCanvasGestures(options) {
|
|
2523
|
+
const {
|
|
2524
|
+
canvasRef,
|
|
2525
|
+
enabled = true,
|
|
2526
|
+
wheelStep = 1.1,
|
|
2527
|
+
onPointerDown,
|
|
2528
|
+
onPointerMove,
|
|
2529
|
+
onPointerUp,
|
|
2530
|
+
onZoom,
|
|
2531
|
+
onPanDelta,
|
|
2532
|
+
onMultiTouchStart
|
|
2533
|
+
} = options;
|
|
2534
|
+
const pointers = useRef(/* @__PURE__ */ new Map());
|
|
2535
|
+
const pinch = useRef(null);
|
|
2536
|
+
const computePinch = useCallback(() => {
|
|
2537
|
+
const pts = [...pointers.current.values()];
|
|
2538
|
+
const dx = pts[1].x - pts[0].x;
|
|
2539
|
+
const dy = pts[1].y - pts[0].y;
|
|
2540
|
+
return {
|
|
2541
|
+
distance: Math.hypot(dx, dy) || 1,
|
|
2542
|
+
centroid: { x: (pts[0].x + pts[1].x) / 2, y: (pts[0].y + pts[1].y) / 2 }
|
|
2543
|
+
};
|
|
2544
|
+
}, []);
|
|
2545
|
+
const handlePointerDown = useCallback(
|
|
2546
|
+
(e) => {
|
|
2547
|
+
if (!enabled) return;
|
|
2548
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
2549
|
+
pointers.current.set(e.pointerId, localPoint(canvasRef.current, e.clientX, e.clientY));
|
|
2550
|
+
if (pointers.current.size === 2) {
|
|
2551
|
+
onMultiTouchStart?.();
|
|
2552
|
+
pinch.current = computePinch();
|
|
2553
|
+
} else if (pointers.current.size === 1) {
|
|
2554
|
+
onPointerDown?.(e);
|
|
2555
|
+
}
|
|
2556
|
+
},
|
|
2557
|
+
[enabled, canvasRef, onMultiTouchStart, computePinch, onPointerDown]
|
|
2558
|
+
);
|
|
2559
|
+
const handlePointerMove = useCallback(
|
|
2560
|
+
(e) => {
|
|
2561
|
+
if (!enabled) return;
|
|
2562
|
+
if (pointers.current.has(e.pointerId)) {
|
|
2563
|
+
pointers.current.set(e.pointerId, localPoint(canvasRef.current, e.clientX, e.clientY));
|
|
2564
|
+
}
|
|
2565
|
+
if (pointers.current.size >= 2 && pinch.current) {
|
|
2566
|
+
const next = computePinch();
|
|
2567
|
+
const prev = pinch.current;
|
|
2568
|
+
if (next.distance !== prev.distance) {
|
|
2569
|
+
onZoom?.(next.distance / prev.distance, next.centroid.x, next.centroid.y);
|
|
2570
|
+
}
|
|
2571
|
+
onPanDelta?.(next.centroid.x - prev.centroid.x, next.centroid.y - prev.centroid.y);
|
|
2572
|
+
pinch.current = next;
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
onPointerMove?.(e);
|
|
2576
|
+
},
|
|
2577
|
+
[enabled, canvasRef, computePinch, onZoom, onPanDelta, onPointerMove]
|
|
2578
|
+
);
|
|
2579
|
+
const endPointer = useCallback(
|
|
2580
|
+
(e, fireUp) => {
|
|
2581
|
+
const wasMulti = pointers.current.size >= 2;
|
|
2582
|
+
pointers.current.delete(e.pointerId);
|
|
2583
|
+
if (pointers.current.size < 2) pinch.current = null;
|
|
2584
|
+
if (wasMulti && pointers.current.size === 1) return;
|
|
2585
|
+
if (pointers.current.size === 0 && fireUp) onPointerUp?.(e);
|
|
2586
|
+
},
|
|
2587
|
+
[onPointerUp]
|
|
2588
|
+
);
|
|
2589
|
+
const handlePointerUp = useCallback(
|
|
2590
|
+
(e) => {
|
|
2591
|
+
if (!enabled) return;
|
|
2592
|
+
endPointer(e, true);
|
|
2593
|
+
},
|
|
2594
|
+
[enabled, endPointer]
|
|
2595
|
+
);
|
|
2596
|
+
const handlePointerCancel = useCallback(
|
|
2597
|
+
(e) => {
|
|
2598
|
+
if (!enabled) return;
|
|
2599
|
+
endPointer(e, false);
|
|
2600
|
+
},
|
|
2601
|
+
[enabled, endPointer]
|
|
2602
|
+
);
|
|
2603
|
+
const handleWheel = useCallback(
|
|
2604
|
+
(e) => {
|
|
2605
|
+
if (!enabled) return;
|
|
2606
|
+
e.preventDefault();
|
|
2607
|
+
const { x, y } = localPoint(canvasRef.current, e.clientX, e.clientY);
|
|
2608
|
+
onZoom?.(e.deltaY < 0 ? wheelStep : 1 / wheelStep, x, y);
|
|
2609
|
+
},
|
|
2610
|
+
[enabled, canvasRef, wheelStep, onZoom]
|
|
2611
|
+
);
|
|
2612
|
+
return {
|
|
2613
|
+
onPointerDown: handlePointerDown,
|
|
2614
|
+
onPointerMove: handlePointerMove,
|
|
2615
|
+
onPointerUp: handlePointerUp,
|
|
2616
|
+
onPointerCancel: handlePointerCancel,
|
|
2617
|
+
onWheel: handleWheel
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
function useTapReveal(options = {}) {
|
|
2621
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2622
|
+
const [revealed, setRevealed] = useState(false);
|
|
2623
|
+
const onRevealRef = useRef(onReveal);
|
|
2624
|
+
const onDismissRef = useRef(onDismiss);
|
|
2625
|
+
onRevealRef.current = onReveal;
|
|
2626
|
+
onDismissRef.current = onDismiss;
|
|
2627
|
+
const reveal = useCallback(() => {
|
|
2628
|
+
setRevealed((wasRevealed) => {
|
|
2629
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2630
|
+
return true;
|
|
2631
|
+
});
|
|
2632
|
+
}, []);
|
|
2633
|
+
const dismiss = useCallback(() => {
|
|
2634
|
+
setRevealed((wasRevealed) => {
|
|
2635
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2636
|
+
return false;
|
|
2637
|
+
});
|
|
2638
|
+
}, []);
|
|
2639
|
+
const onPointerDown = useCallback(
|
|
2640
|
+
(e) => {
|
|
2641
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2642
|
+
if (revealed) dismiss();
|
|
2643
|
+
else reveal();
|
|
2644
|
+
},
|
|
2645
|
+
[enabled, revealed, reveal, dismiss]
|
|
2646
|
+
);
|
|
2647
|
+
useEffect(() => {
|
|
2648
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2649
|
+
const onDocDown = (ev) => {
|
|
2650
|
+
const target = ev.target;
|
|
2651
|
+
if (!(target instanceof Node)) return;
|
|
2652
|
+
const inside = (refs ?? []).some((r) => r.current?.contains(target));
|
|
2653
|
+
if (!inside) dismiss();
|
|
2654
|
+
};
|
|
2655
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2656
|
+
return () => {
|
|
2657
|
+
clearTimeout(id);
|
|
2658
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2659
|
+
};
|
|
2660
|
+
}, [revealed, refs, dismiss]);
|
|
2661
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
2662
|
+
}
|
|
2517
2663
|
var ALMADAR_DND_MIME = "application/x-almadar-dnd";
|
|
2518
2664
|
function useDraggable({ payload, disabled = false }) {
|
|
2519
2665
|
const [isDragging, setIsDragging] = useState(false);
|
|
@@ -2749,4 +2895,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
|
|
|
2749
2895
|
});
|
|
2750
2896
|
}
|
|
2751
2897
|
|
|
2752
|
-
export { ALMADAR_DND_MIME, DEFAULT_SLOTS, I18nProvider, clearEntities, createTranslate, getAllEntities, getByType, getEntity, getSingleton, parseQueryBinding, removeEntity, spawnEntity, updateEntity, updateSingleton, useAgentChat, useAuthContext, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity as useEntityById, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, usePhysics, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSingletonEntity, useSwipeGesture, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
|
|
2898
|
+
export { ALMADAR_DND_MIME, DEFAULT_SLOTS, I18nProvider, clearEntities, createTranslate, getAllEntities, getByType, getEntity, getSingleton, parseQueryBinding, removeEntity, spawnEntity, updateEntity, updateSingleton, useAgentChat, useAuthContext, useCanvasGestures, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity as useEntityById, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, usePhysics, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useRenderInterpolation, useSingletonEntity, useSwipeGesture, useTapReveal, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified pointer/touch gesture detection for canvas surfaces (graph, isometric, etc.).
|
|
3
|
+
*
|
|
4
|
+
* It owns the hard part — pointer tracking + two-finger pinch (scale factor + centroid) —
|
|
5
|
+
* and DELEGATES application to the consumer via callbacks, so each canvas applies pan/zoom
|
|
6
|
+
* in its own coordinate convention (screen-offset vs world-camera). A single pointer is
|
|
7
|
+
* passed straight through to the consumer's domain handlers (pan / node-drag / tile-select);
|
|
8
|
+
* a second pointer takes over as a pinch and cancels any in-flight single-pointer action.
|
|
9
|
+
*
|
|
10
|
+
* Pointer Events cover mouse, touch and pen, so this REPLACES mouse handlers — no dual paths.
|
|
11
|
+
*/
|
|
12
|
+
export interface CanvasGestureCallbacks {
|
|
13
|
+
/** Single-pointer down — start the consumer's pan / drag / select (domain-specific). */
|
|
14
|
+
onPointerDown?: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
15
|
+
/** Single-pointer move. */
|
|
16
|
+
onPointerMove?: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
17
|
+
/** Single-pointer up. */
|
|
18
|
+
onPointerUp?: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Multiplicative zoom around a canvas-local point. Fired by wheel and by pinch.
|
|
21
|
+
* Consumer applies `newZoom = clamp(oldZoom * factor)` keeping (centerX,centerY) fixed.
|
|
22
|
+
*/
|
|
23
|
+
onZoom?: (factor: number, centerX: number, centerY: number) => void;
|
|
24
|
+
/** Two-finger pan delta in canvas-local px (fired alongside pinch). */
|
|
25
|
+
onPanDelta?: (dx: number, dy: number) => void;
|
|
26
|
+
/** A second pointer arrived — cancel any single-pointer pan/drag the consumer started. */
|
|
27
|
+
onMultiTouchStart?: () => void;
|
|
28
|
+
}
|
|
29
|
+
export interface UseCanvasGesturesOptions extends CanvasGestureCallbacks {
|
|
30
|
+
/** The canvas being gestured on (for coordinate translation). */
|
|
31
|
+
canvasRef: React.RefObject<HTMLCanvasElement | null>;
|
|
32
|
+
/** When false, all gestures are inert. Default true. */
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
/** Wheel zoom step per notch (>1). Default 1.1. */
|
|
35
|
+
wheelStep?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface CanvasGestureHandlers {
|
|
38
|
+
onPointerDown: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
39
|
+
onPointerMove: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
40
|
+
onPointerUp: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
41
|
+
onPointerCancel: (e: React.PointerEvent<HTMLCanvasElement>) => void;
|
|
42
|
+
onWheel: (e: React.WheelEvent<HTMLCanvasElement>) => void;
|
|
43
|
+
}
|
|
44
|
+
export declare function useCanvasGestures(options: UseCanvasGesturesOptions): CanvasGestureHandlers;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hover-only reveals (tooltips, hover-popovers, submenus, `Box.hoverEvent`) have no hover on
|
|
3
|
+
* touch, so they're invisible/unreachable. This adds the tap-to-reveal fallback: on a touch/pen
|
|
4
|
+
* tap the surface reveals and fires the SAME event the hover path fires; a tap outside dismisses.
|
|
5
|
+
* Mouse is left to the component's existing hover handlers (`pointerType === 'mouse'` is ignored),
|
|
6
|
+
* so this is purely additive — no behavior change on desktop.
|
|
7
|
+
*/
|
|
8
|
+
export interface TapRevealOptions {
|
|
9
|
+
/** Fired when a tap reveals — reuse to emit the component's existing hover event. */
|
|
10
|
+
onReveal?: () => void;
|
|
11
|
+
/** Fired when an outside tap (or a second trigger tap) dismisses. */
|
|
12
|
+
onDismiss?: () => void;
|
|
13
|
+
/**
|
|
14
|
+
* Elements considered "inside" for outside-tap detection. Pass the trigger and the surface
|
|
15
|
+
* (the surface may be portaled, so it isn't a DOM descendant of the trigger). A tap whose
|
|
16
|
+
* target is inside none of these dismisses.
|
|
17
|
+
*/
|
|
18
|
+
refs?: ReadonlyArray<React.RefObject<HTMLElement | null>>;
|
|
19
|
+
/** When false, taps are ignored (hover-only). Default true. */
|
|
20
|
+
enabled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface TapRevealResult {
|
|
23
|
+
/** Whether the surface is currently revealed via a tap. OR this with the hover state. */
|
|
24
|
+
revealed: boolean;
|
|
25
|
+
/** Spread on the trigger; toggles reveal on a touch/pen tap (ignores mouse). */
|
|
26
|
+
triggerProps: {
|
|
27
|
+
onPointerDown: (e: React.PointerEvent) => void;
|
|
28
|
+
};
|
|
29
|
+
reveal: () => void;
|
|
30
|
+
dismiss: () => void;
|
|
31
|
+
}
|
|
32
|
+
export declare function useTapReveal(options?: TapRevealOptions): TapRevealResult;
|
package/dist/marketing/index.cjs
CHANGED
|
@@ -2625,6 +2625,49 @@ function useEventBus() {
|
|
|
2625
2625
|
};
|
|
2626
2626
|
}, [baseBus, scope]);
|
|
2627
2627
|
}
|
|
2628
|
+
function useTapReveal(options = {}) {
|
|
2629
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2630
|
+
const [revealed, setRevealed] = React9.useState(false);
|
|
2631
|
+
const onRevealRef = React9.useRef(onReveal);
|
|
2632
|
+
const onDismissRef = React9.useRef(onDismiss);
|
|
2633
|
+
onRevealRef.current = onReveal;
|
|
2634
|
+
onDismissRef.current = onDismiss;
|
|
2635
|
+
const reveal = React9.useCallback(() => {
|
|
2636
|
+
setRevealed((wasRevealed) => {
|
|
2637
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2638
|
+
return true;
|
|
2639
|
+
});
|
|
2640
|
+
}, []);
|
|
2641
|
+
const dismiss = React9.useCallback(() => {
|
|
2642
|
+
setRevealed((wasRevealed) => {
|
|
2643
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2644
|
+
return false;
|
|
2645
|
+
});
|
|
2646
|
+
}, []);
|
|
2647
|
+
const onPointerDown = React9.useCallback(
|
|
2648
|
+
(e) => {
|
|
2649
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2650
|
+
if (revealed) dismiss();
|
|
2651
|
+
else reveal();
|
|
2652
|
+
},
|
|
2653
|
+
[enabled, revealed, reveal, dismiss]
|
|
2654
|
+
);
|
|
2655
|
+
React9.useEffect(() => {
|
|
2656
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2657
|
+
const onDocDown = (ev) => {
|
|
2658
|
+
const target = ev.target;
|
|
2659
|
+
if (!(target instanceof Node)) return;
|
|
2660
|
+
const inside = (refs ?? []).some((r2) => r2.current?.contains(target));
|
|
2661
|
+
if (!inside) dismiss();
|
|
2662
|
+
};
|
|
2663
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2664
|
+
return () => {
|
|
2665
|
+
clearTimeout(id);
|
|
2666
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2667
|
+
};
|
|
2668
|
+
}, [revealed, refs, dismiss]);
|
|
2669
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
2670
|
+
}
|
|
2628
2671
|
|
|
2629
2672
|
// components/core/atoms/Box.tsx
|
|
2630
2673
|
var paddingStyles = {
|
|
@@ -2752,10 +2795,12 @@ var Box = React9__default.default.forwardRef(
|
|
|
2752
2795
|
action,
|
|
2753
2796
|
actionPayload,
|
|
2754
2797
|
hoverEvent,
|
|
2798
|
+
tapReveal = true,
|
|
2755
2799
|
maxWidth,
|
|
2756
2800
|
onClick,
|
|
2757
2801
|
onMouseEnter,
|
|
2758
2802
|
onMouseLeave,
|
|
2803
|
+
onPointerDown,
|
|
2759
2804
|
...rest
|
|
2760
2805
|
}, ref) => {
|
|
2761
2806
|
const eventBus = useEventBus();
|
|
@@ -2778,6 +2823,19 @@ var Box = React9__default.default.forwardRef(
|
|
|
2778
2823
|
}
|
|
2779
2824
|
onMouseLeave?.(e);
|
|
2780
2825
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
2826
|
+
const { triggerProps } = useTapReveal({
|
|
2827
|
+
enabled: tapReveal && !!hoverEvent,
|
|
2828
|
+
onReveal: React9.useCallback(() => {
|
|
2829
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2830
|
+
}, [hoverEvent, eventBus]),
|
|
2831
|
+
onDismiss: React9.useCallback(() => {
|
|
2832
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2833
|
+
}, [hoverEvent, eventBus])
|
|
2834
|
+
});
|
|
2835
|
+
const handlePointerDown = React9.useCallback((e) => {
|
|
2836
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
2837
|
+
onPointerDown?.(e);
|
|
2838
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
2781
2839
|
const isClickable = action || onClick;
|
|
2782
2840
|
return React9__default.default.createElement(
|
|
2783
2841
|
Component,
|
|
@@ -2805,6 +2863,7 @@ var Box = React9__default.default.forwardRef(
|
|
|
2805
2863
|
onClick: isClickable ? handleClick : void 0,
|
|
2806
2864
|
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
2807
2865
|
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
2866
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
2808
2867
|
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
2809
2868
|
...rest
|
|
2810
2869
|
},
|
|
@@ -55,6 +55,8 @@ interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
55
55
|
actionPayload?: EventPayload;
|
|
56
56
|
/** Declarative hover event — emits UI:{hoverEvent} with { hovered: true/false } on mouseEnter/mouseLeave */
|
|
57
57
|
hoverEvent?: EventKey;
|
|
58
|
+
/** When true (default), a touch/pen tap also fires `hoverEvent` (toggling hovered) so hover-only reveals work on touch. */
|
|
59
|
+
tapReveal?: boolean;
|
|
58
60
|
/** Maximum width (CSS value, e.g., "550px", "80rem") */
|
|
59
61
|
maxWidth?: string;
|
|
60
62
|
/** Children elements */
|
package/dist/marketing/index.js
CHANGED
|
@@ -2601,6 +2601,49 @@ function useEventBus() {
|
|
|
2601
2601
|
};
|
|
2602
2602
|
}, [baseBus, scope]);
|
|
2603
2603
|
}
|
|
2604
|
+
function useTapReveal(options = {}) {
|
|
2605
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2606
|
+
const [revealed, setRevealed] = useState(false);
|
|
2607
|
+
const onRevealRef = useRef(onReveal);
|
|
2608
|
+
const onDismissRef = useRef(onDismiss);
|
|
2609
|
+
onRevealRef.current = onReveal;
|
|
2610
|
+
onDismissRef.current = onDismiss;
|
|
2611
|
+
const reveal = useCallback(() => {
|
|
2612
|
+
setRevealed((wasRevealed) => {
|
|
2613
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2614
|
+
return true;
|
|
2615
|
+
});
|
|
2616
|
+
}, []);
|
|
2617
|
+
const dismiss = useCallback(() => {
|
|
2618
|
+
setRevealed((wasRevealed) => {
|
|
2619
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2620
|
+
return false;
|
|
2621
|
+
});
|
|
2622
|
+
}, []);
|
|
2623
|
+
const onPointerDown = useCallback(
|
|
2624
|
+
(e) => {
|
|
2625
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2626
|
+
if (revealed) dismiss();
|
|
2627
|
+
else reveal();
|
|
2628
|
+
},
|
|
2629
|
+
[enabled, revealed, reveal, dismiss]
|
|
2630
|
+
);
|
|
2631
|
+
useEffect(() => {
|
|
2632
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2633
|
+
const onDocDown = (ev) => {
|
|
2634
|
+
const target = ev.target;
|
|
2635
|
+
if (!(target instanceof Node)) return;
|
|
2636
|
+
const inside = (refs ?? []).some((r2) => r2.current?.contains(target));
|
|
2637
|
+
if (!inside) dismiss();
|
|
2638
|
+
};
|
|
2639
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2640
|
+
return () => {
|
|
2641
|
+
clearTimeout(id);
|
|
2642
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2643
|
+
};
|
|
2644
|
+
}, [revealed, refs, dismiss]);
|
|
2645
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
2646
|
+
}
|
|
2604
2647
|
|
|
2605
2648
|
// components/core/atoms/Box.tsx
|
|
2606
2649
|
var paddingStyles = {
|
|
@@ -2728,10 +2771,12 @@ var Box = React9.forwardRef(
|
|
|
2728
2771
|
action,
|
|
2729
2772
|
actionPayload,
|
|
2730
2773
|
hoverEvent,
|
|
2774
|
+
tapReveal = true,
|
|
2731
2775
|
maxWidth,
|
|
2732
2776
|
onClick,
|
|
2733
2777
|
onMouseEnter,
|
|
2734
2778
|
onMouseLeave,
|
|
2779
|
+
onPointerDown,
|
|
2735
2780
|
...rest
|
|
2736
2781
|
}, ref) => {
|
|
2737
2782
|
const eventBus = useEventBus();
|
|
@@ -2754,6 +2799,19 @@ var Box = React9.forwardRef(
|
|
|
2754
2799
|
}
|
|
2755
2800
|
onMouseLeave?.(e);
|
|
2756
2801
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
2802
|
+
const { triggerProps } = useTapReveal({
|
|
2803
|
+
enabled: tapReveal && !!hoverEvent,
|
|
2804
|
+
onReveal: useCallback(() => {
|
|
2805
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2806
|
+
}, [hoverEvent, eventBus]),
|
|
2807
|
+
onDismiss: useCallback(() => {
|
|
2808
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2809
|
+
}, [hoverEvent, eventBus])
|
|
2810
|
+
});
|
|
2811
|
+
const handlePointerDown = useCallback((e) => {
|
|
2812
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
2813
|
+
onPointerDown?.(e);
|
|
2814
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
2757
2815
|
const isClickable = action || onClick;
|
|
2758
2816
|
return React9.createElement(
|
|
2759
2817
|
Component,
|
|
@@ -2781,6 +2839,7 @@ var Box = React9.forwardRef(
|
|
|
2781
2839
|
onClick: isClickable ? handleClick : void 0,
|
|
2782
2840
|
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
2783
2841
|
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
2842
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
2784
2843
|
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
2785
2844
|
...rest
|
|
2786
2845
|
},
|