@almadar/ui 5.61.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.
Files changed (61) hide show
  1. package/dist/avl/index.cjs +3599 -1810
  2. package/dist/avl/index.js +2431 -642
  3. package/dist/components/core/atoms/Box.d.ts +2 -0
  4. package/dist/components/core/molecules/CalendarGrid.d.ts +9 -1
  5. package/dist/components/core/molecules/GraphCanvas.d.ts +4 -0
  6. package/dist/components/core/molecules/PositionedCanvas.d.ts +14 -1
  7. package/dist/components/core/molecules/ReplyTree.d.ts +13 -1
  8. package/dist/components/core/templates/index.d.ts +4 -0
  9. package/dist/components/game/molecules/CardHand.d.ts +35 -0
  10. package/dist/components/game/molecules/DialogueBox.d.ts +8 -2
  11. package/dist/components/game/molecules/index.d.ts +1 -0
  12. package/dist/components/game/molecules/three/index.cjs +283 -115
  13. package/dist/components/game/molecules/three/index.js +283 -115
  14. package/dist/components/game/organisms/CardBattlerBoard.d.ts +46 -0
  15. package/dist/components/game/organisms/CityBuilderBoard.d.ts +63 -0
  16. package/dist/components/game/organisms/TopDownShooterBoard.d.ts +64 -0
  17. package/dist/components/game/organisms/TowerDefenseBoard.d.ts +10 -1
  18. package/dist/components/game/organisms/TraitSlot.d.ts +1 -3
  19. package/dist/components/game/organisms/VisualNovelBoard.d.ts +53 -0
  20. package/dist/components/game/organisms/hooks/useCamera.d.ts +16 -0
  21. package/dist/components/game/organisms/index.d.ts +4 -0
  22. package/dist/components/game/templates/CardBattlerTemplate.d.ts +35 -0
  23. package/dist/components/game/templates/CityBuilderTemplate.d.ts +40 -0
  24. package/dist/components/game/templates/GameCanvas3DBattleTemplate.d.ts +5 -2
  25. package/dist/components/game/templates/GameCanvas3DCastleTemplate.d.ts +5 -2
  26. package/dist/components/game/templates/GameCanvas3DWorldMapTemplate.d.ts +5 -2
  27. package/dist/components/game/templates/TopDownShooterTemplate.d.ts +42 -0
  28. package/dist/components/game/templates/VisualNovelTemplate.d.ts +28 -0
  29. package/dist/components/game/templates/game3dAssetManifest.d.ts +50 -0
  30. package/dist/components/game/templates/index.d.ts +4 -0
  31. package/dist/components/index.cjs +3465 -1659
  32. package/dist/components/index.js +2444 -647
  33. package/dist/components/marketing/organisms/CaseStudyOrganism.d.ts +10 -1
  34. package/dist/components/marketing/organisms/FeatureGridOrganism.d.ts +10 -1
  35. package/dist/components/marketing/organisms/HeroOrganism.d.ts +24 -1
  36. package/dist/components/marketing/organisms/PricingOrganism.d.ts +14 -1
  37. package/dist/components/marketing/organisms/ShowcaseOrganism.d.ts +14 -1
  38. package/dist/components/marketing/organisms/StatsOrganism.d.ts +6 -1
  39. package/dist/components/marketing/organisms/StepFlowOrganism.d.ts +9 -1
  40. package/dist/components/marketing/organisms/TeamOrganism.d.ts +10 -1
  41. package/dist/docs/index.cjs +169 -1
  42. package/dist/docs/index.d.cts +2 -0
  43. package/dist/docs/index.js +169 -1
  44. package/dist/hooks/index.cjs +253 -1
  45. package/dist/hooks/index.d.ts +2 -0
  46. package/dist/hooks/index.js +252 -2
  47. package/dist/hooks/useCanvasGestures.d.ts +44 -0
  48. package/dist/hooks/useTapReveal.d.ts +32 -0
  49. package/dist/locales/index.cjs +315 -3
  50. package/dist/locales/index.js +315 -3
  51. package/dist/marketing/index.cjs +59 -0
  52. package/dist/marketing/index.d.cts +2 -0
  53. package/dist/marketing/index.js +59 -0
  54. package/dist/providers/index.cjs +3408 -1619
  55. package/dist/providers/index.js +2407 -618
  56. package/dist/runtime/index.cjs +3464 -1675
  57. package/dist/runtime/index.js +2411 -622
  58. package/locales/ar.json +105 -1
  59. package/locales/en.json +105 -1
  60. package/locales/sl.json +105 -1
  61. 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<'title'> | readonly EntityWith<'title'>[];
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<'title'> | readonly EntityWith<'title'>[];
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<'title'>;
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<'name' | 'price'> | readonly EntityWith<'name' | 'price'>[];
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<'title'> | readonly EntityWith<'title'>[];
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<'value' | 'label'> | readonly EntityWith<'value' | 'label'>[];
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<'title'> | readonly EntityWith<'title'>[];
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<'name'> | readonly EntityWith<'name'>[];
24
+ entity?: EntityWith<TeamMemberRow> | readonly EntityWith<TeamMemberRow>[];
16
25
  heading?: string;
