@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
|
@@ -12,8 +12,17 @@
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import type { EntityWith } from '@almadar/core';
|
|
14
14
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
15
|
+
/** The per-case-study entity fields this organism reads (FieldValue-compatible). */
|
|
16
|
+
export interface CaseStudyRow {
|
|
17
|
+
title: string;
|
|
18
|
+
description?: string;
|
|
19
|
+
category?: string;
|
|
20
|
+
categoryColor?: string;
|
|
21
|
+
href?: string;
|
|
22
|
+
linkLabel?: string;
|
|
23
|
+
}
|
|
15
24
|
export interface CaseStudyOrganismProps extends DisplayStateProps {
|
|
16
|
-
entity?: EntityWith<
|
|
25
|
+
entity?: EntityWith<CaseStudyRow> | readonly EntityWith<CaseStudyRow>[];
|
|
17
26
|
heading?: string;
|
|
18
27
|
subtitle?: string;
|
|
19
28
|
}
|
|
@@ -12,8 +12,17 @@
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import type { EntityWith } from '@almadar/core';
|
|
14
14
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
15
|
+
/** The per-feature entity fields this organism reads (FieldValue-compatible; the
|
|
16
|
+
* `icon`/`href` are string names/urls, the molecule widens `icon` to `IconInput`). */
|
|
17
|
+
export interface FeatureRow {
|
|
18
|
+
title: string;
|
|
19
|
+
icon?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
href?: string;
|
|
22
|
+
linkLabel?: string;
|
|
23
|
+
}
|
|
15
24
|
export interface FeatureGridOrganismProps extends DisplayStateProps {
|
|
16
|
-
entity?: EntityWith<
|
|
25
|
+
entity?: EntityWith<FeatureRow> | readonly EntityWith<FeatureRow>[];
|
|
17
26
|
columns?: 2 | 3 | 4 | 6;
|
|
18
27
|
heading?: string;
|
|
19
28
|
subtitle?: string;
|
|
@@ -12,8 +12,31 @@
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import type { EntityWith } from '@almadar/core';
|
|
14
14
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
15
|
+
/** A hero CTA: a plain `{ label, href }` object (FieldValue-compatible — a `type`,
|
|
16
|
+
* not `interface`, so it's assignable to the entity-row `FieldValue` index sig). */
|
|
17
|
+
export type HeroAction = {
|
|
18
|
+
label?: string;
|
|
19
|
+
href?: string;
|
|
20
|
+
};
|
|
21
|
+
/** The hero entity fields this organism reads (FieldValue-compatible; `image` is a plain
|
|
22
|
+
* `{ src, alt }` object, the action fields plain `{ label, href }` objects). */
|
|
23
|
+
export interface HeroRow {
|
|
24
|
+
title: string;
|
|
25
|
+
tag?: string;
|
|
26
|
+
titleAccent?: string;
|
|
27
|
+
subtitle?: string;
|
|
28
|
+
primaryAction?: HeroAction;
|
|
29
|
+
secondaryAction?: HeroAction;
|
|
30
|
+
installCommand?: string;
|
|
31
|
+
image?: {
|
|
32
|
+
src?: string;
|
|
33
|
+
alt?: string;
|
|
34
|
+
};
|
|
35
|
+
imagePosition?: 'below' | 'right' | 'background';
|
|
36
|
+
background?: 'dark' | 'gradient' | 'subtle';
|
|
37
|
+
}
|
|
15
38
|
export interface HeroOrganismProps extends DisplayStateProps {
|
|
16
|
-
entity?: EntityWith<
|
|
39
|
+
entity?: EntityWith<HeroRow>;
|
|
17
40
|
children?: React.ReactNode;
|
|
18
41
|
}
|
|
19
42
|
export declare const HeroOrganism: React.FC<HeroOrganismProps>;
|
|
@@ -12,8 +12,21 @@
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import type { EntityWith } from '@almadar/core';
|
|
14
14
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
15
|
+
/** The per-plan entity fields this organism reads. The organism reads FLAT
|
|
16
|
+
* `actionLabel`/`actionHref` (the molecule's PricingCardProps nests them under
|
|
17
|
+
* `action`), so this is its own shape, not PricingCardProps. */
|
|
18
|
+
export interface PricingPlanRow {
|
|
19
|
+
name: string;
|
|
20
|
+
price: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
features?: string[];
|
|
23
|
+
actionLabel?: string;
|
|
24
|
+
actionHref?: string;
|
|
25
|
+
highlighted?: boolean;
|
|
26
|
+
badge?: string;
|
|
27
|
+
}
|
|
15
28
|
export interface PricingOrganismProps extends DisplayStateProps {
|
|
16
|
-
entity?: EntityWith<
|
|
29
|
+
entity?: EntityWith<PricingPlanRow> | readonly EntityWith<PricingPlanRow>[];
|
|
17
30
|
heading?: string;
|
|
18
31
|
subtitle?: string;
|
|
19
32
|
}
|
|
@@ -12,8 +12,21 @@
|
|
|
12
12
|
import React from 'react';
|
|
13
13
|
import type { EntityWith } from '@almadar/core';
|
|
14
14
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
15
|
+
/** The per-showcase entity fields this organism reads (FieldValue-compatible; `image`
|
|
16
|
+
* is a plain `{ src, alt }` object, `accentColor` a string). */
|
|
17
|
+
export interface ShowcaseRow {
|
|
18
|
+
title: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
image?: {
|
|
21
|
+
src?: string;
|
|
22
|
+
alt?: string;
|
|
23
|
+
};
|
|
24
|
+
href?: string;
|
|
25
|
+
badge?: string;
|
|
26
|
+
accentColor?: string;
|
|
27
|
+
}
|
|
15
28
|
export interface ShowcaseOrganismProps extends DisplayStateProps {
|
|
16
|
-
entity?: EntityWith<
|
|
29
|
+
entity?: EntityWith<ShowcaseRow> | readonly EntityWith<ShowcaseRow>[];
|
|
17
30
|
columns?: 2 | 3 | 4;
|
|
18
31
|
heading?: string;
|
|
19
32
|
subtitle?: string;
|
|
@@ -11,8 +11,13 @@
|
|
|
11
11
|
import React from 'react';
|
|
12
12
|
import type { EntityWith } from '@almadar/core';
|
|
13
13
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
14
|
+
/** The per-stat entity fields this organism reads (both required). */
|
|
15
|
+
export interface StatRow {
|
|
16
|
+
value: string;
|
|
17
|
+
label: string;
|
|
18
|
+
}
|
|
14
19
|
export interface StatsOrganismProps extends DisplayStateProps {
|
|
15
|
-
entity?: EntityWith<
|
|
20
|
+
entity?: EntityWith<StatRow> | readonly EntityWith<StatRow>[];
|
|
16
21
|
columns?: 2 | 3 | 4 | 6;
|
|
17
22
|
}
|
|
18
23
|
export declare const StatsOrganism: React.FC<StatsOrganismProps>;
|
|
@@ -11,8 +11,16 @@
|
|
|
11
11
|
import React from 'react';
|
|
12
12
|
import type { EntityWith } from '@almadar/core';
|
|
13
13
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
14
|
+
/** The per-step entity fields this organism reads (FieldValue-compatible; `icon` is a
|
|
15
|
+
* string name, the molecule widens it to `IconInput`). */
|
|
16
|
+
export interface StepRow {
|
|
17
|
+
title: string;
|
|
18
|
+
number?: number;
|
|
19
|
+
description?: string;
|
|
20
|
+
icon?: string;
|
|
21
|
+
}
|
|
14
22
|
export interface StepFlowOrganismProps extends DisplayStateProps {
|
|
15
|
-
entity?: EntityWith<
|
|
23
|
+
entity?: EntityWith<StepRow> | readonly EntityWith<StepRow>[];
|
|
16
24
|
orientation?: 'horizontal' | 'vertical';
|
|
17
25
|
showConnectors?: boolean;
|
|
18
26
|
heading?: string;
|
|
@@ -11,8 +11,17 @@
|
|
|
11
11
|
import React from 'react';
|
|
12
12
|
import type { EntityWith } from '@almadar/core';
|
|
13
13
|
import type { DisplayStateProps } from '../../core/organisms/types';
|
|
14
|
+
/** The per-member entity fields this organism reads (FieldValue-compatible;
|
|
15
|
+
* `avatar` is a string url/initials). */
|
|
16
|
+
export interface TeamMemberRow {
|
|
17
|
+
name: string;
|
|
18
|
+
nameAr?: string;
|
|
19
|
+
role?: string;
|
|
20
|
+
bio?: string;
|
|
21
|
+
avatar?: string;
|
|
22
|
+
}
|
|
14
23
|
export interface TeamOrganismProps extends DisplayStateProps {
|
|
15
|
-
entity?: EntityWith<
|
|
24
|
+
entity?: EntityWith<TeamMemberRow> | readonly EntityWith<TeamMemberRow>[];
|
|
16
25
|
heading?: string;
|
|
17
26
|
subtitle?: string;
|
|
18
27
|
}
|
package/dist/docs/index.cjs
CHANGED
|
@@ -2702,12 +2702,60 @@ var init_useEventBus = __esm({
|
|
|
2702
2702
|
};
|
|
2703
2703
|
}
|
|
2704
2704
|
});
|
|
2705
|
+
function useTapReveal(options = {}) {
|
|
2706
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2707
|
+
const [revealed, setRevealed] = React8.useState(false);
|
|
2708
|
+
const onRevealRef = React8.useRef(onReveal);
|
|
2709
|
+
const onDismissRef = React8.useRef(onDismiss);
|
|
2710
|
+
onRevealRef.current = onReveal;
|
|
2711
|
+
onDismissRef.current = onDismiss;
|
|
2712
|
+
const reveal = React8.useCallback(() => {
|
|
2713
|
+
setRevealed((wasRevealed) => {
|
|
2714
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2715
|
+
return true;
|
|
2716
|
+
});
|
|
2717
|
+
}, []);
|
|
2718
|
+
const dismiss = React8.useCallback(() => {
|
|
2719
|
+
setRevealed((wasRevealed) => {
|
|
2720
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2721
|
+
return false;
|
|
2722
|
+
});
|
|
2723
|
+
}, []);
|
|
2724
|
+
const onPointerDown = React8.useCallback(
|
|
2725
|
+
(e) => {
|
|
2726
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2727
|
+
if (revealed) dismiss();
|
|
2728
|
+
else reveal();
|
|
2729
|
+
},
|
|
2730
|
+
[enabled, revealed, reveal, dismiss]
|
|
2731
|
+
);
|
|
2732
|
+
React8.useEffect(() => {
|
|
2733
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2734
|
+
const onDocDown = (ev) => {
|
|
2735
|
+
const target = ev.target;
|
|
2736
|
+
if (!(target instanceof Node)) return;
|
|
2737
|
+
const inside = (refs ?? []).some((r2) => r2.current?.contains(target));
|
|
2738
|
+
if (!inside) dismiss();
|
|
2739
|
+
};
|
|
2740
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2741
|
+
return () => {
|
|
2742
|
+
clearTimeout(id);
|
|
2743
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2744
|
+
};
|
|
2745
|
+
}, [revealed, refs, dismiss]);
|
|
2746
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
2747
|
+
}
|
|
2748
|
+
var init_useTapReveal = __esm({
|
|
2749
|
+
"hooks/useTapReveal.ts"() {
|
|
2750
|
+
}
|
|
2751
|
+
});
|
|
2705
2752
|
var paddingStyles, paddingXStyles, paddingYStyles, marginStyles, marginXStyles, marginYStyles, bgStyles, roundedStyles, shadowStyles, displayStyles, overflowStyles, positionStyles; exports.Box = void 0;
|
|
2706
2753
|
var init_Box = __esm({
|
|
2707
2754
|
"components/core/atoms/Box.tsx"() {
|
|
2708
2755
|
"use client";
|
|
2709
2756
|
init_cn();
|
|
2710
2757
|
init_useEventBus();
|
|
2758
|
+
init_useTapReveal();
|
|
2711
2759
|
paddingStyles = {
|
|
2712
2760
|
none: "p-0",
|
|
2713
2761
|
xs: "p-1",
|
|
@@ -2833,10 +2881,12 @@ var init_Box = __esm({
|
|
|
2833
2881
|
action,
|
|
2834
2882
|
actionPayload,
|
|
2835
2883
|
hoverEvent,
|
|
2884
|
+
tapReveal = true,
|
|
2836
2885
|
maxWidth,
|
|
2837
2886
|
onClick,
|
|
2838
2887
|
onMouseEnter,
|
|
2839
2888
|
onMouseLeave,
|
|
2889
|
+
onPointerDown,
|
|
2840
2890
|
...rest
|
|
2841
2891
|
}, ref) => {
|
|
2842
2892
|
const eventBus = useEventBus();
|
|
@@ -2859,6 +2909,19 @@ var init_Box = __esm({
|
|
|
2859
2909
|
}
|
|
2860
2910
|
onMouseLeave?.(e);
|
|
2861
2911
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
2912
|
+
const { triggerProps } = useTapReveal({
|
|
2913
|
+
enabled: tapReveal && !!hoverEvent,
|
|
2914
|
+
onReveal: React8.useCallback(() => {
|
|
2915
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2916
|
+
}, [hoverEvent, eventBus]),
|
|
2917
|
+
onDismiss: React8.useCallback(() => {
|
|
2918
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2919
|
+
}, [hoverEvent, eventBus])
|
|
2920
|
+
});
|
|
2921
|
+
const handlePointerDown = React8.useCallback((e) => {
|
|
2922
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
2923
|
+
onPointerDown?.(e);
|
|
2924
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
2862
2925
|
const isClickable = action || onClick;
|
|
2863
2926
|
return React8__default.default.createElement(
|
|
2864
2927
|
Component,
|
|
@@ -2886,6 +2949,7 @@ var init_Box = __esm({
|
|
|
2886
2949
|
onClick: isClickable ? handleClick : void 0,
|
|
2887
2950
|
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
2888
2951
|
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
2952
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
2889
2953
|
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
2890
2954
|
...rest
|
|
2891
2955
|
},
|
package/dist/docs/index.d.cts
CHANGED
|
@@ -56,6 +56,8 @@ interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
56
56
|
actionPayload?: EventPayload;
|
|
57
57
|
/** Declarative hover event — emits UI:{hoverEvent} with { hovered: true/false } on mouseEnter/mouseLeave */
|
|
58
58
|
hoverEvent?: EventKey;
|
|
59
|
+
/** When true (default), a touch/pen tap also fires `hoverEvent` (toggling hovered) so hover-only reveals work on touch. */
|
|
60
|
+
tapReveal?: boolean;
|
|
59
61
|
/** Maximum width (CSS value, e.g., "550px", "80rem") */
|
|
60
62
|
maxWidth?: string;
|
|
61
63
|
/** Children elements */
|
package/dist/docs/index.js
CHANGED
|
@@ -2660,12 +2660,60 @@ var init_useEventBus = __esm({
|
|
|
2660
2660
|
};
|
|
2661
2661
|
}
|
|
2662
2662
|
});
|
|
2663
|
+
function useTapReveal(options = {}) {
|
|
2664
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2665
|
+
const [revealed, setRevealed] = useState(false);
|
|
2666
|
+
const onRevealRef = useRef(onReveal);
|
|
2667
|
+
const onDismissRef = useRef(onDismiss);
|
|
2668
|
+
onRevealRef.current = onReveal;
|
|
2669
|
+
onDismissRef.current = onDismiss;
|
|
2670
|
+
const reveal = useCallback(() => {
|
|
2671
|
+
setRevealed((wasRevealed) => {
|
|
2672
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2673
|
+
return true;
|
|
2674
|
+
});
|
|
2675
|
+
}, []);
|
|
2676
|
+
const dismiss = useCallback(() => {
|
|
2677
|
+
setRevealed((wasRevealed) => {
|
|
2678
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2679
|
+
return false;
|
|
2680
|
+
});
|
|
2681
|
+
}, []);
|
|
2682
|
+
const onPointerDown = useCallback(
|
|
2683
|
+
(e) => {
|
|
2684
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2685
|
+
if (revealed) dismiss();
|
|
2686
|
+
else reveal();
|
|
2687
|
+
},
|
|
2688
|
+
[enabled, revealed, reveal, dismiss]
|
|
2689
|
+
);
|
|
2690
|
+
useEffect(() => {
|
|
2691
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2692
|
+
const onDocDown = (ev) => {
|
|
2693
|
+
const target = ev.target;
|
|
2694
|
+
if (!(target instanceof Node)) return;
|
|
2695
|
+
const inside = (refs ?? []).some((r2) => r2.current?.contains(target));
|
|
2696
|
+
if (!inside) dismiss();
|
|
2697
|
+
};
|
|
2698
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2699
|
+
return () => {
|
|
2700
|
+
clearTimeout(id);
|
|
2701
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2702
|
+
};
|
|
2703
|
+
}, [revealed, refs, dismiss]);
|
|
2704
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
2705
|
+
}
|
|
2706
|
+
var init_useTapReveal = __esm({
|
|
2707
|
+
"hooks/useTapReveal.ts"() {
|
|
2708
|
+
}
|
|
2709
|
+
});
|
|
2663
2710
|
var paddingStyles, paddingXStyles, paddingYStyles, marginStyles, marginXStyles, marginYStyles, bgStyles, roundedStyles, shadowStyles, displayStyles, overflowStyles, positionStyles, Box;
|
|
2664
2711
|
var init_Box = __esm({
|
|
2665
2712
|
"components/core/atoms/Box.tsx"() {
|
|
2666
2713
|
"use client";
|
|
2667
2714
|
init_cn();
|
|
2668
2715
|
init_useEventBus();
|
|
2716
|
+
init_useTapReveal();
|
|
2669
2717
|
paddingStyles = {
|
|
2670
2718
|
none: "p-0",
|
|
2671
2719
|
xs: "p-1",
|
|
@@ -2791,10 +2839,12 @@ var init_Box = __esm({
|
|
|
2791
2839
|
action,
|
|
2792
2840
|
actionPayload,
|
|
2793
2841
|
hoverEvent,
|
|
2842
|
+
tapReveal = true,
|
|
2794
2843
|
maxWidth,
|
|
2795
2844
|
onClick,
|
|
2796
2845
|
onMouseEnter,
|
|
2797
2846
|
onMouseLeave,
|
|
2847
|
+
onPointerDown,
|
|
2798
2848
|
...rest
|
|
2799
2849
|
}, ref) => {
|
|
2800
2850
|
const eventBus = useEventBus();
|
|
@@ -2817,6 +2867,19 @@ var init_Box = __esm({
|
|
|
2817
2867
|
}
|
|
2818
2868
|
onMouseLeave?.(e);
|
|
2819
2869
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
2870
|
+
const { triggerProps } = useTapReveal({
|
|
2871
|
+
enabled: tapReveal && !!hoverEvent,
|
|
2872
|
+
onReveal: useCallback(() => {
|
|
2873
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
2874
|
+
}, [hoverEvent, eventBus]),
|
|
2875
|
+
onDismiss: useCallback(() => {
|
|
2876
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
2877
|
+
}, [hoverEvent, eventBus])
|
|
2878
|
+
});
|
|
2879
|
+
const handlePointerDown = useCallback((e) => {
|
|
2880
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
2881
|
+
onPointerDown?.(e);
|
|
2882
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
2820
2883
|
const isClickable = action || onClick;
|
|
2821
2884
|
return React8.createElement(
|
|
2822
2885
|
Component,
|
|
@@ -2844,6 +2907,7 @@ var init_Box = __esm({
|
|
|
2844
2907
|
onClick: isClickable ? handleClick : void 0,
|
|
2845
2908
|
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
2846
2909
|
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
2910
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
2847
2911
|
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
2848
2912
|
...rest
|
|
2849
2913
|
},
|
package/dist/hooks/index.cjs
CHANGED
|
@@ -2516,6 +2516,152 @@ function usePinchZoom(options = {}) {
|
|
|
2516
2516
|
resetZoom
|
|
2517
2517
|
};
|
|
2518
2518
|
}
|
|
2519
|
+
function localPoint(canvas, clientX, clientY) {
|
|
2520
|
+
if (!canvas) return { x: clientX, y: clientY };
|
|
2521
|
+
const rect = canvas.getBoundingClientRect();
|
|
2522
|
+
return { x: clientX - rect.left, y: clientY - rect.top };
|
|
2523
|
+
}
|
|
2524
|
+
function useCanvasGestures(options) {
|
|
2525
|
+
const {
|
|
2526
|
+
canvasRef,
|
|
2527
|
+
enabled = true,
|
|
2528
|
+
wheelStep = 1.1,
|
|
2529
|
+
onPointerDown,
|
|
2530
|
+
onPointerMove,
|
|
2531
|
+
onPointerUp,
|
|
2532
|
+
onZoom,
|
|
2533
|
+
onPanDelta,
|
|
2534
|
+
onMultiTouchStart
|
|
2535
|
+
} = options;
|
|
2536
|
+
const pointers = react.useRef(/* @__PURE__ */ new Map());
|
|
2537
|
+
const pinch = react.useRef(null);
|
|
2538
|
+
const computePinch = react.useCallback(() => {
|
|
2539
|
+
const pts = [...pointers.current.values()];
|
|
2540
|
+
const dx = pts[1].x - pts[0].x;
|
|
2541
|
+
const dy = pts[1].y - pts[0].y;
|
|
2542
|
+
return {
|
|
2543
|
+
distance: Math.hypot(dx, dy) || 1,
|
|
2544
|
+
centroid: { x: (pts[0].x + pts[1].x) / 2, y: (pts[0].y + pts[1].y) / 2 }
|
|
2545
|
+
};
|
|
2546
|
+
}, []);
|
|
2547
|
+
const handlePointerDown = react.useCallback(
|
|
2548
|
+
(e) => {
|
|
2549
|
+
if (!enabled) return;
|
|
2550
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
2551
|
+
pointers.current.set(e.pointerId, localPoint(canvasRef.current, e.clientX, e.clientY));
|
|
2552
|
+
if (pointers.current.size === 2) {
|
|
2553
|
+
onMultiTouchStart?.();
|
|
2554
|
+
pinch.current = computePinch();
|
|
2555
|
+
} else if (pointers.current.size === 1) {
|
|
2556
|
+
onPointerDown?.(e);
|
|
2557
|
+
}
|
|
2558
|
+
},
|
|
2559
|
+
[enabled, canvasRef, onMultiTouchStart, computePinch, onPointerDown]
|
|
2560
|
+
);
|
|
2561
|
+
const handlePointerMove = react.useCallback(
|
|
2562
|
+
(e) => {
|
|
2563
|
+
if (!enabled) return;
|
|
2564
|
+
if (pointers.current.has(e.pointerId)) {
|
|
2565
|
+
pointers.current.set(e.pointerId, localPoint(canvasRef.current, e.clientX, e.clientY));
|
|
2566
|
+
}
|
|
2567
|
+
if (pointers.current.size >= 2 && pinch.current) {
|
|
2568
|
+
const next = computePinch();
|
|
2569
|
+
const prev = pinch.current;
|
|
2570
|
+
if (next.distance !== prev.distance) {
|
|
2571
|
+
onZoom?.(next.distance / prev.distance, next.centroid.x, next.centroid.y);
|
|
2572
|
+
}
|
|
2573
|
+
onPanDelta?.(next.centroid.x - prev.centroid.x, next.centroid.y - prev.centroid.y);
|
|
2574
|
+
pinch.current = next;
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
onPointerMove?.(e);
|
|
2578
|
+
},
|
|
2579
|
+
[enabled, canvasRef, computePinch, onZoom, onPanDelta, onPointerMove]
|
|
2580
|
+
);
|
|
2581
|
+
const endPointer = react.useCallback(
|
|
2582
|
+
(e, fireUp) => {
|
|
2583
|
+
const wasMulti = pointers.current.size >= 2;
|
|
2584
|
+
pointers.current.delete(e.pointerId);
|
|
2585
|
+
if (pointers.current.size < 2) pinch.current = null;
|
|
2586
|
+
if (wasMulti && pointers.current.size === 1) return;
|
|
2587
|
+
if (pointers.current.size === 0 && fireUp) onPointerUp?.(e);
|
|
2588
|
+
},
|
|
2589
|
+
[onPointerUp]
|
|
2590
|
+
);
|
|
2591
|
+
const handlePointerUp = react.useCallback(
|
|
2592
|
+
(e) => {
|
|
2593
|
+
if (!enabled) return;
|
|
2594
|
+
endPointer(e, true);
|
|
2595
|
+
},
|
|
2596
|
+
[enabled, endPointer]
|
|
2597
|
+
);
|
|
2598
|
+
const handlePointerCancel = react.useCallback(
|
|
2599
|
+
(e) => {
|
|
2600
|
+
if (!enabled) return;
|
|
2601
|
+
endPointer(e, false);
|
|
2602
|
+
},
|
|
2603
|
+
[enabled, endPointer]
|
|
2604
|
+
);
|
|
2605
|
+
const handleWheel = react.useCallback(
|
|
2606
|
+
(e) => {
|
|
2607
|
+
if (!enabled) return;
|
|
2608
|
+
e.preventDefault();
|
|
2609
|
+
const { x, y } = localPoint(canvasRef.current, e.clientX, e.clientY);
|
|
2610
|
+
onZoom?.(e.deltaY < 0 ? wheelStep : 1 / wheelStep, x, y);
|
|
2611
|
+
},
|
|
2612
|
+
[enabled, canvasRef, wheelStep, onZoom]
|
|
2613
|
+
);
|
|
2614
|
+
return {
|
|
2615
|
+
onPointerDown: handlePointerDown,
|
|
2616
|
+
onPointerMove: handlePointerMove,
|
|
2617
|
+
onPointerUp: handlePointerUp,
|
|
2618
|
+
onPointerCancel: handlePointerCancel,
|
|
2619
|
+
onWheel: handleWheel
|
|
2620
|
+
};
|
|
2621
|
+
}
|
|
2622
|
+
function useTapReveal(options = {}) {
|
|
2623
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
2624
|
+
const [revealed, setRevealed] = react.useState(false);
|
|
2625
|
+
const onRevealRef = react.useRef(onReveal);
|
|
2626
|
+
const onDismissRef = react.useRef(onDismiss);
|
|
2627
|
+
onRevealRef.current = onReveal;
|
|
2628
|
+
onDismissRef.current = onDismiss;
|
|
2629
|
+
const reveal = react.useCallback(() => {
|
|
2630
|
+
setRevealed((wasRevealed) => {
|
|
2631
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
2632
|
+
return true;
|
|
2633
|
+
});
|
|
2634
|
+
}, []);
|
|
2635
|
+
const dismiss = react.useCallback(() => {
|
|
2636
|
+
setRevealed((wasRevealed) => {
|
|
2637
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
2638
|
+
return false;
|
|
2639
|
+
});
|
|
2640
|
+
}, []);
|
|
2641
|
+
const onPointerDown = react.useCallback(
|
|
2642
|
+
(e) => {
|
|
2643
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
2644
|
+
if (revealed) dismiss();
|
|
2645
|
+
else reveal();
|
|
2646
|
+
},
|
|
2647
|
+
[enabled, revealed, reveal, dismiss]
|
|
2648
|
+
);
|
|
2649
|
+
react.useEffect(() => {
|
|
2650
|
+
if (!revealed || typeof document === "undefined") return;
|
|
2651
|
+
const onDocDown = (ev) => {
|
|
2652
|
+
const target = ev.target;
|
|
2653
|
+
if (!(target instanceof Node)) return;
|
|
2654
|
+
const inside = (refs ?? []).some((r) => r.current?.contains(target));
|
|
2655
|
+
if (!inside) dismiss();
|
|
2656
|
+
};
|
|
2657
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
2658
|
+
return () => {
|
|
2659
|
+
clearTimeout(id);
|
|
2660
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
2661
|
+
};
|
|
2662
|
+
}, [revealed, refs, dismiss]);
|
|
2663
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
2664
|
+
}
|
|
2519
2665
|
var ALMADAR_DND_MIME = "application/x-almadar-dnd";
|
|
2520
2666
|
function useDraggable({ payload, disabled = false }) {
|
|
2521
2667
|
const [isDragging, setIsDragging] = react.useState(false);
|
|
@@ -2767,6 +2913,7 @@ exports.updateEntity = updateEntity;
|
|
|
2767
2913
|
exports.updateSingleton = updateSingleton;
|
|
2768
2914
|
exports.useAgentChat = useAgentChat;
|
|
2769
2915
|
exports.useAuthContext = useAuthContext;
|
|
2916
|
+
exports.useCanvasGestures = useCanvasGestures;
|
|
2770
2917
|
exports.useCompile = useCompile;
|
|
2771
2918
|
exports.useConnectGitHub = useConnectGitHub;
|
|
2772
2919
|
exports.useDeepAgentGeneration = useDeepAgentGeneration;
|
|
@@ -2800,6 +2947,7 @@ exports.useQuerySingleton = useQuerySingleton;
|
|
|
2800
2947
|
exports.useRenderInterpolation = useRenderInterpolation;
|
|
2801
2948
|
exports.useSingletonEntity = useSingletonEntity;
|
|
2802
2949
|
exports.useSwipeGesture = useSwipeGesture;
|
|
2950
|
+
exports.useTapReveal = useTapReveal;
|
|
2803
2951
|
exports.useTraitListens = useTraitListens;
|
|
2804
2952
|
exports.useTranslate = useTranslate;
|
|
2805
2953
|
exports.useUIEvents = useUIEvents;
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -24,6 +24,8 @@ export { useDragReorder, type DragReorderResult, } from './useDragReorder';
|
|
|
24
24
|
export { useInfiniteScroll, type InfiniteScrollOptions, type InfiniteScrollResult, } from './useInfiniteScroll';
|
|
25
25
|
export { usePullToRefresh, type PullToRefreshOptions, type PullToRefreshResult, } from './usePullToRefresh';
|
|
26
26
|
export { usePinchZoom, type PinchZoomOptions, type PinchZoomResult, } from './usePinchZoom';
|
|
27
|
+
export { useCanvasGestures, type UseCanvasGesturesOptions, type CanvasGestureCallbacks, type CanvasGestureHandlers, } from './useCanvasGestures';
|
|
28
|
+
export { useTapReveal, type TapRevealOptions, type TapRevealResult, } from './useTapReveal';
|
|
27
29
|
export { useDraggable, ALMADAR_DND_MIME, type DraggablePayload, type UseDraggableOptions, type UseDraggableResult, } from './useDraggable';
|
|
28
30
|
export { useDropZone, type UseDropZoneOptions, type UseDropZoneResult, } from './useDropZone';
|
|
29
31
|
export { useRenderInterpolation, type Positioned, type RenderInterpolationOptions, type RenderInterpolationHandle, } from './useRenderInterpolation';
|