@jgengine/react 0.22.0 → 0.23.0
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/CHANGELOG.md +96 -0
- package/dist/accessibility.d.ts +5 -0
- package/dist/accessibility.js +9 -0
- package/dist/achievements.js +4 -3
- package/dist/actionHud.d.ts +6 -1
- package/dist/actionHud.js +37 -17
- package/dist/bars.js +5 -2
- package/dist/barsPreview.js +2 -1
- package/dist/characterSheet.js +5 -4
- package/dist/coachMarks.js +3 -2
- package/dist/codex.js +4 -3
- package/dist/components.js +9 -2
- package/dist/creditsScreen.js +2 -1
- package/dist/engineStyles.d.ts +18 -0
- package/dist/engineStyles.js +119 -0
- package/dist/fastTravel.js +4 -3
- package/dist/hud.js +7 -6
- package/dist/hudButton.d.ts +29 -0
- package/dist/hudButton.js +31 -0
- package/dist/hudChromePreview.d.ts +8 -0
- package/dist/hudChromePreview.js +27 -0
- package/dist/hudFrame.js +15 -11
- package/dist/hudInteract.d.ts +26 -0
- package/dist/hudInteract.js +28 -0
- package/dist/hudLayout.js +4 -3
- package/dist/hudPanel.d.ts +31 -0
- package/dist/hudPanel.js +32 -0
- package/dist/hudTheme.d.ts +88 -1
- package/dist/hudTheme.js +123 -8
- package/dist/hudThemePreview.js +2 -1
- package/dist/hudThemeRoot.d.ts +15 -0
- package/dist/hudThemeRoot.js +20 -0
- package/dist/hudTokens.d.ts +39 -0
- package/dist/hudTokens.js +56 -0
- package/dist/iconTreatment.js +3 -2
- package/dist/iconsPreview.js +2 -1
- package/dist/keybindingMenu.js +3 -2
- package/dist/map.js +9 -8
- package/dist/modals.d.ts +6 -3
- package/dist/modals.js +42 -52
- package/dist/notices.d.ts +27 -0
- package/dist/notices.js +145 -0
- package/dist/notifications.js +4 -3
- package/dist/panels.d.ts +9 -2
- package/dist/panels.js +78 -35
- package/dist/photoMode.js +2 -1
- package/dist/presence.d.ts +9 -0
- package/dist/presence.js +25 -0
- package/dist/previewFixtures.js +6 -0
- package/dist/questTracker.js +3 -2
- package/dist/quickMenu.js +6 -5
- package/dist/saveSlots.js +4 -3
- package/dist/selectionHud.js +4 -3
- package/dist/shopGrid.js +2 -1
- package/dist/statusEffectBar.js +2 -1
- package/dist/streetGeometryPreview.js +3 -2
- package/dist/styles.css +72 -0
- package/dist/talentTree.js +3 -2
- package/dist/tweenNumber.d.ts +37 -0
- package/dist/tweenNumber.js +66 -0
- package/dist/uiCues.d.ts +20 -0
- package/dist/uiCues.js +37 -0
- package/dist/waveHud.js +2 -1
- package/dist/waypointMarkers.js +2 -1
- package/package.json +10 -6
- package/skills/jgengine/api.md +18 -18
- package/skills/jgengine-ui/SKILL.md +4 -0
- package/skills/jgengine-ui/api.md +233 -37
- package/skills/jgengine-ui/capabilities.md +52 -0
- package/skills/jgengine-ui/reference-primitives.md +4 -4
package/dist/hudTheme.d.ts
CHANGED
|
@@ -96,6 +96,73 @@ export interface HudThemeSlot {
|
|
|
96
96
|
border: string;
|
|
97
97
|
radius: string;
|
|
98
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Type scale (any CSS length). `min` is the readability floor every engine block clamps to;
|
|
101
|
+
* `xs` is the smallest step a block uses, so it never drops below `min`.
|
|
102
|
+
*/
|
|
103
|
+
export interface HudThemeType {
|
|
104
|
+
min: string;
|
|
105
|
+
xs: string;
|
|
106
|
+
sm: string;
|
|
107
|
+
md: string;
|
|
108
|
+
lg: string;
|
|
109
|
+
xl: string;
|
|
110
|
+
xxl: string;
|
|
111
|
+
display: string;
|
|
112
|
+
/** Body line height (unitless). */
|
|
113
|
+
leading: string;
|
|
114
|
+
/** Letter spacing for uppercase labels and headers. */
|
|
115
|
+
tracking: string;
|
|
116
|
+
}
|
|
117
|
+
/** Spacing steps (any CSS length). */
|
|
118
|
+
export interface HudThemeSpace {
|
|
119
|
+
xs: string;
|
|
120
|
+
sm: string;
|
|
121
|
+
md: string;
|
|
122
|
+
lg: string;
|
|
123
|
+
xl: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Motion durations and easings. Blocks multiply durations by `--jg-motion-scale`, which the engine
|
|
127
|
+
* stylesheet sets to 0 under `prefers-reduced-motion` or `[data-reduced-motion="true"]`.
|
|
128
|
+
*/
|
|
129
|
+
export interface HudThemeMotion {
|
|
130
|
+
fast: string;
|
|
131
|
+
base: string;
|
|
132
|
+
slow: string;
|
|
133
|
+
/** Standard ease for state changes. */
|
|
134
|
+
ease: string;
|
|
135
|
+
/** Decelerating ease for entrances. */
|
|
136
|
+
easeOut: string;
|
|
137
|
+
/** Slight overshoot for pops and presses releasing. */
|
|
138
|
+
spring: string;
|
|
139
|
+
}
|
|
140
|
+
/** Layered `box-shadow` stacks by height, plus the inner top highlight a lit panel edge gets. */
|
|
141
|
+
export interface HudThemeElevation {
|
|
142
|
+
/** Resting panels and buttons. */
|
|
143
|
+
raised: string;
|
|
144
|
+
/** Hovered buttons, popovers, tooltips. */
|
|
145
|
+
overlay: string;
|
|
146
|
+
/** Windows and modal dialogs. */
|
|
147
|
+
modal: string;
|
|
148
|
+
/** Inset top-edge highlight, layered into the stacks above by blocks that want a lit rim. */
|
|
149
|
+
highlight: string;
|
|
150
|
+
}
|
|
151
|
+
/** Interactive-state tokens shared by every engine button, slot, and window. */
|
|
152
|
+
export interface HudThemeState {
|
|
153
|
+
/** Overlay color washed over a hovered control. */
|
|
154
|
+
hover: string;
|
|
155
|
+
/** Hover lift as a `translate` Y length (e.g. `"-1px"`). */
|
|
156
|
+
hoverLift: string;
|
|
157
|
+
/** Overlay color washed over a pressed control. */
|
|
158
|
+
press: string;
|
|
159
|
+
/** Pressed `scale` factor (e.g. `"0.97"`). */
|
|
160
|
+
pressScale: string;
|
|
161
|
+
/** Focus ring as a `box-shadow` value. Unset derives a two-tone ring from the accent. */
|
|
162
|
+
focusRing?: string;
|
|
163
|
+
/** Opacity of a disabled control. */
|
|
164
|
+
disabledOpacity: string;
|
|
165
|
+
}
|
|
99
166
|
/** A full HUD theme. Author one with {@link hudTheme} or {@link deriveHudTheme}. */
|
|
100
167
|
export interface HudTheme {
|
|
101
168
|
palette: HudThemePalette;
|
|
@@ -109,10 +176,25 @@ export interface HudTheme {
|
|
|
109
176
|
/** Minimap chrome ring color. */
|
|
110
177
|
ring: string;
|
|
111
178
|
skin?: HudSkin;
|
|
179
|
+
/** Type scale; unset uses {@link defaultHudTheme}'s. */
|
|
180
|
+
type?: HudThemeType;
|
|
181
|
+
/** Spacing steps; unset uses {@link defaultHudTheme}'s. */
|
|
182
|
+
space?: HudThemeSpace;
|
|
183
|
+
/** Durations and easings; unset uses {@link defaultHudTheme}'s. */
|
|
184
|
+
motion?: HudThemeMotion;
|
|
185
|
+
/** Shadow stacks; unset uses {@link defaultHudTheme}'s. */
|
|
186
|
+
elevation?: HudThemeElevation;
|
|
187
|
+
/** Hover, press, focus, and disabled tokens; unset uses {@link defaultHudTheme}'s. */
|
|
188
|
+
state?: HudThemeState;
|
|
112
189
|
}
|
|
113
190
|
/** Emits theme CSS properties, resetting inherited bar fills when absent. Spread onto a HUD ancestor. */
|
|
114
191
|
export declare function hudThemeVars(theme: HudTheme): CSSProperties;
|
|
115
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* The engine's default HUD look, applied by the shell at the HUD root of every game that does not
|
|
194
|
+
* opt out: a strong system UI font stack, layered translucent panels with a lit top rim and crisp
|
|
195
|
+
* hairline borders, a 12px type floor, and motion that honours reduced-motion. Games override any
|
|
196
|
+
* part with their own theme on a HUD ancestor.
|
|
197
|
+
*/
|
|
116
198
|
export declare const defaultHudTheme: HudTheme;
|
|
117
199
|
/** Per-group partial overrides accepted by {@link hudTheme}. */
|
|
118
200
|
export interface HudThemeOverrides {
|
|
@@ -126,6 +208,11 @@ export interface HudThemeOverrides {
|
|
|
126
208
|
slot?: Partial<HudThemeSlot>;
|
|
127
209
|
ring?: string;
|
|
128
210
|
skin?: HudSkin;
|
|
211
|
+
type?: Partial<HudThemeType>;
|
|
212
|
+
space?: Partial<HudThemeSpace>;
|
|
213
|
+
motion?: Partial<HudThemeMotion>;
|
|
214
|
+
elevation?: Partial<HudThemeElevation>;
|
|
215
|
+
state?: Partial<HudThemeState>;
|
|
129
216
|
}
|
|
130
217
|
/**
|
|
131
218
|
* Builds a full {@link HudTheme} from per-group partials, filling the rest from
|
package/dist/hudTheme.js
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
1
|
import {} from "react";
|
|
2
2
|
import { hudSkinVars } from "./hudSkin.js";
|
|
3
3
|
export { hudSkinVars } from "./hudSkin.js";
|
|
4
|
+
const DEFAULT_TYPE = {
|
|
5
|
+
min: "12px",
|
|
6
|
+
xs: "12px",
|
|
7
|
+
sm: "13px",
|
|
8
|
+
md: "14px",
|
|
9
|
+
lg: "16px",
|
|
10
|
+
xl: "20px",
|
|
11
|
+
xxl: "26px",
|
|
12
|
+
display: "34px",
|
|
13
|
+
leading: "1.4",
|
|
14
|
+
tracking: "0.08em",
|
|
15
|
+
};
|
|
16
|
+
const DEFAULT_SPACE = { xs: "4px", sm: "8px", md: "12px", lg: "16px", xl: "24px" };
|
|
17
|
+
const DEFAULT_MOTION = {
|
|
18
|
+
fast: "120ms",
|
|
19
|
+
base: "180ms",
|
|
20
|
+
slow: "320ms",
|
|
21
|
+
ease: "cubic-bezier(0.2, 0, 0, 1)",
|
|
22
|
+
easeOut: "cubic-bezier(0.16, 1, 0.3, 1)",
|
|
23
|
+
spring: "cubic-bezier(0.34, 1.56, 0.64, 1)",
|
|
24
|
+
};
|
|
25
|
+
const DEFAULT_ELEVATION = {
|
|
26
|
+
raised: "0 1px 2px rgba(0,0,0,0.45), 0 4px 12px -2px rgba(0,0,0,0.4)",
|
|
27
|
+
overlay: "0 2px 4px rgba(0,0,0,0.4), 0 10px 24px -4px rgba(0,0,0,0.5)",
|
|
28
|
+
modal: "0 4px 8px rgba(0,0,0,0.35), 0 24px 56px -12px rgba(0,0,0,0.7)",
|
|
29
|
+
highlight: "inset 0 1px 0 rgba(255,255,255,0.08)",
|
|
30
|
+
};
|
|
31
|
+
const DEFAULT_STATE = {
|
|
32
|
+
hover: "rgba(255,255,255,0.07)",
|
|
33
|
+
hoverLift: "-1px",
|
|
34
|
+
press: "rgba(0,0,0,0.14)",
|
|
35
|
+
pressScale: "0.97",
|
|
36
|
+
disabledOpacity: "0.45",
|
|
37
|
+
};
|
|
38
|
+
function focusRing(theme) {
|
|
39
|
+
return theme.state?.focusRing ?? `0 0 0 2px ${theme.surface.surfaceDeep}, 0 0 0 4px ${theme.palette.accent}`;
|
|
40
|
+
}
|
|
4
41
|
/** Emits theme CSS properties, resetting inherited bar fills when absent. Spread onto a HUD ancestor. */
|
|
5
42
|
export function hudThemeVars(theme) {
|
|
6
43
|
const { palette, surface, status, font, rarity, frame, bar, slot } = theme;
|
|
@@ -72,9 +109,73 @@ export function hudThemeVars(theme) {
|
|
|
72
109
|
"--jg-slot-border": slot.border,
|
|
73
110
|
"--jg-slot-radius": slot.radius,
|
|
74
111
|
"--jg-ring": theme.ring,
|
|
112
|
+
...typeVars(theme.type ?? DEFAULT_TYPE),
|
|
113
|
+
...spaceVars(theme.space ?? DEFAULT_SPACE),
|
|
114
|
+
...motionVars(theme.motion ?? DEFAULT_MOTION),
|
|
115
|
+
...elevationVars(theme.elevation ?? DEFAULT_ELEVATION),
|
|
116
|
+
...stateVars(theme.state ?? DEFAULT_STATE),
|
|
117
|
+
"--jg-focus-ring": focusRing(theme),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function typeVars(type) {
|
|
121
|
+
const floor = (size) => `max(${type.min}, ${size})`;
|
|
122
|
+
return {
|
|
123
|
+
"--jg-type-min": type.min,
|
|
124
|
+
"--jg-type-xs": floor(type.xs),
|
|
125
|
+
"--jg-type-sm": floor(type.sm),
|
|
126
|
+
"--jg-type-md": floor(type.md),
|
|
127
|
+
"--jg-type-lg": floor(type.lg),
|
|
128
|
+
"--jg-type-xl": floor(type.xl),
|
|
129
|
+
"--jg-type-xxl": floor(type.xxl),
|
|
130
|
+
"--jg-type-display": floor(type.display),
|
|
131
|
+
"--jg-leading": type.leading,
|
|
132
|
+
"--jg-tracking-label": type.tracking,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function spaceVars(space) {
|
|
136
|
+
return {
|
|
137
|
+
"--jg-space-xs": space.xs,
|
|
138
|
+
"--jg-space-sm": space.sm,
|
|
139
|
+
"--jg-space-md": space.md,
|
|
140
|
+
"--jg-space-lg": space.lg,
|
|
141
|
+
"--jg-space-xl": space.xl,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function motionVars(motion) {
|
|
145
|
+
return {
|
|
146
|
+
"--jg-motion-fast": motion.fast,
|
|
147
|
+
"--jg-motion-base": motion.base,
|
|
148
|
+
"--jg-motion-slow": motion.slow,
|
|
149
|
+
"--jg-ease": motion.ease,
|
|
150
|
+
"--jg-ease-out": motion.easeOut,
|
|
151
|
+
"--jg-ease-spring": motion.spring,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function elevationVars(elevation) {
|
|
155
|
+
return {
|
|
156
|
+
"--jg-elevation-raised": elevation.raised,
|
|
157
|
+
"--jg-elevation-overlay": elevation.overlay,
|
|
158
|
+
"--jg-elevation-modal": elevation.modal,
|
|
159
|
+
"--jg-highlight": elevation.highlight,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function stateVars(state) {
|
|
163
|
+
return {
|
|
164
|
+
"--jg-hover-overlay": state.hover,
|
|
165
|
+
"--jg-hover-lift": state.hoverLift,
|
|
166
|
+
"--jg-press-overlay": state.press,
|
|
167
|
+
"--jg-press-scale": state.pressScale,
|
|
168
|
+
"--jg-disabled-opacity": state.disabledOpacity,
|
|
75
169
|
};
|
|
76
170
|
}
|
|
77
|
-
|
|
171
|
+
const UI_FONT = '"Inter Variable", Inter, "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
172
|
+
const DISPLAY_FONT = '"Inter Display", "Inter Variable", Inter, "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI Variable Display", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
173
|
+
/**
|
|
174
|
+
* The engine's default HUD look, applied by the shell at the HUD root of every game that does not
|
|
175
|
+
* opt out: a strong system UI font stack, layered translucent panels with a lit top rim and crisp
|
|
176
|
+
* hairline borders, a 12px type floor, and motion that honours reduced-motion. Games override any
|
|
177
|
+
* part with their own theme on a HUD ancestor.
|
|
178
|
+
*/
|
|
78
179
|
export const defaultHudTheme = {
|
|
79
180
|
palette: {
|
|
80
181
|
health: "#e5484d",
|
|
@@ -114,9 +215,9 @@ export const defaultHudTheme = {
|
|
|
114
215
|
neutral: "#c9b458",
|
|
115
216
|
},
|
|
116
217
|
font: {
|
|
117
|
-
display:
|
|
118
|
-
numeric:
|
|
119
|
-
body:
|
|
218
|
+
display: DISPLAY_FONT,
|
|
219
|
+
numeric: UI_FONT,
|
|
220
|
+
body: UI_FONT,
|
|
120
221
|
},
|
|
121
222
|
rarity: {
|
|
122
223
|
common: "#b4b2a8",
|
|
@@ -126,10 +227,10 @@ export const defaultHudTheme = {
|
|
|
126
227
|
legendary: "#e0862e",
|
|
127
228
|
},
|
|
128
229
|
frame: {
|
|
129
|
-
bg: "linear-gradient(180deg, rgba(
|
|
130
|
-
border: "1px solid rgba(255,255,255,0.
|
|
230
|
+
bg: "linear-gradient(180deg, rgba(255,255,255,0.045), rgba(255,255,255,0) 42%), linear-gradient(180deg, rgba(22,27,36,0.9), rgba(10,13,18,0.94))",
|
|
231
|
+
border: "1px solid rgba(255,255,255,0.13)",
|
|
131
232
|
radius: "10px",
|
|
132
|
-
glow:
|
|
233
|
+
glow: `${DEFAULT_ELEVATION.highlight}, ${DEFAULT_ELEVATION.raised}`,
|
|
133
234
|
},
|
|
134
235
|
bar: {
|
|
135
236
|
track: "rgba(0,0,0,0.55)",
|
|
@@ -139,8 +240,17 @@ export const defaultHudTheme = {
|
|
|
139
240
|
bevel: "inset 0 2px 4px rgba(0,0,0,0.55), inset 0 -1px 2px rgba(255,255,255,0.08)",
|
|
140
241
|
text: "#f5f7fa",
|
|
141
242
|
},
|
|
142
|
-
slot: {
|
|
243
|
+
slot: {
|
|
244
|
+
bg: "linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0) 50%), rgba(12,15,21,0.78)",
|
|
245
|
+
border: "1px solid rgba(255,255,255,0.13)",
|
|
246
|
+
radius: "8px",
|
|
247
|
+
},
|
|
143
248
|
ring: "rgba(140,170,200,0.35)",
|
|
249
|
+
type: DEFAULT_TYPE,
|
|
250
|
+
space: DEFAULT_SPACE,
|
|
251
|
+
motion: DEFAULT_MOTION,
|
|
252
|
+
elevation: DEFAULT_ELEVATION,
|
|
253
|
+
state: DEFAULT_STATE,
|
|
144
254
|
};
|
|
145
255
|
/**
|
|
146
256
|
* Builds a full {@link HudTheme} from per-group partials, filling the rest from
|
|
@@ -161,6 +271,11 @@ export function hudTheme(overrides) {
|
|
|
161
271
|
slot: { ...defaultHudTheme.slot, ...overrides.slot },
|
|
162
272
|
ring: overrides.ring ?? defaultHudTheme.ring,
|
|
163
273
|
skin: overrides.skin,
|
|
274
|
+
type: { ...DEFAULT_TYPE, ...overrides.type },
|
|
275
|
+
space: { ...DEFAULT_SPACE, ...overrides.space },
|
|
276
|
+
motion: { ...DEFAULT_MOTION, ...overrides.motion },
|
|
277
|
+
elevation: { ...DEFAULT_ELEVATION, ...overrides.elevation },
|
|
278
|
+
state: { ...DEFAULT_STATE, ...overrides.state },
|
|
164
279
|
};
|
|
165
280
|
}
|
|
166
281
|
const theme = hudTheme;
|
package/dist/hudThemePreview.js
CHANGED
|
@@ -3,6 +3,7 @@ import {} from "react";
|
|
|
3
3
|
import { AmmoCounter, ExperienceBar, HealthBar, ManaBar, ShieldBar } from "./bars.js";
|
|
4
4
|
import { HudFrame } from "./hudFrame.js";
|
|
5
5
|
import { HUD_THEME_PRESETS, defaultHudTheme, hudThemeVars } from "./hudTheme.js";
|
|
6
|
+
import { hudType } from "./hudTokens.js";
|
|
6
7
|
/**
|
|
7
8
|
* A deterministic preset matrix for {@link HudTheme} (#1034): every genre preset × (bars + a themed
|
|
8
9
|
* frame + a slot row), rendered from static values. One `hudThemeVars(theme)` block per cell drives
|
|
@@ -19,7 +20,7 @@ function Slot({ index }) {
|
|
|
19
20
|
display: "flex",
|
|
20
21
|
alignItems: "center",
|
|
21
22
|
justifyContent: "center",
|
|
22
|
-
fontSize:
|
|
23
|
+
fontSize: hudType("xs"),
|
|
23
24
|
color: "var(--jg-bar-text, #f4f6fb)",
|
|
24
25
|
opacity: index === 0 ? 1 : 0.6,
|
|
25
26
|
}, children: index + 1 }));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type HudTheme } from "./hudTheme.js";
|
|
3
|
+
/**
|
|
4
|
+
* The HUD root the shell mounts around every `GameUI`: a layout-free (`display: contents`)
|
|
5
|
+
* `[data-jg-hud]` element carrying the theme's `--jg-*` variables, plus the engine stylesheet. Unset
|
|
6
|
+
* `theme` applies {@link defaultHudTheme}; a game's own theme on any descendant still wins by
|
|
7
|
+
* inheritance. `false` opts out of the default theme and the generic HUD control defaults; the
|
|
8
|
+
* keyframes stay so engine blocks still animate.
|
|
9
|
+
*
|
|
10
|
+
* @capability hud-theme-root apply the default (or a game) HudTheme and the engine stylesheet at the HUD root
|
|
11
|
+
*/
|
|
12
|
+
export declare function HudThemeRoot({ theme, children }: {
|
|
13
|
+
theme?: HudTheme | false;
|
|
14
|
+
children?: ReactNode;
|
|
15
|
+
}): ReactNode;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useEngineStyles } from "./engineStyles.js";
|
|
4
|
+
import { defaultHudTheme, hudThemeVars } from "./hudTheme.js";
|
|
5
|
+
/**
|
|
6
|
+
* The HUD root the shell mounts around every `GameUI`: a layout-free (`display: contents`)
|
|
7
|
+
* `[data-jg-hud]` element carrying the theme's `--jg-*` variables, plus the engine stylesheet. Unset
|
|
8
|
+
* `theme` applies {@link defaultHudTheme}; a game's own theme on any descendant still wins by
|
|
9
|
+
* inheritance. `false` opts out of the default theme and the generic HUD control defaults; the
|
|
10
|
+
* keyframes stay so engine blocks still animate.
|
|
11
|
+
*
|
|
12
|
+
* @capability hud-theme-root apply the default (or a game) HudTheme and the engine stylesheet at the HUD root
|
|
13
|
+
*/
|
|
14
|
+
export function HudThemeRoot({ theme, children }) {
|
|
15
|
+
useEngineStyles();
|
|
16
|
+
const vars = useMemo(() => (theme === false ? null : hudThemeVars(theme ?? defaultHudTheme)), [theme]);
|
|
17
|
+
if (vars === null)
|
|
18
|
+
return children;
|
|
19
|
+
return (_jsx("div", { "data-jg-hud": "", style: { display: "contents", ...vars }, children: children }));
|
|
20
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline-style accessors for the `HudTheme` scale tokens (#1034): each returns a `var(--jg-*)`
|
|
3
|
+
* reference with the default theme's value as fallback, so a block reads the active theme when one
|
|
4
|
+
* is applied and still renders the default look outside the shell.
|
|
5
|
+
*
|
|
6
|
+
* @capability hud-tokens inline-style accessors for the HudTheme type scale, spacing, motion, elevation, and focus ring
|
|
7
|
+
*/
|
|
8
|
+
/** Type-scale step. `xs` is the smallest step and never renders below the theme's 12px floor. */
|
|
9
|
+
export type HudTypeStep = "xs" | "sm" | "md" | "lg" | "xl" | "xxl" | "display";
|
|
10
|
+
/** Spacing step. */
|
|
11
|
+
export type HudSpaceStep = "xs" | "sm" | "md" | "lg" | "xl";
|
|
12
|
+
/** Motion duration step. */
|
|
13
|
+
export type HudMotionSpeed = "fast" | "base" | "slow";
|
|
14
|
+
/** Motion easing. */
|
|
15
|
+
export type HudEase = "ease" | "easeOut" | "spring";
|
|
16
|
+
/** Shadow stack height. */
|
|
17
|
+
export type HudElevation = "raised" | "overlay" | "modal";
|
|
18
|
+
/** UI sans stack used when no theme supplies `--jg-font-body`. */
|
|
19
|
+
export declare const HUD_FONT_STACK = "\"Inter Variable\", Inter, \"SF Pro Text\", -apple-system, BlinkMacSystemFont, \"Segoe UI Variable Text\", \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif";
|
|
20
|
+
/** Font-size reference for a type-scale step, e.g. `fontSize: hudType("xs")`. */
|
|
21
|
+
export declare function hudType(step: HudTypeStep): string;
|
|
22
|
+
/** Spacing reference for a step, e.g. `padding: hudSpace("sm")`. */
|
|
23
|
+
export declare function hudSpace(step: HudSpaceStep): string;
|
|
24
|
+
/** Duration reference scaled by `--jg-motion-scale` (0 under reduced motion). */
|
|
25
|
+
export declare function hudDuration(speed?: HudMotionSpeed): string;
|
|
26
|
+
/** Easing reference. */
|
|
27
|
+
export declare function hudEase(ease?: HudEase): string;
|
|
28
|
+
/** `transition` value for the given properties at one speed and easing, honouring reduced motion. */
|
|
29
|
+
export declare function hudTransition(properties: string | readonly string[], speed?: HudMotionSpeed, ease?: HudEase): string;
|
|
30
|
+
/** `box-shadow` reference for a height, with the lit top rim layered in. */
|
|
31
|
+
export declare function hudElevation(level?: HudElevation): string;
|
|
32
|
+
/** Font-family references for each theme role. */
|
|
33
|
+
export declare const hudFont: {
|
|
34
|
+
readonly body: "var(--jg-font-body, \"Inter Variable\", Inter, \"SF Pro Text\", -apple-system, BlinkMacSystemFont, \"Segoe UI Variable Text\", \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)";
|
|
35
|
+
readonly display: "var(--jg-font-display, \"Inter Variable\", Inter, \"SF Pro Text\", -apple-system, BlinkMacSystemFont, \"Segoe UI Variable Text\", \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)";
|
|
36
|
+
readonly numeric: "var(--jg-font-numeric, \"Inter Variable\", Inter, \"SF Pro Text\", -apple-system, BlinkMacSystemFont, \"Segoe UI Variable Text\", \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif)";
|
|
37
|
+
};
|
|
38
|
+
/** Focus ring `box-shadow` reference. */
|
|
39
|
+
export declare const HUD_FOCUS_RING = "var(--jg-focus-ring, 0 0 0 2px #0a0c10, 0 0 0 4px var(--jg-accent, #38bdf8))";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline-style accessors for the `HudTheme` scale tokens (#1034): each returns a `var(--jg-*)`
|
|
3
|
+
* reference with the default theme's value as fallback, so a block reads the active theme when one
|
|
4
|
+
* is applied and still renders the default look outside the shell.
|
|
5
|
+
*
|
|
6
|
+
* @capability hud-tokens inline-style accessors for the HudTheme type scale, spacing, motion, elevation, and focus ring
|
|
7
|
+
*/
|
|
8
|
+
const TYPE_PX = { xs: 12, sm: 13, md: 14, lg: 16, xl: 20, xxl: 26, display: 34 };
|
|
9
|
+
const SPACE_PX = { xs: 4, sm: 8, md: 12, lg: 16, xl: 24 };
|
|
10
|
+
const MOTION_MS = { fast: 120, base: 180, slow: 320 };
|
|
11
|
+
const EASE = {
|
|
12
|
+
ease: ["--jg-ease", "cubic-bezier(0.2, 0, 0, 1)"],
|
|
13
|
+
easeOut: ["--jg-ease-out", "cubic-bezier(0.16, 1, 0.3, 1)"],
|
|
14
|
+
spring: ["--jg-ease-spring", "cubic-bezier(0.34, 1.56, 0.64, 1)"],
|
|
15
|
+
};
|
|
16
|
+
const ELEVATION = {
|
|
17
|
+
raised: "0 1px 2px rgba(0,0,0,0.45), 0 4px 12px -2px rgba(0,0,0,0.4)",
|
|
18
|
+
overlay: "0 2px 4px rgba(0,0,0,0.4), 0 10px 24px -4px rgba(0,0,0,0.5)",
|
|
19
|
+
modal: "0 4px 8px rgba(0,0,0,0.35), 0 24px 56px -12px rgba(0,0,0,0.7)",
|
|
20
|
+
};
|
|
21
|
+
/** UI sans stack used when no theme supplies `--jg-font-body`. */
|
|
22
|
+
export const HUD_FONT_STACK = '"Inter Variable", Inter, "SF Pro Text", -apple-system, BlinkMacSystemFont, "Segoe UI Variable Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
23
|
+
/** Font-size reference for a type-scale step, e.g. `fontSize: hudType("xs")`. */
|
|
24
|
+
export function hudType(step) {
|
|
25
|
+
return `var(--jg-type-${step}, ${TYPE_PX[step]}px)`;
|
|
26
|
+
}
|
|
27
|
+
/** Spacing reference for a step, e.g. `padding: hudSpace("sm")`. */
|
|
28
|
+
export function hudSpace(step) {
|
|
29
|
+
return `var(--jg-space-${step}, ${SPACE_PX[step]}px)`;
|
|
30
|
+
}
|
|
31
|
+
/** Duration reference scaled by `--jg-motion-scale` (0 under reduced motion). */
|
|
32
|
+
export function hudDuration(speed = "fast") {
|
|
33
|
+
return `calc(var(--jg-motion-${speed}, ${MOTION_MS[speed]}ms) * var(--jg-motion-scale, 1))`;
|
|
34
|
+
}
|
|
35
|
+
/** Easing reference. */
|
|
36
|
+
export function hudEase(ease = "ease") {
|
|
37
|
+
const [name, fallback] = EASE[ease];
|
|
38
|
+
return `var(${name}, ${fallback})`;
|
|
39
|
+
}
|
|
40
|
+
/** `transition` value for the given properties at one speed and easing, honouring reduced motion. */
|
|
41
|
+
export function hudTransition(properties, speed = "fast", ease = "ease") {
|
|
42
|
+
const list = typeof properties === "string" ? [properties] : properties;
|
|
43
|
+
return list.map((property) => `${property} ${hudDuration(speed)} ${hudEase(ease)}`).join(", ");
|
|
44
|
+
}
|
|
45
|
+
/** `box-shadow` reference for a height, with the lit top rim layered in. */
|
|
46
|
+
export function hudElevation(level = "raised") {
|
|
47
|
+
return `var(--jg-highlight, inset 0 1px 0 rgba(255,255,255,0.08)), var(--jg-elevation-${level}, ${ELEVATION[level]})`;
|
|
48
|
+
}
|
|
49
|
+
/** Font-family references for each theme role. */
|
|
50
|
+
export const hudFont = {
|
|
51
|
+
body: `var(--jg-font-body, ${HUD_FONT_STACK})`,
|
|
52
|
+
display: `var(--jg-font-display, ${HUD_FONT_STACK})`,
|
|
53
|
+
numeric: `var(--jg-font-numeric, ${HUD_FONT_STACK})`,
|
|
54
|
+
};
|
|
55
|
+
/** Focus ring `box-shadow` reference. */
|
|
56
|
+
export const HUD_FOCUS_RING = "var(--jg-focus-ring, 0 0 0 2px #0a0c10, 0 0 0 4px var(--jg-accent, #38bdf8))";
|
package/dist/iconTreatment.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import {} from "react";
|
|
3
3
|
import { GameIcon, iconForAction, iconForItemId } from "./gameIcons.js";
|
|
4
|
+
import { hudType } from "./hudTokens.js";
|
|
4
5
|
const SCHOOL_GRADIENT = {
|
|
5
6
|
fire: ["#ff8a3d", "#661805"],
|
|
6
7
|
frost: ["#8fe3ff", "#0e3357"],
|
|
@@ -58,11 +59,11 @@ export function IconTreatment({ icon, glyph, school = "neutral", size = 44, coun
|
|
|
58
59
|
justifyContent: "center",
|
|
59
60
|
boxSizing: "border-box",
|
|
60
61
|
...style,
|
|
61
|
-
}, children: [_jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(180deg, rgba(255,255,255,0.3), rgba(255,255,255,0) 46%)", pointerEvents: "none" } }), _jsx("div", { style: { position: "absolute", inset: 0, borderRadius: "inherit", boxShadow: "inset 0 0 12px rgba(0,0,0,0.55)", pointerEvents: "none" } }), content, keycap !== undefined ? (_jsx("span", { style: { position: "absolute", top: 1, left: 4, fontSize:
|
|
62
|
+
}, children: [_jsx("div", { style: { position: "absolute", inset: 0, background: "linear-gradient(180deg, rgba(255,255,255,0.3), rgba(255,255,255,0) 46%)", pointerEvents: "none" } }), _jsx("div", { style: { position: "absolute", inset: 0, borderRadius: "inherit", boxShadow: "inset 0 0 12px rgba(0,0,0,0.55)", pointerEvents: "none" } }), content, keycap !== undefined ? (_jsx("span", { style: { position: "absolute", top: 1, left: 4, fontSize: hudType("xs"), fontWeight: 700, color: "#fff", opacity: 0.75, textShadow: "0 1px 2px rgba(0,0,0,0.9)" }, children: keycap })) : null, count !== undefined && count > 1 ? (_jsx("span", { "data-count": true, style: {
|
|
62
63
|
position: "absolute",
|
|
63
64
|
bottom: 1,
|
|
64
65
|
right: 3,
|
|
65
|
-
fontSize:
|
|
66
|
+
fontSize: hudType("xs"),
|
|
66
67
|
fontWeight: 800,
|
|
67
68
|
color: "#fff",
|
|
68
69
|
fontVariantNumeric: "tabular-nums",
|
package/dist/iconsPreview.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { IconTreatment } from "./iconTreatment.js";
|
|
3
|
+
import { hudType } from "./hudTokens.js";
|
|
3
4
|
/**
|
|
4
5
|
* A deterministic showcase of the painted {@link IconTreatment} (#1035): a school row (one gradient
|
|
5
6
|
* each) and a mock hotbar of treated item icons with count badges and an active slot. Static, so it
|
|
@@ -25,5 +26,5 @@ const HOTBAR = [
|
|
|
25
26
|
];
|
|
26
27
|
/** Renders the school-gradient row and a treated-icon hotbar — the deterministic #1035 fixture. */
|
|
27
28
|
export function IconsPreview({ className }) {
|
|
28
|
-
return (_jsxs("div", { "data-icons-preview": true, className: className, style: { display: "flex", flexDirection: "column", gap: 22, padding: 26, background: "#0e1216", fontFamily: "system-ui, sans-serif", color: "#e8edf2" }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize:
|
|
29
|
+
return (_jsxs("div", { "data-icons-preview": true, className: className, style: { display: "flex", flexDirection: "column", gap: 22, padding: 26, background: "#0e1216", fontFamily: "system-ui, sans-serif", color: "#e8edf2" }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: hudType("xs"), fontWeight: 700, letterSpacing: 0.6, textTransform: "uppercase", opacity: 0.6, marginBottom: 8 }, children: "school gradients" }), _jsx("div", { style: { display: "flex", gap: 10 }, children: SCHOOLS.map(([school, icon]) => (_jsx(IconTreatment, { icon: icon, school: school, size: 52 }, school))) })] }), _jsxs("div", { children: [_jsx("div", { style: { fontSize: hudType("xs"), fontWeight: 700, letterSpacing: 0.6, textTransform: "uppercase", opacity: 0.6, marginBottom: 8 }, children: "hotbar \u2014 treated icons + count badges (slot 1 active)" }), _jsx("div", { style: { display: "flex", gap: 6 }, children: HOTBAR.map((entry, index) => (_jsx(IconTreatment, { icon: entry.icon, school: entry.school, size: 50, keycap: String(index + 1), active: index === 0, ...(entry.count === undefined ? {} : { count: entry.count }) }, index))) })] })] }));
|
|
29
30
|
}
|
package/dist/keybindingMenu.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useReducer } from "react";
|
|
3
3
|
import { Keycap } from "./keyHint.js";
|
|
4
|
+
import { hudType } from "./hudTokens.js";
|
|
4
5
|
/**
|
|
5
6
|
* Subscribe to a rebind session and re-render on every change (capture, reset,
|
|
6
7
|
* arm/disarm, restore). Returns the session unchanged for convenient inline use.
|
|
@@ -98,7 +99,7 @@ function KeybindingRow({ row, armed, capturePrompt, theme, onArm, onReset, }) {
|
|
|
98
99
|
marginLeft: 8,
|
|
99
100
|
padding: "1px 7px",
|
|
100
101
|
borderRadius: 999,
|
|
101
|
-
fontSize:
|
|
102
|
+
fontSize: hudType("xs"),
|
|
102
103
|
fontWeight: 800,
|
|
103
104
|
letterSpacing: "0.06em",
|
|
104
105
|
textTransform: "uppercase",
|
|
@@ -128,7 +129,7 @@ function KeybindingRow({ row, armed, capturePrompt, theme, onArm, onReset, }) {
|
|
|
128
129
|
opacity: row.isDefault ? 0.35 : 1,
|
|
129
130
|
cursor: row.isDefault ? "default" : "pointer",
|
|
130
131
|
padding: "4px 8px",
|
|
131
|
-
fontSize:
|
|
132
|
+
fontSize: hudType("xs"),
|
|
132
133
|
}, children: "Reset" })] }));
|
|
133
134
|
}
|
|
134
135
|
function buttonStyle(color, border) {
|
package/dist/map.js
CHANGED
|
@@ -4,6 +4,7 @@ import { DEFAULT_MARKER_KINDS, markerKindStyle, } from "@jgengine/core/world/mar
|
|
|
4
4
|
import { bearingToCardinal, clampToMinimapEdge, compassBearing, headingToBearing, projectToMinimap, relativeBearing, unprojectFromMinimap, } from "@jgengine/core/world/minimap";
|
|
5
5
|
import { mapLayerColor, } from "@jgengine/core/world/mapLayers";
|
|
6
6
|
import { createFogDataUrl } from "./fogOverlay.js";
|
|
7
|
+
import { hudType } from "./hudTokens.js";
|
|
7
8
|
function routeNodes(routes, project, keyPrefix) {
|
|
8
9
|
if (routes === undefined)
|
|
9
10
|
return [];
|
|
@@ -150,7 +151,7 @@ export function Minimap({ markers, center, worldRadius, fog, size = 176, facingY
|
|
|
150
151
|
justifyContent: "space-between",
|
|
151
152
|
alignItems: "center",
|
|
152
153
|
marginBottom: 6,
|
|
153
|
-
fontSize:
|
|
154
|
+
fontSize: hudType("xs"),
|
|
154
155
|
letterSpacing: 1.4,
|
|
155
156
|
textTransform: "uppercase",
|
|
156
157
|
color: "rgba(203,213,225,0.75)",
|
|
@@ -291,7 +292,7 @@ export function Compass({ facingYaw, center, markers, width = 340, fov = (Math.P
|
|
|
291
292
|
left: x,
|
|
292
293
|
bottom: 2,
|
|
293
294
|
transform: "translateX(-50%)",
|
|
294
|
-
fontSize:
|
|
295
|
+
fontSize: hudType("xs"),
|
|
295
296
|
color: style.color,
|
|
296
297
|
fontWeight: 700,
|
|
297
298
|
}, children: style.glyph }, marker.id));
|
|
@@ -317,7 +318,7 @@ export function MinimapPanel({ zoneLabel, clock, showCompass = true, compassProp
|
|
|
317
318
|
width: minimapProps.size ?? 176,
|
|
318
319
|
color: "#e2e8f0",
|
|
319
320
|
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
320
|
-
}, children: [zoneLabel !== undefined ? (_jsx("span", { className: zoneLabelClassName, "data-minimap-chrome-zone": true, style: { fontSize: 12, fontWeight: 700 }, children: zoneLabel })) : (_jsx("span", {})), clock !== undefined ? (_jsx("span", { className: clockClassName, "data-minimap-chrome-clock": true, style: { fontSize:
|
|
321
|
+
}, children: [zoneLabel !== undefined ? (_jsx("span", { className: zoneLabelClassName, "data-minimap-chrome-zone": true, style: { fontSize: 12, fontWeight: 700 }, children: zoneLabel })) : (_jsx("span", {})), clock !== undefined ? (_jsx("span", { className: clockClassName, "data-minimap-chrome-clock": true, style: { fontSize: hudType("xs"), color: "rgba(226,232,240,0.75)" }, children: clock })) : null] })) : null, _jsx(Minimap, { ...minimapProps, children: children }), showCompass ? (_jsx("div", { className: compassClassName, "data-minimap-chrome-compass": true, style: { marginTop: 6 }, children: _jsx(Compass, { facingYaw: minimapProps.facingYaw ?? 0, center: minimapProps.center, markers: minimapProps.markers, width: minimapProps.size ?? 176, ...compassProps }) })) : null] }));
|
|
321
322
|
}
|
|
322
323
|
const TRACK_PIP_DIAMETER = {
|
|
323
324
|
dot: 6,
|
|
@@ -449,7 +450,7 @@ export function WorldMap({ markers, bounds, player, facingYaw = 0, fog, backgrou
|
|
|
449
450
|
borderRadius: 6,
|
|
450
451
|
background: "transparent",
|
|
451
452
|
color: "rgba(226,232,240,0.85)",
|
|
452
|
-
fontSize:
|
|
453
|
+
fontSize: hudType("xs"),
|
|
453
454
|
padding: "3px 9px",
|
|
454
455
|
cursor: "pointer",
|
|
455
456
|
}, children: "Close" })) : null] }), _jsx(WorldMapSurface, { markers: markers, bounds: bounds, player: player, facingYaw: facingYaw, fog: fog, background: background, width: width, height: height, kindStyles: kindStyles, routes: routes, zones: zones, cellStates: cellStates, onWorldClick: onWorldClick })] }));
|
|
@@ -605,7 +606,7 @@ export function FullscreenMap({ open = true, bounds, contentWidth = 900, minScal
|
|
|
605
606
|
justifyContent: "space-between",
|
|
606
607
|
padding: "10px 16px",
|
|
607
608
|
borderBottom: "1px solid rgba(148,163,184,0.2)",
|
|
608
|
-
}, children: [_jsx("span", { style: { fontSize: 13, fontWeight: 700, letterSpacing: 1.6, textTransform: "uppercase" }, children: title }), _jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [_jsx("button", { type: "button", "aria-label": "Zoom out", style: controlButton, onClick: () => zoomBy(1 / 1.2, contentWidth / 2, contentHeight / 2), children: "\u2212" }), _jsx("button", { type: "button", "aria-label": "Zoom in", style: controlButton, onClick: () => zoomBy(1.2, contentWidth / 2, contentHeight / 2), children: "+" }), _jsx("button", { type: "button", "aria-label": "Reset view", style: { ...controlButton, width: "auto", padding: "0 10px", fontSize:
|
|
609
|
+
}, children: [_jsx("span", { style: { fontSize: 13, fontWeight: 700, letterSpacing: 1.6, textTransform: "uppercase" }, children: title }), _jsxs("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [_jsx("button", { type: "button", "aria-label": "Zoom out", style: controlButton, onClick: () => zoomBy(1 / 1.2, contentWidth / 2, contentHeight / 2), children: "\u2212" }), _jsx("button", { type: "button", "aria-label": "Zoom in", style: controlButton, onClick: () => zoomBy(1.2, contentWidth / 2, contentHeight / 2), children: "+" }), _jsx("button", { type: "button", "aria-label": "Reset view", style: { ...controlButton, width: "auto", padding: "0 10px", fontSize: hudType("xs") }, onClick: () => setViewport(IDENTITY_VIEWPORT), children: "Reset" }), onClose !== undefined ? (_jsx("button", { type: "button", "aria-label": "Close map", style: { ...controlButton, width: "auto", padding: "0 12px", fontSize: hudType("xs") }, onClick: onClose, children: "Close" })) : null] })] }), _jsxs("div", { "data-fullscreen-map-viewport": true, "data-map-tool": tool, style: {
|
|
609
610
|
position: "relative",
|
|
610
611
|
flex: 1,
|
|
611
612
|
minHeight: 0,
|
|
@@ -680,9 +681,9 @@ export function MapLegend({ kinds, labels, kindStyles = DEFAULT_MARKER_KINDS, ti
|
|
|
680
681
|
border: "1px solid rgba(148,163,184,0.28)",
|
|
681
682
|
color: "#e2e8f0",
|
|
682
683
|
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
683
|
-
fontSize:
|
|
684
|
+
fontSize: hudType("xs"),
|
|
684
685
|
...style,
|
|
685
|
-
}, children: [title !== "" ? (_jsx("div", { style: { fontSize:
|
|
686
|
+
}, children: [title !== "" ? (_jsx("div", { style: { fontSize: hudType("xs"), letterSpacing: 1.4, textTransform: "uppercase", color: "rgba(203,213,225,0.7)", marginBottom: 5 }, children: title })) : null, _jsx("ul", { style: { listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 3 }, children: kinds.map((kind) => {
|
|
686
687
|
const kindStyle = markerKindStyle(kind, kindStyles);
|
|
687
688
|
return (_jsxs("li", { "data-legend-kind": kind, style: { display: "flex", alignItems: "center", gap: 7 }, children: [_jsx("span", { "aria-hidden": true, style: { width: 14, textAlign: "center", color: kindStyle.color, fontWeight: 700 }, children: kindStyle.glyph }), _jsx("span", { children: labels?.[kind] ?? kind })] }, kind));
|
|
688
689
|
}) })] }));
|
|
@@ -704,5 +705,5 @@ export function WaypointArrow({ relative, distance, label, formatDistance = (val
|
|
|
704
705
|
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
705
706
|
textShadow: "0 1px 2px rgba(0,0,0,0.9)",
|
|
706
707
|
...style,
|
|
707
|
-
}, children: [_jsx("svg", { width: size, height: size, viewBox: "0 0 44 44", "aria-hidden": true, "data-waypoint-arrow-needle": true, children: _jsx("g", { transform: `rotate(${(relative * 180) / Math.PI} 22 22)`, children: _jsx("path", { d: "M22 6 L32 34 L22 27 L12 34 Z", fill: color, stroke: "rgba(0,0,0,0.7)", strokeWidth: 1.2, strokeLinejoin: "round" }) }) }), label !== undefined ? (_jsx("span", { style: { fontSize:
|
|
708
|
+
}, children: [_jsx("svg", { width: size, height: size, viewBox: "0 0 44 44", "aria-hidden": true, "data-waypoint-arrow-needle": true, children: _jsx("g", { transform: `rotate(${(relative * 180) / Math.PI} 22 22)`, children: _jsx("path", { d: "M22 6 L32 34 L22 27 L12 34 Z", fill: color, stroke: "rgba(0,0,0,0.7)", strokeWidth: 1.2, strokeLinejoin: "round" }) }) }), label !== undefined ? (_jsx("span", { style: { fontSize: hudType("xs"), fontWeight: 700, letterSpacing: 0.6, textTransform: "uppercase" }, children: label })) : null, distance !== undefined ? (_jsx("span", { style: { fontSize: hudType("xs"), fontVariantNumeric: "tabular-nums", color: "rgba(226,232,240,0.9)" }, children: formatDistance(distance) })) : null] }));
|
|
708
709
|
}
|
package/dist/modals.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CSSProperties, type ReactNode } from "react";
|
|
2
2
|
import { type ModalRecord, type ModalStack } from "@jgengine/core/ui/modalStack";
|
|
3
|
+
import { type HudInteractListener } from "./hudInteract.js";
|
|
3
4
|
/**
|
|
4
5
|
* React chrome over the headless modal stack (`@jgengine/core/ui/modalStack`) — the blocking-overlay
|
|
5
6
|
* layer a game raises over its scene: a pause menu, a "quit to menu?" confirm, a reward popup.
|
|
@@ -43,6 +44,8 @@ export interface ModalHostProps {
|
|
|
43
44
|
closeOnEsc?: boolean;
|
|
44
45
|
/** z-index of the host's stacking context — sits above the HUD/windows. Default 80. */
|
|
45
46
|
zIndexBase?: number;
|
|
47
|
+
/** Called with `open` / `close` as modals show and the stack empties (`cue` is the modal kind) — the UI sound seam. */
|
|
48
|
+
onInteract?: HudInteractListener;
|
|
46
49
|
className?: string;
|
|
47
50
|
style?: CSSProperties;
|
|
48
51
|
}
|
|
@@ -64,7 +67,7 @@ export interface ModalControls {
|
|
|
64
67
|
*
|
|
65
68
|
* @capability modal-host full-screen modal/dialog host over a modal stack — dimmed backdrop, focus trap, Esc/backdrop-to-cancel, aria-modal dialog
|
|
66
69
|
*/
|
|
67
|
-
export declare function ModalHost({ stack, children, showBackdrop, backdrop, closeOnBackdrop, closeOnEsc, zIndexBase, className, style, }: ModalHostProps): ReactNode;
|
|
70
|
+
export declare function ModalHost({ stack, children, showBackdrop, backdrop, closeOnBackdrop, closeOnEsc, zIndexBase, onInteract, className, style, }: ModalHostProps): ReactNode;
|
|
68
71
|
/** Props for {@link ConfirmDialog}. */
|
|
69
72
|
export interface ConfirmDialogProps {
|
|
70
73
|
title: ReactNode;
|
|
@@ -85,7 +88,7 @@ export interface ConfirmDialogProps {
|
|
|
85
88
|
}
|
|
86
89
|
/**
|
|
87
90
|
* A generic two-button confirmation dialog — title, optional body, and Cancel / Confirm buttons over
|
|
88
|
-
* a `HudTheme`-token-driven {@link
|
|
91
|
+
* a `HudTheme`-token-driven {@link HudPanel}. Presentation-only: wire `onConfirm`/`onCancel` to a
|
|
89
92
|
* modal stack's `resolve` (typically inside a {@link ModalHost} render callback) and reskin via
|
|
90
93
|
* `HudTheme` tokens or `danger` for a destructive action. It interprets nothing — the game supplies
|
|
91
94
|
* the copy.
|
|
@@ -121,7 +124,7 @@ export interface PauseMenuProps {
|
|
|
121
124
|
}
|
|
122
125
|
/**
|
|
123
126
|
* A reskinnable pause-menu building block: a primary Resume button plus a game-filled list of slot
|
|
124
|
-
* items (Settings, Save, Quit, …), stacked in a `HudTheme`-token-driven {@link
|
|
127
|
+
* items (Settings, Save, Quit, …), stacked in a `HudTheme`-token-driven {@link HudPanel}. It ships
|
|
125
128
|
* the common shape every game's pause screen needs and nothing genre-specific — the game supplies the
|
|
126
129
|
* title, item labels/order, and destructive styling, and reskins with `HudTheme` tokens. Drop it into
|
|
127
130
|
* a {@link ModalHost} keyed on a `"pause"` modal, or render it standalone.
|