17
26
  subtitle?: string;
18
27
  }
@@ -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
  },
@@ -4815,7 +4879,111 @@ var init_en = __esm({
4815
4879
  "stateMachine.legend.final": "Final",
4816
4880
  "stateMachine.legend.state": "State",
4817
4881
  "stateMachine.legend.multiEvent": "Multi-event",
4818
- "relationSelect.selectPlaceholder": "Select..."
4882
+ "relationSelect.selectPlaceholder": "Select...",
4883
+ "battle.cancel": "Cancel",
4884
+ "battle.defeat": "Defeat",
4885
+ "battle.endTurn": "End Turn",
4886
+ "battle.playAgain": "Play Again",
4887
+ "battle.turnsPlayed": "Turns Played",
4888
+ "battle.victory": "Victory",
4889
+ "builder.allPlaced": "All placed",
4890
+ "builder.blueprint": "Blueprint",
4891
+ "builder.build": "Build",
4892
+ "builder.components": "Components",
4893
+ "builder.empty": "Empty",
4894
+ "builder.reset": "Reset",
4895
+ "builder.success": "Success",
4896
+ "classifier.allCorrect": "All correct!",
4897
+ "classifier.check": "Check",
4898
+ "classifier.correct": "correct",
4899
+ "classifier.itemsToSort": "Items to sort",
4900
+ "classifier.reset": "Reset",
4901
+ "common.error": "Error",
4902
+ "debugger.allFound": "All bugs found!",
4903
+ "debugger.bugsFound": "bugs found",
4904
+ "debugger.findBugs": "Find {{count}} bugs",
4905
+ "debugger.reset": "Reset",
4906
+ "debugger.submit": "Submit",
4907
+ "error.genericLoad": "Failed to load",
4908
+ "error.loadingData": "Loading data",
4909
+ "eventHandler.addRule": "Add Rule",
4910
+ "eventHandler.chainComplete": "Chain complete!",
4911
+ "eventHandler.clickObject": "Click objects",
4912
+ "eventHandler.eventLog": "Event Log",
4913
+ "eventHandler.heardEvent": "{{object}} heard {{event}} \u2192 {{action}}",
4914
+ "eventHandler.noEvents": "No events yet",
4915
+ "eventHandler.noListeners": "No listeners for {{event}}",
4916
+ "eventHandler.rules": "{{count}}/{{max}} rules",
4917
+ "eventHandler.simulationStarted": "Simulating: {{events}}",
4918
+ "eventHandler.state": "State",
4919
+ "eventHandler.then": "then",
4920
+ "eventHandler.when": "When",
4921
+ "game.goal": "Goal",
4922
+ "game.hint": "Hint",
4923
+ "game.play": "Play",
4924
+ "game.reset": "Reset",
4925
+ "game.runTests": "Run Tests",
4926
+ "negotiator.chooseAction": "Choose an action",
4927
+ "negotiator.failed": "Negotiation failed",
4928
+ "negotiator.finalScore": "Final score",
4929
+ "negotiator.history": "History",
4930
+ "negotiator.opponent": "Opponent",
4931
+ "negotiator.playAgain": "Play Again",
4932
+ "negotiator.round": "Round {{current}} of {{total}}",
4933
+ "negotiator.success": "Negotiation successful",
4934
+ "negotiator.target": "Target",
4935
+ "negotiator.you": "You",
4936
+ "platformer.level": "Level",
4937
+ "platformer.lost": "Game Over",
4938
+ "platformer.nextLevel": "Next Level",
4939
+ "platformer.noLives": "No lives left",
4940
+ "platformer.playAgain": "Play Again",
4941
+ "platformer.score": "Score",
4942
+ "platformer.won": "You won!",
4943
+ "puzzle.tryAgainButton": "Try Again",
4944
+ "roguelike.atk": "ATK",
4945
+ "roguelike.cleared": "Dungeon cleared! Depth reached: {{depth}}",
4946
+ "roguelike.defeat": "Defeated!",
4947
+ "roguelike.depth": "Depth",
4948
+ "roguelike.enemy": "Enemy",
4949
+ "roguelike.hp": "HP",
4950
+ "roguelike.phase": "Phase",
4951
+ "roguelike.playAgain": "Play Again",
4952
+ "roguelike.player": "Hero",
4953
+ "roguelike.victory": "Victory!",
4954
+ "sequencer.actions": "Actions",
4955
+ "sequencer.dragActions": "Drag actions here",
4956
+ "sequencer.levelComplete": "Level complete!",
4957
+ "sequencer.yourSequence": "Your sequence",
4958
+ "simulator.correct": "Correct",
4959
+ "simulator.incorrect": "Incorrect",
4960
+ "simulator.parameters": "Parameters",
4961
+ "simulator.reset": "Reset",
4962
+ "simulator.simulate": "Simulate",
4963
+ "simulator.target": "Target",
4964
+ "stateArchitect.addTransition": "Add transition from {{state}}",
4965
+ "stateArchitect.addTransitionPrompt": "Click target state",
4966
+ "stateArchitect.allPassed": "All tests passed!",
4967
+ "stateArchitect.clickTarget": "Click a target state (current: {{state}})",
4968
+ "stateArchitect.gotState": "Got state: {{state}}",
4969
+ "stateArchitect.graph": "Graph",
4970
+ "stateArchitect.hideJson": "Hide JSON",
4971
+ "stateArchitect.showJson": "Show JSON",
4972
+ "stateArchitect.testResults": "Test Results",
4973
+ "stateArchitect.transitions": "{{count}} transitions",
4974
+ "stateArchitect.variables": "Variables: {{name}}",
4975
+ "stateArchitect.viewCode": "View Code",
4976
+ "td.defeat": "Defeat",
4977
+ "td.gold": "Gold",
4978
+ "td.lives": "Lives",
4979
+ "td.livesReachedZero": "Your base was overrun",
4980
+ "td.placeTower": "Place tower",
4981
+ "td.playAgain": "Play Again",
4982
+ "td.startWave": "Start Wave",
4983
+ "td.survivedAllWaves": "Survived all waves!",
4984
+ "td.victory": "Victory!",
4985
+ "td.wave": "Wave",
4986
+ "td.waveInProgress": "Wave in progress\u2026"
4819
4987
  };
4820
4988
  }
