@almadar/ui 5.62.0 → 5.63.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.
- package/dist/avl/index.cjs +526 -161
- package/dist/avl/index.js +526 -161
- 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 +526 -162
- package/dist/components/index.js +526 -162
- 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 +526 -161
- package/dist/providers/index.js +526 -161
- package/dist/runtime/index.cjs +526 -161
- package/dist/runtime/index.js +526 -161
- package/package.json +2 -2
|
@@ -52,6 +52,8 @@ export interface BoxProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
52
52
|
actionPayload?: EventPayload;
|
|
53
53
|
/** Declarative hover event — emits UI:{hoverEvent} with { hovered: true/false } on mouseEnter/mouseLeave */
|
|
54
54
|
hoverEvent?: EventKey;
|
|
55
|
+
/** When true (default), a touch/pen tap also fires `hoverEvent` (toggling hovered) so hover-only reveals work on touch. */
|
|
56
|
+
tapReveal?: boolean;
|
|
55
57
|
/** Maximum width (CSS value, e.g., "550px", "80rem") */
|
|
56
58
|
maxWidth?: string;
|
|
57
59
|
/** Children elements */
|
|
@@ -13,13 +13,21 @@ import type { EventEmit, EventPayload, EntityRow, EntityWith } from "@almadar/co
|
|
|
13
13
|
* 7 on laptop+ (≥1025).
|
|
14
14
|
*/
|
|
15
15
|
export type CalendarDayWindow = 1 | 3 | 7;
|
|
16
|
+
/** The per-event entity fields this grid reads. `startTime`/`endTime` are ISO
|
|
17
|
+
* strings; `color` is a Tailwind class string applied to the event chip. */
|
|
18
|
+
export interface CalendarEventRow {
|
|
19
|
+
title: string;
|
|
20
|
+
startTime: string;
|
|
21
|
+
endTime?: string;
|
|
22
|
+
color?: string;
|
|
23
|
+
}
|
|
16
24
|
export interface CalendarGridProps {
|
|
17
25
|
/** Start of the week (defaults to current week's Monday) */
|
|
18
26
|
weekStart?: Date;
|
|
19
27
|
/** Time slot labels (defaults to 09:00-17:00) */
|
|
20
28
|
timeSlots?: string[];
|
|
21
29
|
/** Events to display on the grid */
|
|
22
|
-
events?: readonly EntityWith<
|
|
30
|
+
events?: readonly EntityWith<CalendarEventRow>[];
|
|
23
31
|
/** Called when a time slot is clicked */
|
|
24
32
|
onSlotClick?: (day: Date, time: string) => void;
|
|
25
33
|
/** Called when a day header is clicked */
|
|
@@ -2,12 +2,25 @@ import React from "react";
|
|
|
2
2
|
import type { EventEmit, EntityWith } from "@almadar/core";
|
|
3
3
|
export type CanvasItemStatus = 'empty' | 'seated' | 'ordered' | 'awaiting-bill' | 'cleaning';
|
|
4
4
|
export type CanvasItemShape = 'round' | 'rectangle' | 'square';
|
|
5
|
+
/** The per-item entity fields this canvas reads. `x`/`y` are pixel coordinates
|
|
6
|
+
* in the canvas plane; `status`/`shape` are string literal unions widened to
|
|
7
|
+
* `string` at the row level. */
|
|
8
|
+
export interface CanvasItemRow {
|
|
9
|
+
label: string;
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
capacity: number;
|
|
13
|
+
partySize?: number;
|
|
14
|
+
serverName?: string;
|
|
15
|
+
status?: CanvasItemStatus;
|
|
16
|
+
shape?: CanvasItemShape;
|
|
17
|
+
}
|
|
5
18
|
export interface PositionedCanvasProps {
|
|
6
19
|
/**
|
|
7
20
|
* Items to render. The molecule narrows non-array values to `[]` and reads
|
|
8
21
|
* each row's `id` / `x` / `y` / `label` fields at render time.
|
|
9
22
|
*/
|
|
10
|
-
items: readonly EntityWith<
|
|
23
|
+
items: readonly EntityWith<CanvasItemRow>[];
|
|
11
24
|
width?: number;
|
|
12
25
|
height?: number;
|
|
13
26
|
selectedId?: string | null;
|
|
@@ -7,8 +7,20 @@
|
|
|
7
7
|
import React from "react";
|
|
8
8
|
import type { EventEmit, EntityWith } from "@almadar/core";
|
|
9
9
|
import { type VoteValue } from "./VoteStack";
|
|
10
|
+
/** The per-node entity fields this tree reads. `replies` is the same row shape
|
|
11
|
+
* nested recursively; `userVote` carries the `VoteValue` literal union. */
|
|
12
|
+
export interface ReplyNodeRow {
|
|
13
|
+
authorName: string;
|
|
14
|
+
content: string;
|
|
15
|
+
authorAvatarUrl?: string;
|
|
16
|
+
postedAt?: string;
|
|
17
|
+
voteCount?: number;
|
|
18
|
+
userVote?: VoteValue;
|
|
19
|
+
collapsed?: boolean;
|
|
20
|
+
replies?: readonly EntityWith<ReplyNodeRow>[];
|
|
21
|
+
}
|
|
10
22
|
export interface ReplyTreeProps {
|
|
11
|
-
nodes: readonly EntityWith<
|
|
23
|
+
nodes: readonly EntityWith<ReplyNodeRow>[];
|
|
12
24
|
maxDepth?: number;
|
|
13
25
|
onVote?: (nodeId: string, vote: VoteValue) => void;
|
|
14
26
|
onReply?: (parentNodeId: string) => void;
|
|
@@ -3101,6 +3101,9 @@ var GameCanvas3D = React11.forwardRef(
|
|
|
3101
3101
|
target: cameraTarget,
|
|
3102
3102
|
enableDamping: true,
|
|
3103
3103
|
dampingFactor: 0.05,
|
|
3104
|
+
enableZoom: true,
|
|
3105
|
+
enablePan: true,
|
|
3106
|
+
touches: { ONE: THREE6__namespace.TOUCH.ROTATE, TWO: THREE6__namespace.TOUCH.DOLLY_PAN },
|
|
3104
3107
|
minDistance: 2,
|
|
3105
3108
|
maxDistance: 100,
|
|
3106
3109
|
maxPolarAngle: Math.PI / 2 - 0.1
|
|
@@ -4438,6 +4441,51 @@ function GameBoard3D({
|
|
|
4438
4441
|
] });
|
|
4439
4442
|
}
|
|
4440
4443
|
GameBoard3D.displayName = "GameBoard3D";
|
|
4444
|
+
function useTapReveal(options = {}) {
|
|
4445
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
4446
|
+
const [revealed, setRevealed] = React11.useState(false);
|
|
4447
|
+
const onRevealRef = React11.useRef(onReveal);
|
|
4448
|
+
const onDismissRef = React11.useRef(onDismiss);
|
|
4449
|
+
onRevealRef.current = onReveal;
|
|
4450
|
+
onDismissRef.current = onDismiss;
|
|
4451
|
+
const reveal = React11.useCallback(() => {
|
|
4452
|
+
setRevealed((wasRevealed) => {
|
|
4453
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
4454
|
+
return true;
|
|
4455
|
+
});
|
|
4456
|
+
}, []);
|
|
4457
|
+
const dismiss = React11.useCallback(() => {
|
|
4458
|
+
setRevealed((wasRevealed) => {
|
|
4459
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
4460
|
+
return false;
|
|
4461
|
+
});
|
|
4462
|
+
}, []);
|
|
4463
|
+
const onPointerDown = React11.useCallback(
|
|
4464
|
+
(e) => {
|
|
4465
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
4466
|
+
if (revealed) dismiss();
|
|
4467
|
+
else reveal();
|
|
4468
|
+
},
|
|
4469
|
+
[enabled, revealed, reveal, dismiss]
|
|
4470
|
+
);
|
|
4471
|
+
React11.useEffect(() => {
|
|
4472
|
+
if (!revealed || typeof document === "undefined") return;
|
|
4473
|
+
const onDocDown = (ev) => {
|
|
4474
|
+
const target = ev.target;
|
|
4475
|
+
if (!(target instanceof Node)) return;
|
|
4476
|
+
const inside = (refs ?? []).some((r) => r.current?.contains(target));
|
|
4477
|
+
if (!inside) dismiss();
|
|
4478
|
+
};
|
|
4479
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
4480
|
+
return () => {
|
|
4481
|
+
clearTimeout(id);
|
|
4482
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
4483
|
+
};
|
|
4484
|
+
}, [revealed, refs, dismiss]);
|
|
4485
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
4486
|
+
}
|
|
4487
|
+
|
|
4488
|
+
// components/core/atoms/Box.tsx
|
|
4441
4489
|
var paddingStyles = {
|
|
4442
4490
|
none: "p-0",
|
|
4443
4491
|
xs: "p-1",
|
|
@@ -4563,10 +4611,12 @@ var Box = React11__default.default.forwardRef(
|
|
|
4563
4611
|
action,
|
|
4564
4612
|
actionPayload,
|
|
4565
4613
|
hoverEvent,
|
|
4614
|
+
tapReveal = true,
|
|
4566
4615
|
maxWidth,
|
|
4567
4616
|
onClick,
|
|
4568
4617
|
onMouseEnter,
|
|
4569
4618
|
onMouseLeave,
|
|
4619
|
+
onPointerDown,
|
|
4570
4620
|
...rest
|
|
4571
4621
|
}, ref) => {
|
|
4572
4622
|
const eventBus = useEventBus();
|
|
@@ -4589,6 +4639,19 @@ var Box = React11__default.default.forwardRef(
|
|
|
4589
4639
|
}
|
|
4590
4640
|
onMouseLeave?.(e);
|
|
4591
4641
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
4642
|
+
const { triggerProps } = useTapReveal({
|
|
4643
|
+
enabled: tapReveal && !!hoverEvent,
|
|
4644
|
+
onReveal: React11.useCallback(() => {
|
|
4645
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
4646
|
+
}, [hoverEvent, eventBus]),
|
|
4647
|
+
onDismiss: React11.useCallback(() => {
|
|
4648
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
4649
|
+
}, [hoverEvent, eventBus])
|
|
4650
|
+
});
|
|
4651
|
+
const handlePointerDown = React11.useCallback((e) => {
|
|
4652
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
4653
|
+
onPointerDown?.(e);
|
|
4654
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
4592
4655
|
const isClickable = action || onClick;
|
|
4593
4656
|
return React11__default.default.createElement(
|
|
4594
4657
|
Component2,
|
|
@@ -4616,6 +4679,7 @@ var Box = React11__default.default.forwardRef(
|
|
|
4616
4679
|
onClick: isClickable ? handleClick : void 0,
|
|
4617
4680
|
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
4618
4681
|
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
4682
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
4619
4683
|
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
4620
4684
|
...rest
|
|
4621
4685
|
},
|
|
@@ -3077,6 +3077,9 @@ var GameCanvas3D = forwardRef(
|
|
|
3077
3077
|
target: cameraTarget,
|
|
3078
3078
|
enableDamping: true,
|
|
3079
3079
|
dampingFactor: 0.05,
|
|
3080
|
+
enableZoom: true,
|
|
3081
|
+
enablePan: true,
|
|
3082
|
+
touches: { ONE: THREE6.TOUCH.ROTATE, TWO: THREE6.TOUCH.DOLLY_PAN },
|
|
3080
3083
|
minDistance: 2,
|
|
3081
3084
|
maxDistance: 100,
|
|
3082
3085
|
maxPolarAngle: Math.PI / 2 - 0.1
|
|
@@ -4414,6 +4417,51 @@ function GameBoard3D({
|
|
|
4414
4417
|
] });
|
|
4415
4418
|
}
|
|
4416
4419
|
GameBoard3D.displayName = "GameBoard3D";
|
|
4420
|
+
function useTapReveal(options = {}) {
|
|
4421
|
+
const { onReveal, onDismiss, refs, enabled = true } = options;
|
|
4422
|
+
const [revealed, setRevealed] = useState(false);
|
|
4423
|
+
const onRevealRef = useRef(onReveal);
|
|
4424
|
+
const onDismissRef = useRef(onDismiss);
|
|
4425
|
+
onRevealRef.current = onReveal;
|
|
4426
|
+
onDismissRef.current = onDismiss;
|
|
4427
|
+
const reveal = useCallback(() => {
|
|
4428
|
+
setRevealed((wasRevealed) => {
|
|
4429
|
+
if (!wasRevealed) onRevealRef.current?.();
|
|
4430
|
+
return true;
|
|
4431
|
+
});
|
|
4432
|
+
}, []);
|
|
4433
|
+
const dismiss = useCallback(() => {
|
|
4434
|
+
setRevealed((wasRevealed) => {
|
|
4435
|
+
if (wasRevealed) onDismissRef.current?.();
|
|
4436
|
+
return false;
|
|
4437
|
+
});
|
|
4438
|
+
}, []);
|
|
4439
|
+
const onPointerDown = useCallback(
|
|
4440
|
+
(e) => {
|
|
4441
|
+
if (!enabled || e.pointerType === "mouse") return;
|
|
4442
|
+
if (revealed) dismiss();
|
|
4443
|
+
else reveal();
|
|
4444
|
+
},
|
|
4445
|
+
[enabled, revealed, reveal, dismiss]
|
|
4446
|
+
);
|
|
4447
|
+
useEffect(() => {
|
|
4448
|
+
if (!revealed || typeof document === "undefined") return;
|
|
4449
|
+
const onDocDown = (ev) => {
|
|
4450
|
+
const target = ev.target;
|
|
4451
|
+
if (!(target instanceof Node)) return;
|
|
4452
|
+
const inside = (refs ?? []).some((r) => r.current?.contains(target));
|
|
4453
|
+
if (!inside) dismiss();
|
|
4454
|
+
};
|
|
4455
|
+
const id = setTimeout(() => document.addEventListener("pointerdown", onDocDown), 0);
|
|
4456
|
+
return () => {
|
|
4457
|
+
clearTimeout(id);
|
|
4458
|
+
document.removeEventListener("pointerdown", onDocDown);
|
|
4459
|
+
};
|
|
4460
|
+
}, [revealed, refs, dismiss]);
|
|
4461
|
+
return { revealed, triggerProps: { onPointerDown }, reveal, dismiss };
|
|
4462
|
+
}
|
|
4463
|
+
|
|
4464
|
+
// components/core/atoms/Box.tsx
|
|
4417
4465
|
var paddingStyles = {
|
|
4418
4466
|
none: "p-0",
|
|
4419
4467
|
xs: "p-1",
|
|
@@ -4539,10 +4587,12 @@ var Box = React11.forwardRef(
|
|
|
4539
4587
|
action,
|
|
4540
4588
|
actionPayload,
|
|
4541
4589
|
hoverEvent,
|
|
4590
|
+
tapReveal = true,
|
|
4542
4591
|
maxWidth,
|
|
4543
4592
|
onClick,
|
|
4544
4593
|
onMouseEnter,
|
|
4545
4594
|
onMouseLeave,
|
|
4595
|
+
onPointerDown,
|
|
4546
4596
|
...rest
|
|
4547
4597
|
}, ref) => {
|
|
4548
4598
|
const eventBus = useEventBus();
|
|
@@ -4565,6 +4615,19 @@ var Box = React11.forwardRef(
|
|
|
4565
4615
|
}
|
|
4566
4616
|
onMouseLeave?.(e);
|
|
4567
4617
|
}, [hoverEvent, eventBus, onMouseLeave]);
|
|
4618
|
+
const { triggerProps } = useTapReveal({
|
|
4619
|
+
enabled: tapReveal && !!hoverEvent,
|
|
4620
|
+
onReveal: useCallback(() => {
|
|
4621
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: true });
|
|
4622
|
+
}, [hoverEvent, eventBus]),
|
|
4623
|
+
onDismiss: useCallback(() => {
|
|
4624
|
+
if (hoverEvent) eventBus.emit(`UI:${hoverEvent}`, { hovered: false });
|
|
4625
|
+
}, [hoverEvent, eventBus])
|
|
4626
|
+
});
|
|
4627
|
+
const handlePointerDown = useCallback((e) => {
|
|
4628
|
+
if (hoverEvent && tapReveal) triggerProps.onPointerDown(e);
|
|
4629
|
+
onPointerDown?.(e);
|
|
4630
|
+
}, [hoverEvent, tapReveal, triggerProps, onPointerDown]);
|
|
4568
4631
|
const isClickable = action || onClick;
|
|
4569
4632
|
return React11.createElement(
|
|
4570
4633
|
Component2,
|
|
@@ -4592,6 +4655,7 @@ var Box = React11.forwardRef(
|
|
|
4592
4655
|
onClick: isClickable ? handleClick : void 0,
|
|
4593
4656
|
onMouseEnter: hoverEvent || onMouseEnter ? handleMouseEnter : void 0,
|
|
4594
4657
|
onMouseLeave: hoverEvent || onMouseLeave ? handleMouseLeave : void 0,
|
|
4658
|
+
onPointerDown: hoverEvent && tapReveal || onPointerDown ? handlePointerDown : void 0,
|
|
4595
4659
|
style: maxWidth ? { maxWidth, ...rest.style } : rest.style,
|
|
4596
4660
|
...rest
|
|
4597
4661
|
},
|
|
@@ -21,6 +21,22 @@ interface CameraResult {
|
|
|
21
21
|
handleMouseLeave: () => void;
|
|
22
22
|
/** Wheel handler — zoom in/out */
|
|
23
23
|
handleWheel: (e: React.WheelEvent, drawFn?: () => void) => void;
|
|
24
|
+
/** Pointer down — starts panning (mouse/touch/pen via Pointer Events). */
|
|
25
|
+
handlePointerDown: (e: React.PointerEvent) => void;
|
|
26
|
+
/** Pointer up — stops panning. */
|
|
27
|
+
handlePointerUp: () => void;
|
|
28
|
+
/** Pointer move — pans camera if dragging, returns true if panning. */
|
|
29
|
+
handlePointerMove: (e: React.PointerEvent, drawFn?: () => void) => boolean;
|
|
30
|
+
/** Apply a two-finger pan delta (screen px) directly to the camera. */
|
|
31
|
+
panBy: (dx: number, dy: number, drawFn?: () => void) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Multiplicative zoom by `factor` keeping the world point under (centerX,centerY)
|
|
34
|
+
* — screen px relative to the canvas — fixed. Used by wheel + pinch.
|
|
35
|
+
*/
|
|
36
|
+
zoomAtPoint: (factor: number, centerX: number, centerY: number, viewportSize: {
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
}, drawFn?: () => void) => void;
|
|
24
40
|
/** Convert screen coordinates to world coordinates (inverse camera transform) */
|
|
25
41
|
screenToWorld: (clientX: number, clientY: number, canvas: HTMLCanvasElement, viewportSize: {
|
|
26
42
|
width: number;
|