4821
4989
  });
@@ -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 */
@@ -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
  },
@@ -4773,7 +4837,111 @@ var init_en = __esm({
4773
4837
  "stateMachine.legend.final": "Final",
4774
4838
  "stateMachine.legend.state": "State",
4775
4839
  "stateMachine.legend.multiEvent": "Multi-event",
4776
- "relationSelect.selectPlaceholder": "Select..."
4840
+ "relationSelect.selectPlaceholder": "Select...",
4841
+ "battle.cancel": "Cancel",
4842
+ "battle.defeat": "Defeat",
4843
+ "battle.endTurn": "End Turn",
4844
+ "battle.playAgain": "Play Again",
4845
+ "battle.turnsPlayed": "Turns Played",
4846
+ "battle.victory": "Victory",
4847
+ "builder.allPlaced": "All placed",
4848
+ "builder.blueprint": "Blueprint",
4849
+ "builder.build": "Build",
4850
+ "builder.components": "Components",
4851
+ "builder.empty": "Empty",
4852
+ "builder.reset": "Reset",
4853
+ "builder.success": "Success",
4854
+ "classifier.allCorrect": "All correct!",
4855
+ "classifier.check": "Check",
4856
+ "classifier.correct": "correct",
4857
+ "classifier.itemsToSort": "Items to sort",
4858
+ "classifier.reset": "Reset",
4859
+ "common.error": "Error",
4860
+ "debugger.allFound": "All bugs found!",
4861
+ "debugger.bugsFound": "bugs found",
4862
+ "debugger.findBugs": "Find {{count}} bugs",
4863
+ "debugger.reset": "Reset",
4864
+ "debugger.submit": "Submit",
4865
+ "error.genericLoad": "Failed to load",
4866
+ "error.loadingData": "Loading data",
4867
+ "eventHandler.addRule": "Add Rule",
4868
+ "eventHandler.chainComplete": "Chain complete!",
4869
+ "eventHandler.clickObject": "Click objects",
4870
+ "eventHandler.eventLog": "Event Log",
4871
+ "eventHandler.heardEvent": "{{object}} heard {{event}} \u2192 {{action}}",
4872
+ "eventHandler.noEvents": "No events yet",
4873
+ "eventHandler.noListeners": "No listeners for {{event}}",
4874
+ "eventHandler.rules": "{{count}}/{{max}} rules",
4875
+ "eventHandler.simulationStarted": "Simulating: {{events}}",
4876
+ "eventHandler.state": "State",
4877
+ "eventHandler.then": "then",
4878
+ "eventHandler.when": "When",
4879
+ "game.goal": "Goal",
4880
+ "game.hint": "Hint",
4881
+ "game.play": "Play",
4882
+ "game.reset": "Reset",
4883
+ "game.runTests": "Run Tests",
4884
+ "negotiator.chooseAction": "Choose an action",
4885
+ "negotiator.failed": "Negotiation failed",
4886
+ "negotiator.finalScore": "Final score",
4887
+ "negotiator.history": "History",
4888
+ "negotiator.opponent": "Opponent",
4889
+ "negotiator.playAgain": "Play Again",
4890
+ "negotiator.round": "Round {{current}} of {{total}}",
4891
+ "negotiator.success": "Negotiation successful",
4892
+ "negotiator.target": "Target",
4893
+ "negotiator.you": "You",
4894
+ "platformer.level": "Level",
4895
+ "platformer.lost": "Game Over",
4896
+ "platformer.nextLevel": "Next Level",
4897
+ "platformer.noLives": "No lives left",
4898
+ "platformer.playAgain": "Play Again",
4899
+ "platformer.score": "Score",
4900
+ "platformer.won": "You won!",
4901
+ "puzzle.tryAgainButton": "Try Again",
4902
+ "roguelike.atk": "ATK",
4903
+ "roguelike.cleared": "Dungeon cleared! Depth reached: {{depth}}",
4904
+ "roguelike.defeat": "Defeated!",
4905
+ "roguelike.depth": "Depth",
4906
+ "roguelike.enemy": "Enemy",
4907
+ "roguelike.hp": "HP",
4908
+ "roguelike.phase": "Phase",
4909
+ "roguelike.playAgain": "Play Again",
4910
+ "roguelike.player": "Hero",
4911
+ "roguelike.victory": "Victory!",
4912
+ "sequencer.actions": "Actions",
4913
+ "sequencer.dragActions": "Drag actions here",
4914
+ "sequencer.levelComplete": "Level complete!",
4915
+ "sequencer.yourSequence": "Your sequence",
4916
+ "simulator.correct": "Correct",
4917
+ "simulator.incorrect": "Incorrect",
4918
+ "simulator.parameters": "Parameters",
4919
+ "simulator.reset": "Reset",
4920
+ "simulator.simulate": "Simulate",
4921
+ "simulator.target": "Target",
4922
+ "stateArchitect.addTransition": "Add transition from {{state}}",
4923
+ "stateArchitect.addTransitionPrompt": "Click target state",
4924
+ "stateArchitect.allPassed": "All tests passed!",
4925
+ "stateArchitect.clickTarget": "Click a target state (current: {{state}})",
4926
+ "stateArchitect.gotState": "Got state: {{state}}",
4927
+ "stateArchitect.graph": "Graph",
4928
+ "stateArchitect.hideJson": "Hide JSON",
4929
+ "stateArchitect.showJson": "Show JSON",
4930
+ "stateArchitect.testResults": "Test Results",
4931
+ "stateArchitect.transitions": "{{count}} transitions",
4932
+ "stateArchitect.variables": "Variables: {{name}}",
4933
+ "stateArchitect.viewCode": "View Code",
4934
+ "td.defeat": "Defeat",
4935
+ "td.gold": "Gold",
4936
+ "td.lives": "Lives",
4937
+ "td.livesReachedZero": "Your base was overrun",
4938
+ "td.placeTower": "Place tower",
4939
+ "td.playAgain": "Play Again",
4940
+ "td.startWave": "Start Wave",
4941
+ "td.survivedAllWaves": "Survived all waves!",
4942
+ "td.victory": "Victory!",
4943
+ "td.wave": "Wave",
4944
+ "td.waveInProgress": "Wave in progress\u2026"
4777
4945
  };
4778
4946
  }
4779
4947
  });