koin.js 1.0.0 → 1.0.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/index.js +277 -277
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +2944 -0
- package/package.json +12 -3
package/dist/index.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React5 = require('react');
|
|
4
4
|
var lucideReact = require('lucide-react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var nostalgist = require('nostalgist');
|
|
7
7
|
|
|
8
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var React5__default = /*#__PURE__*/_interopDefault(React5);
|
|
11
11
|
|
|
12
12
|
var __defProp = Object.defineProperty;
|
|
13
13
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
14
14
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
15
|
-
var ControlButton =
|
|
15
|
+
var ControlButton = React5.memo(function ControlButton2({
|
|
16
16
|
onClick,
|
|
17
17
|
onMouseDown,
|
|
18
18
|
onMouseUp,
|
|
@@ -59,7 +59,7 @@ var ControlButton = React3.memo(function ControlButton2({
|
|
|
59
59
|
});
|
|
60
60
|
var SPEED_OPTIONS = [1, 2];
|
|
61
61
|
function SpeedMenu({ speed, onSpeedChange, disabled = false }) {
|
|
62
|
-
const [showMenu, setShowMenu] =
|
|
62
|
+
const [showMenu, setShowMenu] = React5.useState(false);
|
|
63
63
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
64
64
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
65
65
|
"button",
|
|
@@ -177,7 +177,7 @@ function HardcoreTooltip({ show, message = "Disabled in Hardcore mode", children
|
|
|
177
177
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-amber-500/90 text-black text-xs rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-50", children: message })
|
|
178
178
|
] });
|
|
179
179
|
}
|
|
180
|
-
var PlaybackControls =
|
|
180
|
+
var PlaybackControls = React5.memo(function PlaybackControls2({
|
|
181
181
|
isPaused,
|
|
182
182
|
isRunning,
|
|
183
183
|
speed,
|
|
@@ -260,10 +260,10 @@ function AutoSaveIndicator({
|
|
|
260
260
|
isPaused = false,
|
|
261
261
|
onClick
|
|
262
262
|
}) {
|
|
263
|
-
const prevStateRef =
|
|
264
|
-
const [displayProgress, setDisplayProgress] =
|
|
265
|
-
const [iconOpacity, setIconOpacity] =
|
|
266
|
-
|
|
263
|
+
const prevStateRef = React5.useRef(state);
|
|
264
|
+
const [displayProgress, setDisplayProgress] = React5.useState(progress);
|
|
265
|
+
const [iconOpacity, setIconOpacity] = React5.useState(1);
|
|
266
|
+
React5.useEffect(() => {
|
|
267
267
|
const prevState = prevStateRef.current;
|
|
268
268
|
if (state === "done" && prevState === "saving") {
|
|
269
269
|
const startProgress = displayProgress;
|
|
@@ -306,7 +306,7 @@ function AutoSaveIndicator({
|
|
|
306
306
|
}
|
|
307
307
|
prevStateRef.current = state;
|
|
308
308
|
}, [state, progress]);
|
|
309
|
-
|
|
309
|
+
React5.useEffect(() => {
|
|
310
310
|
if (state !== prevStateRef.current) {
|
|
311
311
|
setIconOpacity(0);
|
|
312
312
|
const timer = setTimeout(() => {
|
|
@@ -421,7 +421,7 @@ function AutoSaveIndicator({
|
|
|
421
421
|
}
|
|
422
422
|
);
|
|
423
423
|
}
|
|
424
|
-
var SaveLoadControls =
|
|
424
|
+
var SaveLoadControls = React5.memo(function SaveLoadControls2({
|
|
425
425
|
onSave,
|
|
426
426
|
onLoad,
|
|
427
427
|
onScreenshot,
|
|
@@ -517,17 +517,17 @@ var QUICK_PRESETS = [
|
|
|
517
517
|
{ id: "crt/crt-geom", label: "CRT Geom" },
|
|
518
518
|
{ id: "handheld/lcd-grid-v2", label: "LCD Grid" }
|
|
519
519
|
];
|
|
520
|
-
var ShaderDropdown =
|
|
520
|
+
var ShaderDropdown = React5.memo(function ShaderDropdown2({
|
|
521
521
|
currentShader = "",
|
|
522
522
|
onShaderChange,
|
|
523
523
|
isRunning = false,
|
|
524
524
|
systemColor = "#00FF41",
|
|
525
525
|
disabled = false
|
|
526
526
|
}) {
|
|
527
|
-
const [isOpen, setIsOpen] =
|
|
528
|
-
const [pendingShader, setPendingShader] =
|
|
529
|
-
const dropdownRef =
|
|
530
|
-
|
|
527
|
+
const [isOpen, setIsOpen] = React5.useState(false);
|
|
528
|
+
const [pendingShader, setPendingShader] = React5.useState(null);
|
|
529
|
+
const dropdownRef = React5.useRef(null);
|
|
530
|
+
React5.useEffect(() => {
|
|
531
531
|
const handleClickOutside = (e) => {
|
|
532
532
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
533
533
|
setIsOpen(false);
|
|
@@ -671,7 +671,7 @@ function RAButton({
|
|
|
671
671
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1 bg-gray-900/95 text-white text-xs rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-50 border border-white/10", children: isIdentifying ? "Identifying game..." : isGameFound ? `${achievementCount} achievements available` : isConnected ? "Connected - Game not in RA database" : "Connect RetroAchievements" })
|
|
672
672
|
] });
|
|
673
673
|
}
|
|
674
|
-
var SettingsControls =
|
|
674
|
+
var SettingsControls = React5.memo(function SettingsControls2({
|
|
675
675
|
onFullscreen,
|
|
676
676
|
onControls,
|
|
677
677
|
onGamepadSettings,
|
|
@@ -775,12 +775,12 @@ var SettingsControls = React3.memo(function SettingsControls2({
|
|
|
775
775
|
/* @__PURE__ */ jsxRuntime.jsx(ControlButton, { onClick: onExit, icon: lucideReact.Power, label: "Exit", danger: true, disabled, systemColor })
|
|
776
776
|
] });
|
|
777
777
|
});
|
|
778
|
-
var MobileControlDrawer =
|
|
778
|
+
var MobileControlDrawer = React5.memo(function MobileControlDrawer2({
|
|
779
779
|
children,
|
|
780
780
|
systemColor = "#00FF41"
|
|
781
781
|
}) {
|
|
782
|
-
const [isExpanded, setIsExpanded] =
|
|
783
|
-
|
|
782
|
+
const [isExpanded, setIsExpanded] = React5.useState(false);
|
|
783
|
+
React5.useEffect(() => {
|
|
784
784
|
if (isExpanded) {
|
|
785
785
|
const handleInteract = (e) => {
|
|
786
786
|
const target = e.target;
|
|
@@ -866,7 +866,7 @@ var MobileControlDrawer = React3.memo(function MobileControlDrawer2({
|
|
|
866
866
|
] });
|
|
867
867
|
});
|
|
868
868
|
var MobileControlDrawer_default = MobileControlDrawer;
|
|
869
|
-
var PlayerControls =
|
|
869
|
+
var PlayerControls = React5.memo(function PlayerControls2({
|
|
870
870
|
isPaused,
|
|
871
871
|
isRunning,
|
|
872
872
|
speed,
|
|
@@ -980,7 +980,7 @@ var PlayerControls = React3.memo(function PlayerControls2({
|
|
|
980
980
|
] });
|
|
981
981
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
982
982
|
/* @__PURE__ */ jsxRuntime.jsx(MobileControlDrawer_default, { systemColor, children: controlsContent }),
|
|
983
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:flex w-full items-center justify-between gap-
|
|
983
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden sm:flex w-full items-center justify-between gap-2 px-4 py-2 bg-black/80 backdrop-blur-sm border-t border-white/10 shrink-0 overflow-x-auto", children: controlsContent })
|
|
984
984
|
] });
|
|
985
985
|
});
|
|
986
986
|
var PlayerControls_default = PlayerControls;
|
|
@@ -1028,11 +1028,11 @@ var TOAST_CONFIGS = {
|
|
|
1028
1028
|
}
|
|
1029
1029
|
};
|
|
1030
1030
|
function ToastItem({ toast, onDismiss }) {
|
|
1031
|
-
const [isVisible, setIsVisible] =
|
|
1032
|
-
const [isExiting, setIsExiting] =
|
|
1031
|
+
const [isVisible, setIsVisible] = React5.useState(false);
|
|
1032
|
+
const [isExiting, setIsExiting] = React5.useState(false);
|
|
1033
1033
|
const config = TOAST_CONFIGS[toast.type];
|
|
1034
1034
|
const IconComponent = config.icon;
|
|
1035
|
-
|
|
1035
|
+
React5.useEffect(() => {
|
|
1036
1036
|
requestAnimationFrame(() => {
|
|
1037
1037
|
setIsVisible(true);
|
|
1038
1038
|
});
|
|
@@ -1138,17 +1138,17 @@ function ToastContainer({ toasts, onDismiss }) {
|
|
|
1138
1138
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed top-4 right-4 z-[9999] flex flex-col gap-2 pointer-events-none", children: toasts.map((toast) => /* @__PURE__ */ jsxRuntime.jsx(ToastItem, { toast, onDismiss }, toast.id)) })
|
|
1139
1139
|
] });
|
|
1140
1140
|
}
|
|
1141
|
-
var PerformanceOverlay =
|
|
1141
|
+
var PerformanceOverlay = React5.memo(function PerformanceOverlay2({
|
|
1142
1142
|
isVisible,
|
|
1143
1143
|
coreName = "Unknown",
|
|
1144
1144
|
systemColor = "#00FF41"
|
|
1145
1145
|
}) {
|
|
1146
|
-
const [fps, setFps] =
|
|
1147
|
-
const [frameTime, setFrameTime] =
|
|
1148
|
-
const frameTimesRef =
|
|
1149
|
-
const lastTimeRef =
|
|
1150
|
-
const rafIdRef =
|
|
1151
|
-
|
|
1146
|
+
const [fps, setFps] = React5.useState(0);
|
|
1147
|
+
const [frameTime, setFrameTime] = React5.useState(0);
|
|
1148
|
+
const frameTimesRef = React5.useRef([]);
|
|
1149
|
+
const lastTimeRef = React5.useRef(performance.now());
|
|
1150
|
+
const rafIdRef = React5.useRef(null);
|
|
1151
|
+
React5.useEffect(() => {
|
|
1152
1152
|
if (!isVisible) {
|
|
1153
1153
|
if (rafIdRef.current) {
|
|
1154
1154
|
cancelAnimationFrame(rafIdRef.current);
|
|
@@ -1254,14 +1254,14 @@ var KEY_TO_BUTTON = {
|
|
|
1254
1254
|
"ShiftRight": "SELECT",
|
|
1255
1255
|
"Space": "COIN"
|
|
1256
1256
|
};
|
|
1257
|
-
var InputDisplay =
|
|
1257
|
+
var InputDisplay = React5.memo(function InputDisplay2({
|
|
1258
1258
|
isVisible,
|
|
1259
1259
|
system,
|
|
1260
1260
|
systemColor = "#00FF41",
|
|
1261
1261
|
position = "bottom-right"
|
|
1262
1262
|
}) {
|
|
1263
|
-
const [activeKeys, setActiveKeys] =
|
|
1264
|
-
|
|
1263
|
+
const [activeKeys, setActiveKeys] = React5.useState(/* @__PURE__ */ new Set());
|
|
1264
|
+
React5.useEffect(() => {
|
|
1265
1265
|
if (!isVisible) return;
|
|
1266
1266
|
const handleKeyDown = (e) => {
|
|
1267
1267
|
const button = KEY_TO_BUTTON[e.code];
|
|
@@ -1335,7 +1335,7 @@ var InputDisplay = React3.memo(function InputDisplay2({
|
|
|
1335
1335
|
}
|
|
1336
1336
|
);
|
|
1337
1337
|
});
|
|
1338
|
-
var DpadButton =
|
|
1338
|
+
var DpadButton = React5.memo(function DpadButton2({
|
|
1339
1339
|
active,
|
|
1340
1340
|
color,
|
|
1341
1341
|
children
|
|
@@ -1353,7 +1353,7 @@ var DpadButton = React3.memo(function DpadButton2({
|
|
|
1353
1353
|
}
|
|
1354
1354
|
);
|
|
1355
1355
|
});
|
|
1356
|
-
var ActionButton =
|
|
1356
|
+
var ActionButton = React5.memo(function ActionButton2({
|
|
1357
1357
|
active,
|
|
1358
1358
|
color,
|
|
1359
1359
|
children
|
|
@@ -1372,7 +1372,7 @@ var ActionButton = React3.memo(function ActionButton2({
|
|
|
1372
1372
|
);
|
|
1373
1373
|
});
|
|
1374
1374
|
var InputDisplay_default = InputDisplay;
|
|
1375
|
-
var RecordingIndicator =
|
|
1375
|
+
var RecordingIndicator = React5.memo(function RecordingIndicator2({
|
|
1376
1376
|
isRecording,
|
|
1377
1377
|
isPaused,
|
|
1378
1378
|
duration,
|
|
@@ -1381,7 +1381,7 @@ var RecordingIndicator = React3.memo(function RecordingIndicator2({
|
|
|
1381
1381
|
onStop,
|
|
1382
1382
|
systemColor = "#FF3333"
|
|
1383
1383
|
}) {
|
|
1384
|
-
const [isHovered, setIsHovered] =
|
|
1384
|
+
const [isHovered, setIsHovered] = React5.useState(false);
|
|
1385
1385
|
if (!isRecording) return null;
|
|
1386
1386
|
const minutes = Math.floor(duration / 60);
|
|
1387
1387
|
const seconds = duration % 60;
|
|
@@ -1495,7 +1495,7 @@ var SHORTCUTS = [
|
|
|
1495
1495
|
]
|
|
1496
1496
|
}
|
|
1497
1497
|
];
|
|
1498
|
-
var ShortcutsModal =
|
|
1498
|
+
var ShortcutsModal = React5.memo(function ShortcutsModal2({
|
|
1499
1499
|
isOpen,
|
|
1500
1500
|
onClose,
|
|
1501
1501
|
systemColor = "#00FF41"
|
|
@@ -1705,10 +1705,10 @@ function createOrientationChangeHandler(callback, checkReady, maxRafs = 3) {
|
|
|
1705
1705
|
|
|
1706
1706
|
// src/hooks/useMobile.ts
|
|
1707
1707
|
function useMobile() {
|
|
1708
|
-
const [isMobile, setIsMobile] =
|
|
1709
|
-
const [isLandscape, setIsLandscape] =
|
|
1710
|
-
const [isPortrait, setIsPortrait] =
|
|
1711
|
-
|
|
1708
|
+
const [isMobile, setIsMobile] = React5.useState(false);
|
|
1709
|
+
const [isLandscape, setIsLandscape] = React5.useState(false);
|
|
1710
|
+
const [isPortrait, setIsPortrait] = React5.useState(true);
|
|
1711
|
+
React5.useEffect(() => {
|
|
1712
1712
|
let lastOrientation = null;
|
|
1713
1713
|
let orientationTimeout = null;
|
|
1714
1714
|
const checkOrientation = () => {
|
|
@@ -1860,17 +1860,17 @@ function useTouchHandlers({
|
|
|
1860
1860
|
onRelease,
|
|
1861
1861
|
onPositionChange
|
|
1862
1862
|
}) {
|
|
1863
|
-
const isDraggingRef =
|
|
1864
|
-
const dragStartRef =
|
|
1865
|
-
const dragTimerRef =
|
|
1866
|
-
const touchStartPosRef =
|
|
1867
|
-
const clearDragTimer =
|
|
1863
|
+
const isDraggingRef = React5.useRef(false);
|
|
1864
|
+
const dragStartRef = React5.useRef({ x: 0, y: 0 });
|
|
1865
|
+
const dragTimerRef = React5.useRef(null);
|
|
1866
|
+
const touchStartPosRef = React5.useRef({ x: 0, y: 0 });
|
|
1867
|
+
const clearDragTimer = React5.useCallback(() => {
|
|
1868
1868
|
if (dragTimerRef.current) {
|
|
1869
1869
|
clearTimeout(dragTimerRef.current);
|
|
1870
1870
|
dragTimerRef.current = null;
|
|
1871
1871
|
}
|
|
1872
1872
|
}, []);
|
|
1873
|
-
const startDragging =
|
|
1873
|
+
const startDragging = React5.useCallback(
|
|
1874
1874
|
(touchX, touchY) => {
|
|
1875
1875
|
isDraggingRef.current = true;
|
|
1876
1876
|
dragStartRef.current = {
|
|
@@ -1883,7 +1883,7 @@ function useTouchHandlers({
|
|
|
1883
1883
|
},
|
|
1884
1884
|
[displayX, displayY, containerWidth, containerHeight, isSystemButton, buttonType, onRelease]
|
|
1885
1885
|
);
|
|
1886
|
-
const handleTouchStart =
|
|
1886
|
+
const handleTouchStart = React5.useCallback(
|
|
1887
1887
|
(e) => {
|
|
1888
1888
|
const touch = e.touches[0];
|
|
1889
1889
|
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY };
|
|
@@ -1918,7 +1918,7 @@ function useTouchHandlers({
|
|
|
1918
1918
|
},
|
|
1919
1919
|
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange, buttonSize, startDragging]
|
|
1920
1920
|
);
|
|
1921
|
-
const handleTouchMove =
|
|
1921
|
+
const handleTouchMove = React5.useCallback(
|
|
1922
1922
|
(e) => {
|
|
1923
1923
|
const touch = e.touches[0];
|
|
1924
1924
|
if (onPositionChange && !isDraggingRef.current) {
|
|
@@ -1945,7 +1945,7 @@ function useTouchHandlers({
|
|
|
1945
1945
|
},
|
|
1946
1946
|
[onPositionChange, clearDragTimer, startDragging, containerWidth, containerHeight, buttonSize]
|
|
1947
1947
|
);
|
|
1948
|
-
const handleTouchEnd =
|
|
1948
|
+
const handleTouchEnd = React5.useCallback(
|
|
1949
1949
|
(e) => {
|
|
1950
1950
|
clearDragTimer();
|
|
1951
1951
|
if (isDraggingRef.current) {
|
|
@@ -1962,7 +1962,7 @@ function useTouchHandlers({
|
|
|
1962
1962
|
},
|
|
1963
1963
|
[clearDragTimer, isSystemButton, buttonType, onRelease]
|
|
1964
1964
|
);
|
|
1965
|
-
const handleTouchCancel =
|
|
1965
|
+
const handleTouchCancel = React5.useCallback(
|
|
1966
1966
|
(e) => {
|
|
1967
1967
|
clearDragTimer();
|
|
1968
1968
|
if (isDraggingRef.current) {
|
|
@@ -1979,7 +1979,7 @@ function useTouchHandlers({
|
|
|
1979
1979
|
},
|
|
1980
1980
|
[clearDragTimer, isSystemButton, buttonType, onRelease]
|
|
1981
1981
|
);
|
|
1982
|
-
const cleanup =
|
|
1982
|
+
const cleanup = React5.useCallback(() => {
|
|
1983
1983
|
clearDragTimer();
|
|
1984
1984
|
}, [clearDragTimer]);
|
|
1985
1985
|
return {
|
|
@@ -2043,7 +2043,7 @@ function getButtonStyles(buttonType, isPressed) {
|
|
|
2043
2043
|
};
|
|
2044
2044
|
}
|
|
2045
2045
|
}
|
|
2046
|
-
var VirtualButton =
|
|
2046
|
+
var VirtualButton = React5__default.default.memo(function VirtualButton2({
|
|
2047
2047
|
config,
|
|
2048
2048
|
isPressed,
|
|
2049
2049
|
onPress,
|
|
@@ -2057,7 +2057,7 @@ var VirtualButton = React3__default.default.memo(function VirtualButton2({
|
|
|
2057
2057
|
systemColor = "#00FF41"
|
|
2058
2058
|
// Default retro green
|
|
2059
2059
|
}) {
|
|
2060
|
-
const buttonRef =
|
|
2060
|
+
const buttonRef = React5.useRef(null);
|
|
2061
2061
|
const isSystemButton = config.type === "start" || config.type === "select";
|
|
2062
2062
|
const displayX = customPosition ? customPosition.x : config.x;
|
|
2063
2063
|
const displayY = customPosition ? customPosition.y : config.y;
|
|
@@ -2080,7 +2080,7 @@ var VirtualButton = React3__default.default.memo(function VirtualButton2({
|
|
|
2080
2080
|
onRelease,
|
|
2081
2081
|
onPositionChange
|
|
2082
2082
|
});
|
|
2083
|
-
|
|
2083
|
+
React5.useEffect(() => {
|
|
2084
2084
|
const button = buttonRef.current;
|
|
2085
2085
|
if (!button) return;
|
|
2086
2086
|
button.addEventListener("touchstart", handleTouchStart, { passive: false });
|
|
@@ -2757,7 +2757,7 @@ function dispatchKeyboardEvent(type, code) {
|
|
|
2757
2757
|
canvas.dispatchEvent(event);
|
|
2758
2758
|
return true;
|
|
2759
2759
|
}
|
|
2760
|
-
var Dpad =
|
|
2760
|
+
var Dpad = React5__default.default.memo(function Dpad2({
|
|
2761
2761
|
size,
|
|
2762
2762
|
x,
|
|
2763
2763
|
y,
|
|
@@ -2767,14 +2767,14 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2767
2767
|
systemColor = "#00FF41",
|
|
2768
2768
|
isLandscape = false
|
|
2769
2769
|
}) {
|
|
2770
|
-
const dpadRef =
|
|
2771
|
-
const activeTouchRef =
|
|
2772
|
-
const activeDirectionsRef =
|
|
2773
|
-
const upRef =
|
|
2774
|
-
const downRef =
|
|
2775
|
-
const leftRef =
|
|
2776
|
-
const rightRef =
|
|
2777
|
-
const getKeyCode =
|
|
2770
|
+
const dpadRef = React5.useRef(null);
|
|
2771
|
+
const activeTouchRef = React5.useRef(null);
|
|
2772
|
+
const activeDirectionsRef = React5.useRef(/* @__PURE__ */ new Set());
|
|
2773
|
+
const upRef = React5.useRef(null);
|
|
2774
|
+
const downRef = React5.useRef(null);
|
|
2775
|
+
const leftRef = React5.useRef(null);
|
|
2776
|
+
const rightRef = React5.useRef(null);
|
|
2777
|
+
const getKeyCode = React5.useCallback((direction) => {
|
|
2778
2778
|
if (!controls) {
|
|
2779
2779
|
const defaults = {
|
|
2780
2780
|
up: "ArrowUp",
|
|
@@ -2786,7 +2786,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2786
2786
|
}
|
|
2787
2787
|
return controls[direction] || "";
|
|
2788
2788
|
}, [controls]);
|
|
2789
|
-
const getDirectionsFromTouch =
|
|
2789
|
+
const getDirectionsFromTouch = React5.useCallback((touchX, touchY, rect) => {
|
|
2790
2790
|
const centerX = rect.left + rect.width / 2;
|
|
2791
2791
|
const centerY = rect.top + rect.height / 2;
|
|
2792
2792
|
const dx = touchX - centerX;
|
|
@@ -2802,7 +2802,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2802
2802
|
if (angle >= -67.5 && angle <= 67.5) directions.add("right");
|
|
2803
2803
|
return directions;
|
|
2804
2804
|
}, []);
|
|
2805
|
-
const updateVisuals =
|
|
2805
|
+
const updateVisuals = React5.useCallback((directions) => {
|
|
2806
2806
|
const activeColor = systemColor;
|
|
2807
2807
|
const inactiveColor = "#1a1a1a";
|
|
2808
2808
|
if (upRef.current) upRef.current.style.fill = directions.has("up") ? activeColor : inactiveColor;
|
|
@@ -2810,7 +2810,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2810
2810
|
if (leftRef.current) leftRef.current.style.fill = directions.has("left") ? activeColor : inactiveColor;
|
|
2811
2811
|
if (rightRef.current) rightRef.current.style.fill = directions.has("right") ? activeColor : inactiveColor;
|
|
2812
2812
|
}, [systemColor]);
|
|
2813
|
-
const updateDirections =
|
|
2813
|
+
const updateDirections = React5.useCallback((newDirections) => {
|
|
2814
2814
|
const prev = activeDirectionsRef.current;
|
|
2815
2815
|
prev.forEach((dir) => {
|
|
2816
2816
|
if (!newDirections.has(dir)) {
|
|
@@ -2830,7 +2830,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2830
2830
|
activeDirectionsRef.current = newDirections;
|
|
2831
2831
|
updateVisuals(newDirections);
|
|
2832
2832
|
}, [getKeyCode, updateVisuals]);
|
|
2833
|
-
const handleTouchStart =
|
|
2833
|
+
const handleTouchStart = React5.useCallback((e) => {
|
|
2834
2834
|
e.preventDefault();
|
|
2835
2835
|
e.stopPropagation();
|
|
2836
2836
|
const touch = e.touches[0];
|
|
@@ -2839,7 +2839,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2839
2839
|
if (!rect) return;
|
|
2840
2840
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
2841
2841
|
}, [getDirectionsFromTouch, updateDirections]);
|
|
2842
|
-
const handleTouchMove =
|
|
2842
|
+
const handleTouchMove = React5.useCallback((e) => {
|
|
2843
2843
|
e.preventDefault();
|
|
2844
2844
|
let touch = null;
|
|
2845
2845
|
for (let i = 0; i < e.touches.length; i++) {
|
|
@@ -2853,7 +2853,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2853
2853
|
if (!rect) return;
|
|
2854
2854
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
2855
2855
|
}, [getDirectionsFromTouch, updateDirections]);
|
|
2856
|
-
const handleTouchEnd =
|
|
2856
|
+
const handleTouchEnd = React5.useCallback((e) => {
|
|
2857
2857
|
e.preventDefault();
|
|
2858
2858
|
let touchEnded = true;
|
|
2859
2859
|
for (let i = 0; i < e.touches.length; i++) {
|
|
@@ -2872,7 +2872,7 @@ var Dpad = React3__default.default.memo(function Dpad2({
|
|
|
2872
2872
|
updateVisuals(/* @__PURE__ */ new Set());
|
|
2873
2873
|
}
|
|
2874
2874
|
}, [getKeyCode, updateVisuals]);
|
|
2875
|
-
|
|
2875
|
+
React5.useEffect(() => {
|
|
2876
2876
|
const dpad = dpadRef.current;
|
|
2877
2877
|
if (!dpad) return;
|
|
2878
2878
|
dpad.addEventListener("touchstart", handleTouchStart, { passive: false });
|
|
@@ -2930,9 +2930,9 @@ function adjustButtonPosition(config, context) {
|
|
|
2930
2930
|
}
|
|
2931
2931
|
var STORAGE_KEY = "virtual-button-positions";
|
|
2932
2932
|
function useButtonPositions() {
|
|
2933
|
-
const [landscapePositions, setLandscapePositions] =
|
|
2934
|
-
const [portraitPositions, setPortraitPositions] =
|
|
2935
|
-
|
|
2933
|
+
const [landscapePositions, setLandscapePositions] = React5.useState({});
|
|
2934
|
+
const [portraitPositions, setPortraitPositions] = React5.useState({});
|
|
2935
|
+
React5.useEffect(() => {
|
|
2936
2936
|
try {
|
|
2937
2937
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
2938
2938
|
if (stored) {
|
|
@@ -2948,7 +2948,7 @@ function useButtonPositions() {
|
|
|
2948
2948
|
console.error("Failed to load button positions:", e);
|
|
2949
2949
|
}
|
|
2950
2950
|
}, []);
|
|
2951
|
-
const savePosition =
|
|
2951
|
+
const savePosition = React5.useCallback((buttonType, x, y, isLandscape) => {
|
|
2952
2952
|
if (isLandscape) {
|
|
2953
2953
|
setLandscapePositions((prev) => {
|
|
2954
2954
|
const updated = { ...prev, [buttonType]: { x, y } };
|
|
@@ -2979,11 +2979,11 @@ function useButtonPositions() {
|
|
|
2979
2979
|
});
|
|
2980
2980
|
}
|
|
2981
2981
|
}, [landscapePositions, portraitPositions]);
|
|
2982
|
-
const getPosition =
|
|
2982
|
+
const getPosition = React5.useCallback((buttonType, isLandscape) => {
|
|
2983
2983
|
const positions = isLandscape ? landscapePositions : portraitPositions;
|
|
2984
2984
|
return positions[buttonType] || null;
|
|
2985
2985
|
}, [landscapePositions, portraitPositions]);
|
|
2986
|
-
const resetPositions =
|
|
2986
|
+
const resetPositions = React5.useCallback(() => {
|
|
2987
2987
|
setLandscapePositions({});
|
|
2988
2988
|
setPortraitPositions({});
|
|
2989
2989
|
try {
|
|
@@ -3008,9 +3008,9 @@ function VirtualController({
|
|
|
3008
3008
|
// Default retro green
|
|
3009
3009
|
}) {
|
|
3010
3010
|
const { isMobile, isLandscape, isPortrait } = useMobile();
|
|
3011
|
-
const [pressedButtons, setPressedButtons] =
|
|
3012
|
-
const [containerSize, setContainerSize] =
|
|
3013
|
-
const [isFullscreenState, setIsFullscreenState] =
|
|
3011
|
+
const [pressedButtons, setPressedButtons] = React5.useState(/* @__PURE__ */ new Set());
|
|
3012
|
+
const [containerSize, setContainerSize] = React5.useState({ width: 0, height: 0 });
|
|
3013
|
+
const [isFullscreenState, setIsFullscreenState] = React5.useState(false);
|
|
3014
3014
|
const { getPosition, savePosition } = useButtonPositions();
|
|
3015
3015
|
const layout = getLayoutForSystem(system);
|
|
3016
3016
|
const visibleButtons = layout.buttons.filter((btn) => {
|
|
@@ -3021,7 +3021,7 @@ function VirtualController({
|
|
|
3021
3021
|
});
|
|
3022
3022
|
const DPAD_TYPES = ["up", "down", "left", "right"];
|
|
3023
3023
|
const dpadButtons = visibleButtons.filter((btn) => DPAD_TYPES.includes(btn.type));
|
|
3024
|
-
|
|
3024
|
+
React5.useEffect(() => {
|
|
3025
3025
|
const updateSize = () => {
|
|
3026
3026
|
const { width, height } = getViewportSize();
|
|
3027
3027
|
setContainerSize({ width, height });
|
|
@@ -3064,14 +3064,14 @@ function VirtualController({
|
|
|
3064
3064
|
cleanupFullscreen();
|
|
3065
3065
|
};
|
|
3066
3066
|
}, [containerSize.height]);
|
|
3067
|
-
const getButtonKeyboardCode =
|
|
3067
|
+
const getButtonKeyboardCode = React5.useCallback(
|
|
3068
3068
|
(buttonType) => {
|
|
3069
3069
|
return getKeyboardCode(buttonType, controls);
|
|
3070
3070
|
},
|
|
3071
3071
|
[controls]
|
|
3072
3072
|
);
|
|
3073
3073
|
const SYSTEM_BUTTONS2 = ["start", "select"];
|
|
3074
|
-
const handlePress =
|
|
3074
|
+
const handlePress = React5.useCallback(
|
|
3075
3075
|
(buttonType) => {
|
|
3076
3076
|
const isSystemButton = SYSTEM_BUTTONS2.includes(buttonType);
|
|
3077
3077
|
if (!isSystemButton && !isRunning) {
|
|
@@ -3094,7 +3094,7 @@ function VirtualController({
|
|
|
3094
3094
|
},
|
|
3095
3095
|
[isRunning, getButtonKeyboardCode]
|
|
3096
3096
|
);
|
|
3097
|
-
const handlePressDown =
|
|
3097
|
+
const handlePressDown = React5.useCallback(
|
|
3098
3098
|
(buttonType) => {
|
|
3099
3099
|
if (!isRunning) return;
|
|
3100
3100
|
const isSystemButton = SYSTEM_BUTTONS2.includes(buttonType);
|
|
@@ -3111,7 +3111,7 @@ function VirtualController({
|
|
|
3111
3111
|
},
|
|
3112
3112
|
[isRunning, getButtonKeyboardCode]
|
|
3113
3113
|
);
|
|
3114
|
-
const handleRelease =
|
|
3114
|
+
const handleRelease = React5.useCallback(
|
|
3115
3115
|
(buttonType) => {
|
|
3116
3116
|
const isSystemButton = SYSTEM_BUTTONS2.includes(buttonType);
|
|
3117
3117
|
if (isSystemButton) return;
|
|
@@ -3127,7 +3127,7 @@ function VirtualController({
|
|
|
3127
3127
|
},
|
|
3128
3128
|
[getButtonKeyboardCode]
|
|
3129
3129
|
);
|
|
3130
|
-
|
|
3130
|
+
React5.useEffect(() => {
|
|
3131
3131
|
if (!isRunning && pressedButtons.size > 0) {
|
|
3132
3132
|
pressedButtons.forEach((buttonType) => {
|
|
3133
3133
|
if (!SYSTEM_BUTTONS2.includes(buttonType)) {
|
|
@@ -3137,7 +3137,7 @@ function VirtualController({
|
|
|
3137
3137
|
setPressedButtons(/* @__PURE__ */ new Set());
|
|
3138
3138
|
}
|
|
3139
3139
|
}, [isRunning, pressedButtons, handleRelease]);
|
|
3140
|
-
const memoizedButtonElements =
|
|
3140
|
+
const memoizedButtonElements = React5.useMemo(() => {
|
|
3141
3141
|
const width = containerSize.width || (typeof window !== "undefined" ? window.innerWidth : 0);
|
|
3142
3142
|
const height = containerSize.height || (typeof window !== "undefined" ? window.innerHeight : 0);
|
|
3143
3143
|
const context = {
|
|
@@ -3408,7 +3408,7 @@ function saveMuteState(muted) {
|
|
|
3408
3408
|
if (typeof window === "undefined") return;
|
|
3409
3409
|
localStorage.setItem(MUTE_KEY, muted.toString());
|
|
3410
3410
|
}
|
|
3411
|
-
var GameCanvas =
|
|
3411
|
+
var GameCanvas = React5.memo(function GameCanvas2({
|
|
3412
3412
|
status,
|
|
3413
3413
|
system,
|
|
3414
3414
|
error,
|
|
@@ -3419,8 +3419,8 @@ var GameCanvas = React3.memo(function GameCanvas2({
|
|
|
3419
3419
|
canvasRef,
|
|
3420
3420
|
onSelectBios
|
|
3421
3421
|
}) {
|
|
3422
|
-
const canvasContainerRef =
|
|
3423
|
-
|
|
3422
|
+
const canvasContainerRef = React5.useRef(null);
|
|
3423
|
+
React5.useEffect(() => {
|
|
3424
3424
|
const container = canvasContainerRef.current;
|
|
3425
3425
|
if (!container || canvasRef.current) return;
|
|
3426
3426
|
const canvas = document.createElement("canvas");
|
|
@@ -3438,7 +3438,7 @@ var GameCanvas = React3.memo(function GameCanvas2({
|
|
|
3438
3438
|
canvasRef.current = null;
|
|
3439
3439
|
};
|
|
3440
3440
|
}, [canvasRef]);
|
|
3441
|
-
|
|
3441
|
+
React5.useEffect(() => {
|
|
3442
3442
|
if (status !== "ready" && status !== "running" && status !== "paused") return;
|
|
3443
3443
|
return setupCanvasResize(canvasContainerRef);
|
|
3444
3444
|
}, [status]);
|
|
@@ -3472,23 +3472,23 @@ function ControlMapper({
|
|
|
3472
3472
|
onClose,
|
|
3473
3473
|
system
|
|
3474
3474
|
}) {
|
|
3475
|
-
const [localControls, setLocalControls] =
|
|
3476
|
-
const [listeningFor, setListeningFor] =
|
|
3477
|
-
const activeButtons =
|
|
3475
|
+
const [localControls, setLocalControls] = React5.useState(controls);
|
|
3476
|
+
const [listeningFor, setListeningFor] = React5.useState(null);
|
|
3477
|
+
const activeButtons = React5.useMemo(() => {
|
|
3478
3478
|
return getConsoleButtons(system || "SNES");
|
|
3479
3479
|
}, [system]);
|
|
3480
|
-
const controlGroups =
|
|
3480
|
+
const controlGroups = React5.useMemo(() => {
|
|
3481
3481
|
return getFilteredGroups(activeButtons);
|
|
3482
3482
|
}, [activeButtons]);
|
|
3483
|
-
const defaultControls =
|
|
3483
|
+
const defaultControls = React5.useMemo(() => {
|
|
3484
3484
|
return getConsoleKeyboardDefaults(system || "SNES");
|
|
3485
3485
|
}, [system]);
|
|
3486
|
-
|
|
3486
|
+
React5.useEffect(() => {
|
|
3487
3487
|
if (isOpen) {
|
|
3488
3488
|
setLocalControls(controls);
|
|
3489
3489
|
}
|
|
3490
3490
|
}, [isOpen, controls]);
|
|
3491
|
-
|
|
3491
|
+
React5.useEffect(() => {
|
|
3492
3492
|
if (!isOpen) {
|
|
3493
3493
|
setListeningFor(null);
|
|
3494
3494
|
return;
|
|
@@ -3638,17 +3638,17 @@ function toGamepadInfo(gamepad) {
|
|
|
3638
3638
|
}
|
|
3639
3639
|
function useGamepad(options) {
|
|
3640
3640
|
const { onConnect, onDisconnect } = options || {};
|
|
3641
|
-
const [gamepads, setGamepads] =
|
|
3642
|
-
const rafRef =
|
|
3643
|
-
const lastStateRef =
|
|
3644
|
-
const prevCountRef =
|
|
3645
|
-
const onConnectRef =
|
|
3646
|
-
const onDisconnectRef =
|
|
3647
|
-
|
|
3641
|
+
const [gamepads, setGamepads] = React5.useState([]);
|
|
3642
|
+
const rafRef = React5.useRef(null);
|
|
3643
|
+
const lastStateRef = React5.useRef("");
|
|
3644
|
+
const prevCountRef = React5.useRef(0);
|
|
3645
|
+
const onConnectRef = React5.useRef(onConnect);
|
|
3646
|
+
const onDisconnectRef = React5.useRef(onDisconnect);
|
|
3647
|
+
React5.useEffect(() => {
|
|
3648
3648
|
onConnectRef.current = onConnect;
|
|
3649
3649
|
onDisconnectRef.current = onDisconnect;
|
|
3650
3650
|
}, [onConnect, onDisconnect]);
|
|
3651
|
-
const getGamepads =
|
|
3651
|
+
const getGamepads = React5.useCallback(() => {
|
|
3652
3652
|
if (typeof navigator === "undefined" || typeof navigator.getGamepads !== "function") {
|
|
3653
3653
|
return [];
|
|
3654
3654
|
}
|
|
@@ -3662,14 +3662,14 @@ function useGamepad(options) {
|
|
|
3662
3662
|
}
|
|
3663
3663
|
return connected;
|
|
3664
3664
|
}, []);
|
|
3665
|
-
const getRawGamepad =
|
|
3665
|
+
const getRawGamepad = React5.useCallback((index) => {
|
|
3666
3666
|
const rawGamepads = navigator.getGamepads?.() ?? [];
|
|
3667
3667
|
return rawGamepads[index] ?? null;
|
|
3668
3668
|
}, []);
|
|
3669
|
-
const refresh =
|
|
3669
|
+
const refresh = React5.useCallback(() => {
|
|
3670
3670
|
setGamepads(getGamepads());
|
|
3671
3671
|
}, [getGamepads]);
|
|
3672
|
-
|
|
3672
|
+
React5.useEffect(() => {
|
|
3673
3673
|
if (typeof window === "undefined" || typeof navigator === "undefined") {
|
|
3674
3674
|
return;
|
|
3675
3675
|
}
|
|
@@ -3770,11 +3770,11 @@ function GamepadMapper({
|
|
|
3770
3770
|
onSave,
|
|
3771
3771
|
systemColor = "#00FF41"
|
|
3772
3772
|
}) {
|
|
3773
|
-
const [selectedPlayer, setSelectedPlayer] =
|
|
3774
|
-
const [bindings, setBindings] =
|
|
3775
|
-
const [listeningFor, setListeningFor] =
|
|
3776
|
-
const rafRef =
|
|
3777
|
-
|
|
3773
|
+
const [selectedPlayer, setSelectedPlayer] = React5.useState(1);
|
|
3774
|
+
const [bindings, setBindings] = React5.useState({});
|
|
3775
|
+
const [listeningFor, setListeningFor] = React5.useState(null);
|
|
3776
|
+
const rafRef = React5.useRef(null);
|
|
3777
|
+
React5.useEffect(() => {
|
|
3778
3778
|
if (isOpen) {
|
|
3779
3779
|
const loadedBindings = {};
|
|
3780
3780
|
for (let i = 1; i <= 4; i++) {
|
|
@@ -3786,7 +3786,7 @@ function GamepadMapper({
|
|
|
3786
3786
|
}
|
|
3787
3787
|
}
|
|
3788
3788
|
}, [isOpen, gamepads]);
|
|
3789
|
-
|
|
3789
|
+
React5.useEffect(() => {
|
|
3790
3790
|
if (!isOpen || !listeningFor) {
|
|
3791
3791
|
if (rafRef.current) {
|
|
3792
3792
|
cancelAnimationFrame(rafRef.current);
|
|
@@ -3821,7 +3821,7 @@ function GamepadMapper({
|
|
|
3821
3821
|
}
|
|
3822
3822
|
};
|
|
3823
3823
|
}, [isOpen, listeningFor, selectedPlayer]);
|
|
3824
|
-
|
|
3824
|
+
React5.useEffect(() => {
|
|
3825
3825
|
if (!isOpen) return;
|
|
3826
3826
|
const handleKeyDown = (e) => {
|
|
3827
3827
|
if (e.code === "Escape") {
|
|
@@ -4009,7 +4009,7 @@ function CheatModal({
|
|
|
4009
4009
|
onToggle,
|
|
4010
4010
|
onClose
|
|
4011
4011
|
}) {
|
|
4012
|
-
const [copiedId, setCopiedId] =
|
|
4012
|
+
const [copiedId, setCopiedId] = React5__default.default.useState(null);
|
|
4013
4013
|
if (!isOpen) return null;
|
|
4014
4014
|
const handleCopy = async (code, id) => {
|
|
4015
4015
|
await navigator.clipboard.writeText(code);
|
|
@@ -4908,13 +4908,13 @@ function RASidebar({
|
|
|
4908
4908
|
unlockedIds
|
|
4909
4909
|
}) {
|
|
4910
4910
|
const defaultTab = isLoggedIn && currentGame && achievements.length > 0 ? "achievements" : "settings";
|
|
4911
|
-
const [activeTab, setActiveTab] =
|
|
4912
|
-
const [filter, setFilter] =
|
|
4913
|
-
const [username, setUsername] =
|
|
4914
|
-
const [password, setPassword] =
|
|
4915
|
-
const [showPassword, setShowPassword] =
|
|
4916
|
-
const [localError, setLocalError] =
|
|
4917
|
-
|
|
4911
|
+
const [activeTab, setActiveTab] = React5.useState(defaultTab);
|
|
4912
|
+
const [filter, setFilter] = React5.useState("all");
|
|
4913
|
+
const [username, setUsername] = React5.useState("");
|
|
4914
|
+
const [password, setPassword] = React5.useState("");
|
|
4915
|
+
const [showPassword, setShowPassword] = React5.useState(false);
|
|
4916
|
+
const [localError, setLocalError] = React5.useState(null);
|
|
4917
|
+
React5.useEffect(() => {
|
|
4918
4918
|
if (!isOpen) {
|
|
4919
4919
|
setUsername("");
|
|
4920
4920
|
setPassword("");
|
|
@@ -5069,8 +5069,8 @@ function RASidebar({
|
|
|
5069
5069
|
] });
|
|
5070
5070
|
}
|
|
5071
5071
|
function useToast(defaultDuration = 3e3) {
|
|
5072
|
-
const [toasts, setToasts] =
|
|
5073
|
-
const showToast =
|
|
5072
|
+
const [toasts, setToasts] = React5.useState([]);
|
|
5073
|
+
const showToast = React5.useCallback((message, type = "info", options) => {
|
|
5074
5074
|
const id = crypto.randomUUID();
|
|
5075
5075
|
const duration = options?.duration ?? defaultDuration;
|
|
5076
5076
|
const newToast = {
|
|
@@ -5089,10 +5089,10 @@ function useToast(defaultDuration = 3e3) {
|
|
|
5089
5089
|
}, duration);
|
|
5090
5090
|
}
|
|
5091
5091
|
}, [defaultDuration]);
|
|
5092
|
-
const dismissToast =
|
|
5092
|
+
const dismissToast = React5.useCallback((id) => {
|
|
5093
5093
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
5094
5094
|
}, []);
|
|
5095
|
-
const clearToasts =
|
|
5095
|
+
const clearToasts = React5.useCallback(() => {
|
|
5096
5096
|
setToasts([]);
|
|
5097
5097
|
}, []);
|
|
5098
5098
|
return {
|
|
@@ -5106,21 +5106,21 @@ function useToast(defaultDuration = 3e3) {
|
|
|
5106
5106
|
// src/hooks/useGameUI.ts
|
|
5107
5107
|
function useGameUI() {
|
|
5108
5108
|
const { isMobile } = useMobile();
|
|
5109
|
-
const containerRef =
|
|
5110
|
-
const canvasRef =
|
|
5109
|
+
const containerRef = React5.useRef(null);
|
|
5110
|
+
const canvasRef = React5.useRef(null);
|
|
5111
5111
|
const { toasts, showToast, dismissToast } = useToast(3500);
|
|
5112
|
-
const [isFullscreen2, setIsFullscreen] =
|
|
5113
|
-
const [raSidebarOpen, setRaSidebarOpen] =
|
|
5114
|
-
const checkFullscreen =
|
|
5112
|
+
const [isFullscreen2, setIsFullscreen] = React5.useState(false);
|
|
5113
|
+
const [raSidebarOpen, setRaSidebarOpen] = React5.useState(false);
|
|
5114
|
+
const checkFullscreen = React5.useCallback(() => {
|
|
5115
5115
|
const fullscreen = isFullscreen();
|
|
5116
5116
|
setIsFullscreen(fullscreen);
|
|
5117
5117
|
return fullscreen;
|
|
5118
5118
|
}, []);
|
|
5119
|
-
|
|
5119
|
+
React5.useEffect(() => {
|
|
5120
5120
|
checkFullscreen();
|
|
5121
5121
|
return setupFullscreenListener(checkFullscreen);
|
|
5122
5122
|
}, [checkFullscreen]);
|
|
5123
|
-
const handleFullscreen =
|
|
5123
|
+
const handleFullscreen = React5.useCallback(async () => {
|
|
5124
5124
|
if (!containerRef.current) return;
|
|
5125
5125
|
try {
|
|
5126
5126
|
const nativeWorked = await toggleFullscreen(containerRef.current);
|
|
@@ -5663,15 +5663,15 @@ function useEmulatorCore({
|
|
|
5663
5663
|
onReady,
|
|
5664
5664
|
onError
|
|
5665
5665
|
}) {
|
|
5666
|
-
const [status, setStatus] =
|
|
5667
|
-
const [error, setError] =
|
|
5668
|
-
const [isPaused, setIsPaused] =
|
|
5669
|
-
const [speed, setSpeedState] =
|
|
5670
|
-
const [isFastForwardOn, setIsFastForwardOn] =
|
|
5671
|
-
const [isPerformanceMode, setIsPerformanceMode] =
|
|
5672
|
-
const nostalgistRef =
|
|
5673
|
-
const isStartingRef =
|
|
5674
|
-
const prepare =
|
|
5666
|
+
const [status, setStatus] = React5.useState("idle");
|
|
5667
|
+
const [error, setError] = React5.useState(null);
|
|
5668
|
+
const [isPaused, setIsPaused] = React5.useState(false);
|
|
5669
|
+
const [speed, setSpeedState] = React5.useState(1);
|
|
5670
|
+
const [isFastForwardOn, setIsFastForwardOn] = React5.useState(false);
|
|
5671
|
+
const [isPerformanceMode, setIsPerformanceMode] = React5.useState(false);
|
|
5672
|
+
const nostalgistRef = React5.useRef(null);
|
|
5673
|
+
const isStartingRef = React5.useRef(false);
|
|
5674
|
+
const prepare = React5.useCallback(async () => {
|
|
5675
5675
|
if (!romUrl || !system) {
|
|
5676
5676
|
console.warn("[Nostalgist] Missing romUrl or system");
|
|
5677
5677
|
return;
|
|
@@ -5802,7 +5802,7 @@ function useEmulatorCore({
|
|
|
5802
5802
|
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
5803
5803
|
}
|
|
5804
5804
|
}, [system, romUrl, coreOverride, biosUrl, initialState, getCanvasElement, keyboardControls, gamepadBindings, initialVolume, onError, retroAchievements]);
|
|
5805
|
-
const start =
|
|
5805
|
+
const start = React5.useCallback(async () => {
|
|
5806
5806
|
if (isStartingRef.current) {
|
|
5807
5807
|
console.log("[Nostalgist] Already starting");
|
|
5808
5808
|
return;
|
|
@@ -5835,7 +5835,7 @@ function useEmulatorCore({
|
|
|
5835
5835
|
isStartingRef.current = false;
|
|
5836
5836
|
}
|
|
5837
5837
|
}, [prepare, onReady, onError]);
|
|
5838
|
-
const stop =
|
|
5838
|
+
const stop = React5.useCallback(() => {
|
|
5839
5839
|
if (nostalgistRef.current) {
|
|
5840
5840
|
try {
|
|
5841
5841
|
nostalgistRef.current.exit();
|
|
@@ -5848,7 +5848,7 @@ function useEmulatorCore({
|
|
|
5848
5848
|
setIsPaused(false);
|
|
5849
5849
|
}
|
|
5850
5850
|
}, []);
|
|
5851
|
-
|
|
5851
|
+
React5.useEffect(() => {
|
|
5852
5852
|
return () => {
|
|
5853
5853
|
if (nostalgistRef.current) {
|
|
5854
5854
|
console.log("[Nostalgist] Cleaning up emulator on unmount");
|
|
@@ -5856,7 +5856,7 @@ function useEmulatorCore({
|
|
|
5856
5856
|
}
|
|
5857
5857
|
};
|
|
5858
5858
|
}, [stop]);
|
|
5859
|
-
const restart =
|
|
5859
|
+
const restart = React5.useCallback(async () => {
|
|
5860
5860
|
if (nostalgistRef.current) {
|
|
5861
5861
|
try {
|
|
5862
5862
|
nostalgistRef.current.restart();
|
|
@@ -5871,7 +5871,7 @@ function useEmulatorCore({
|
|
|
5871
5871
|
}
|
|
5872
5872
|
}
|
|
5873
5873
|
}, [stop, start]);
|
|
5874
|
-
const pause =
|
|
5874
|
+
const pause = React5.useCallback(() => {
|
|
5875
5875
|
if (nostalgistRef.current && !isPaused && status === "running") {
|
|
5876
5876
|
try {
|
|
5877
5877
|
nostalgistRef.current.pause();
|
|
@@ -5882,7 +5882,7 @@ function useEmulatorCore({
|
|
|
5882
5882
|
}
|
|
5883
5883
|
}
|
|
5884
5884
|
}, [isPaused, status]);
|
|
5885
|
-
const resume =
|
|
5885
|
+
const resume = React5.useCallback(() => {
|
|
5886
5886
|
if (nostalgistRef.current) {
|
|
5887
5887
|
try {
|
|
5888
5888
|
nostalgistRef.current.resume();
|
|
@@ -5895,14 +5895,14 @@ function useEmulatorCore({
|
|
|
5895
5895
|
}
|
|
5896
5896
|
}
|
|
5897
5897
|
}, [status]);
|
|
5898
|
-
const togglePause =
|
|
5898
|
+
const togglePause = React5.useCallback(() => {
|
|
5899
5899
|
if (isPaused) {
|
|
5900
5900
|
resume();
|
|
5901
5901
|
} else {
|
|
5902
5902
|
pause();
|
|
5903
5903
|
}
|
|
5904
5904
|
}, [isPaused, pause, resume]);
|
|
5905
|
-
const setSpeed =
|
|
5905
|
+
const setSpeed = React5.useCallback((multiplier) => {
|
|
5906
5906
|
if (!nostalgistRef.current) return;
|
|
5907
5907
|
try {
|
|
5908
5908
|
const nostalgist = nostalgistRef.current;
|
|
@@ -5922,7 +5922,7 @@ function useEmulatorCore({
|
|
|
5922
5922
|
console.error("[Nostalgist] Set speed error:", err);
|
|
5923
5923
|
}
|
|
5924
5924
|
}, [isFastForwardOn]);
|
|
5925
|
-
const screenshot =
|
|
5925
|
+
const screenshot = React5.useCallback(async () => {
|
|
5926
5926
|
if (!nostalgistRef.current) {
|
|
5927
5927
|
return null;
|
|
5928
5928
|
}
|
|
@@ -5952,7 +5952,7 @@ function useEmulatorCore({
|
|
|
5952
5952
|
return null;
|
|
5953
5953
|
}
|
|
5954
5954
|
}, []);
|
|
5955
|
-
const resize =
|
|
5955
|
+
const resize = React5.useCallback((size) => {
|
|
5956
5956
|
if (!nostalgistRef.current) {
|
|
5957
5957
|
console.warn("[Nostalgist] Cannot resize: emulator not ready");
|
|
5958
5958
|
return;
|
|
@@ -5963,7 +5963,7 @@ function useEmulatorCore({
|
|
|
5963
5963
|
console.error("[Nostalgist] Resize error:", err);
|
|
5964
5964
|
}
|
|
5965
5965
|
}, []);
|
|
5966
|
-
|
|
5966
|
+
React5.useCallback(() => {
|
|
5967
5967
|
return nostalgistRef.current;
|
|
5968
5968
|
}, []);
|
|
5969
5969
|
return {
|
|
@@ -5989,11 +5989,11 @@ function useEmulatorCore({
|
|
|
5989
5989
|
};
|
|
5990
5990
|
}
|
|
5991
5991
|
function useEmulatorAudio({ nostalgistRef, initialVolume = 100 }) {
|
|
5992
|
-
const [volume, setVolume] =
|
|
5993
|
-
const [isMuted, setIsMuted] =
|
|
5994
|
-
const gainNodeRef =
|
|
5995
|
-
const lastVolumeRef =
|
|
5996
|
-
|
|
5992
|
+
const [volume, setVolume] = React5.useState(initialVolume);
|
|
5993
|
+
const [isMuted, setIsMuted] = React5.useState(false);
|
|
5994
|
+
const gainNodeRef = React5.useRef(null);
|
|
5995
|
+
const lastVolumeRef = React5.useRef(initialVolume);
|
|
5996
|
+
React5.useEffect(() => {
|
|
5997
5997
|
const originalConnect = AudioNode.prototype.connect;
|
|
5998
5998
|
const contextGainMap = /* @__PURE__ */ new WeakMap();
|
|
5999
5999
|
AudioNode.prototype.connect = function(destination, output, input) {
|
|
@@ -6021,7 +6021,7 @@ function useEmulatorAudio({ nostalgistRef, initialVolume = 100 }) {
|
|
|
6021
6021
|
AudioNode.prototype.connect = originalConnect;
|
|
6022
6022
|
};
|
|
6023
6023
|
}, []);
|
|
6024
|
-
const setVolumeLevel =
|
|
6024
|
+
const setVolumeLevel = React5.useCallback((newVolume) => {
|
|
6025
6025
|
const clampedVolume = Math.max(0, Math.min(100, newVolume));
|
|
6026
6026
|
const volumeValue = clampedVolume / 100;
|
|
6027
6027
|
try {
|
|
@@ -6042,7 +6042,7 @@ function useEmulatorAudio({ nostalgistRef, initialVolume = 100 }) {
|
|
|
6042
6042
|
console.error("[Nostalgist] Volume change error:", err);
|
|
6043
6043
|
}
|
|
6044
6044
|
}, []);
|
|
6045
|
-
const toggleMute =
|
|
6045
|
+
const toggleMute = React5.useCallback(() => {
|
|
6046
6046
|
if (!nostalgistRef.current) return;
|
|
6047
6047
|
try {
|
|
6048
6048
|
const emscripten = nostalgistRef.current.getEmscripten();
|
|
@@ -6084,7 +6084,7 @@ function useEmulatorAudio({ nostalgistRef, initialVolume = 100 }) {
|
|
|
6084
6084
|
};
|
|
6085
6085
|
}
|
|
6086
6086
|
function useEmulatorInput({ nostalgistRef }) {
|
|
6087
|
-
const pressKey =
|
|
6087
|
+
const pressKey = React5.useCallback((key) => {
|
|
6088
6088
|
if (!nostalgistRef.current) return;
|
|
6089
6089
|
try {
|
|
6090
6090
|
nostalgistRef.current.press(key);
|
|
@@ -6099,10 +6099,10 @@ function useEmulatorInput({ nostalgistRef }) {
|
|
|
6099
6099
|
var MIN_SAVE_INTERVAL = 100;
|
|
6100
6100
|
var SAVE_TIMEOUT = 5e3;
|
|
6101
6101
|
function useSaveScheduler(nostalgistRef) {
|
|
6102
|
-
const queueRef =
|
|
6103
|
-
const savingRef =
|
|
6104
|
-
const lastSaveTimeRef =
|
|
6105
|
-
const processQueue =
|
|
6102
|
+
const queueRef = React5.useRef([]);
|
|
6103
|
+
const savingRef = React5.useRef(false);
|
|
6104
|
+
const lastSaveTimeRef = React5.useRef(0);
|
|
6105
|
+
const processQueue = React5.useCallback(async () => {
|
|
6106
6106
|
if (savingRef.current || queueRef.current.length === 0) {
|
|
6107
6107
|
return;
|
|
6108
6108
|
}
|
|
@@ -6156,7 +6156,7 @@ function useSaveScheduler(nostalgistRef) {
|
|
|
6156
6156
|
setTimeout(() => processQueue(), MIN_SAVE_INTERVAL);
|
|
6157
6157
|
}
|
|
6158
6158
|
}, [nostalgistRef]);
|
|
6159
|
-
const save =
|
|
6159
|
+
const save = React5.useCallback(() => {
|
|
6160
6160
|
return new Promise((resolve) => {
|
|
6161
6161
|
queueRef.current.push({
|
|
6162
6162
|
priority: "high",
|
|
@@ -6166,7 +6166,7 @@ function useSaveScheduler(nostalgistRef) {
|
|
|
6166
6166
|
processQueue();
|
|
6167
6167
|
});
|
|
6168
6168
|
}, [processQueue]);
|
|
6169
|
-
const queueRewindCapture =
|
|
6169
|
+
const queueRewindCapture = React5.useCallback(() => {
|
|
6170
6170
|
const lowPriorityCount = queueRef.current.filter((q) => q.priority === "low").length;
|
|
6171
6171
|
if (lowPriorityCount >= 3) {
|
|
6172
6172
|
return Promise.resolve(null);
|
|
@@ -6180,13 +6180,13 @@ function useSaveScheduler(nostalgistRef) {
|
|
|
6180
6180
|
processQueue();
|
|
6181
6181
|
});
|
|
6182
6182
|
}, [processQueue]);
|
|
6183
|
-
const isSaving =
|
|
6184
|
-
const getQueueLength =
|
|
6185
|
-
const clearQueue =
|
|
6183
|
+
const isSaving = React5.useCallback(() => savingRef.current, []);
|
|
6184
|
+
const getQueueLength = React5.useCallback(() => queueRef.current.length, []);
|
|
6185
|
+
const clearQueue = React5.useCallback(() => {
|
|
6186
6186
|
queueRef.current.forEach((item) => item.resolve(null));
|
|
6187
6187
|
queueRef.current = [];
|
|
6188
6188
|
}, []);
|
|
6189
|
-
const resultRef =
|
|
6189
|
+
const resultRef = React5.useRef({
|
|
6190
6190
|
save,
|
|
6191
6191
|
queueRewindCapture,
|
|
6192
6192
|
isSaving,
|
|
@@ -6203,22 +6203,22 @@ function useSaveScheduler(nostalgistRef) {
|
|
|
6203
6203
|
|
|
6204
6204
|
// src/hooks/emulator/useEmulatorSaves.ts
|
|
6205
6205
|
function useEmulatorSaves({ nostalgistRef, isPaused, setIsPaused, setStatus, rewindEnabled = true }) {
|
|
6206
|
-
const [isRewinding, setIsRewinding] =
|
|
6207
|
-
const [rewindBufferSize, setRewindBufferSize] =
|
|
6208
|
-
const rewindIntervalRef =
|
|
6209
|
-
const rewindBufferRef =
|
|
6210
|
-
const rewindCaptureIntervalRef =
|
|
6206
|
+
const [isRewinding, setIsRewinding] = React5.useState(false);
|
|
6207
|
+
const [rewindBufferSize, setRewindBufferSize] = React5.useState(0);
|
|
6208
|
+
const rewindIntervalRef = React5.useRef(null);
|
|
6209
|
+
const rewindBufferRef = React5.useRef([]);
|
|
6210
|
+
const rewindCaptureIntervalRef = React5.useRef(null);
|
|
6211
6211
|
const saveScheduler = useSaveScheduler(nostalgistRef);
|
|
6212
|
-
const saveState =
|
|
6212
|
+
const saveState = React5.useCallback(async () => {
|
|
6213
6213
|
if (!nostalgistRef.current) return null;
|
|
6214
6214
|
const result = await saveScheduler.queueRewindCapture();
|
|
6215
6215
|
return result?.data ?? null;
|
|
6216
6216
|
}, [saveScheduler, nostalgistRef]);
|
|
6217
|
-
const saveStateWithBlob =
|
|
6217
|
+
const saveStateWithBlob = React5.useCallback(async () => {
|
|
6218
6218
|
if (!nostalgistRef.current) return null;
|
|
6219
6219
|
return saveScheduler.save();
|
|
6220
6220
|
}, [saveScheduler, nostalgistRef]);
|
|
6221
|
-
const loadState =
|
|
6221
|
+
const loadState = React5.useCallback(async (state) => {
|
|
6222
6222
|
if (!nostalgistRef.current) {
|
|
6223
6223
|
console.warn("[Nostalgist] Cannot load state: emulator not running");
|
|
6224
6224
|
return false;
|
|
@@ -6239,7 +6239,7 @@ function useEmulatorSaves({ nostalgistRef, isPaused, setIsPaused, setStatus, rew
|
|
|
6239
6239
|
return false;
|
|
6240
6240
|
}
|
|
6241
6241
|
}, [nostalgistRef, setIsPaused, setStatus]);
|
|
6242
|
-
const startRewindCapture =
|
|
6242
|
+
const startRewindCapture = React5.useCallback(() => {
|
|
6243
6243
|
if (!rewindEnabled) {
|
|
6244
6244
|
return;
|
|
6245
6245
|
}
|
|
@@ -6267,13 +6267,13 @@ function useEmulatorSaves({ nostalgistRef, isPaused, setIsPaused, setStatus, rew
|
|
|
6267
6267
|
}
|
|
6268
6268
|
}, 500);
|
|
6269
6269
|
}, [isPaused, saveState, nostalgistRef]);
|
|
6270
|
-
const stopRewindCapture =
|
|
6270
|
+
const stopRewindCapture = React5.useCallback(() => {
|
|
6271
6271
|
if (rewindCaptureIntervalRef.current) {
|
|
6272
6272
|
clearInterval(rewindCaptureIntervalRef.current);
|
|
6273
6273
|
rewindCaptureIntervalRef.current = null;
|
|
6274
6274
|
}
|
|
6275
6275
|
}, []);
|
|
6276
|
-
const stopRewind =
|
|
6276
|
+
const stopRewind = React5.useCallback(() => {
|
|
6277
6277
|
if (!isRewinding) {
|
|
6278
6278
|
return;
|
|
6279
6279
|
}
|
|
@@ -6294,7 +6294,7 @@ function useEmulatorSaves({ nostalgistRef, isPaused, setIsPaused, setStatus, rew
|
|
|
6294
6294
|
console.error("[Nostalgist] Stop rewind error:", err);
|
|
6295
6295
|
}
|
|
6296
6296
|
}, [isRewinding, startRewindCapture, nostalgistRef]);
|
|
6297
|
-
const startRewind =
|
|
6297
|
+
const startRewind = React5.useCallback(() => {
|
|
6298
6298
|
if (!nostalgistRef.current || isRewinding) {
|
|
6299
6299
|
return;
|
|
6300
6300
|
}
|
|
@@ -6333,7 +6333,7 @@ function useEmulatorSaves({ nostalgistRef, isPaused, setIsPaused, setStatus, rew
|
|
|
6333
6333
|
startRewindCapture();
|
|
6334
6334
|
}
|
|
6335
6335
|
}, [isRewinding, loadState, stopRewindCapture, startRewindCapture, stopRewind, nostalgistRef]);
|
|
6336
|
-
|
|
6336
|
+
React5.useEffect(() => {
|
|
6337
6337
|
return () => {
|
|
6338
6338
|
saveScheduler.clearQueue();
|
|
6339
6339
|
if (rewindIntervalRef.current) {
|
|
@@ -6361,7 +6361,7 @@ function useEmulatorSaves({ nostalgistRef, isPaused, setIsPaused, setStatus, rew
|
|
|
6361
6361
|
};
|
|
6362
6362
|
}
|
|
6363
6363
|
function useEmulatorCheats({ nostalgistRef }) {
|
|
6364
|
-
const applyCheat =
|
|
6364
|
+
const applyCheat = React5.useCallback((code) => {
|
|
6365
6365
|
if (!nostalgistRef.current) return;
|
|
6366
6366
|
try {
|
|
6367
6367
|
nostalgistRef.current.addCheat(code);
|
|
@@ -6369,7 +6369,7 @@ function useEmulatorCheats({ nostalgistRef }) {
|
|
|
6369
6369
|
console.error("[Nostalgist] Apply cheat error:", err);
|
|
6370
6370
|
}
|
|
6371
6371
|
}, [nostalgistRef]);
|
|
6372
|
-
const resetCheats =
|
|
6372
|
+
const resetCheats = React5.useCallback(() => {
|
|
6373
6373
|
if (!nostalgistRef.current) return;
|
|
6374
6374
|
try {
|
|
6375
6375
|
nostalgistRef.current.resetCheats();
|
|
@@ -6400,7 +6400,7 @@ var useNostalgist = ({
|
|
|
6400
6400
|
romFileName,
|
|
6401
6401
|
shader
|
|
6402
6402
|
}) => {
|
|
6403
|
-
const isHeavySystem =
|
|
6403
|
+
const isHeavySystem = React5.useMemo(() => {
|
|
6404
6404
|
return PERFORMANCE_TIER_2_SYSTEMS.has(system.toUpperCase());
|
|
6405
6405
|
}, [system]);
|
|
6406
6406
|
const {
|
|
@@ -6477,7 +6477,7 @@ var useNostalgist = ({
|
|
|
6477
6477
|
} = useEmulatorCheats({
|
|
6478
6478
|
nostalgistRef
|
|
6479
6479
|
});
|
|
6480
|
-
const start =
|
|
6480
|
+
const start = React5.useCallback(async () => {
|
|
6481
6481
|
await coreStart();
|
|
6482
6482
|
setTimeout(() => {
|
|
6483
6483
|
if (nostalgistRef.current) {
|
|
@@ -6485,11 +6485,11 @@ var useNostalgist = ({
|
|
|
6485
6485
|
}
|
|
6486
6486
|
}, 2e3);
|
|
6487
6487
|
}, [coreStart, startRewindCapture, nostalgistRef]);
|
|
6488
|
-
const stop =
|
|
6488
|
+
const stop = React5.useCallback(() => {
|
|
6489
6489
|
stopRewindCapture();
|
|
6490
6490
|
coreStop();
|
|
6491
6491
|
}, [stopRewindCapture, coreStop]);
|
|
6492
|
-
const hookReturn =
|
|
6492
|
+
const hookReturn = React5.useMemo(() => ({
|
|
6493
6493
|
status,
|
|
6494
6494
|
error,
|
|
6495
6495
|
isPaused,
|
|
@@ -6560,18 +6560,18 @@ function useVolume({
|
|
|
6560
6560
|
setVolume: setVolumeInHook,
|
|
6561
6561
|
toggleMute: toggleMuteInHook
|
|
6562
6562
|
}) {
|
|
6563
|
-
const [volume, setVolumeState] =
|
|
6564
|
-
const [isMuted, setIsMutedState] =
|
|
6565
|
-
|
|
6563
|
+
const [volume, setVolumeState] = React5.useState(() => loadVolume());
|
|
6564
|
+
const [isMuted, setIsMutedState] = React5.useState(() => loadMuteState());
|
|
6565
|
+
React5.useEffect(() => {
|
|
6566
6566
|
setVolumeInHook(volume);
|
|
6567
6567
|
}, [setVolumeInHook]);
|
|
6568
|
-
const setVolume =
|
|
6568
|
+
const setVolume = React5.useCallback((newVolume) => {
|
|
6569
6569
|
const clampedVolume = Math.max(0, Math.min(100, newVolume));
|
|
6570
6570
|
setVolumeState(clampedVolume);
|
|
6571
6571
|
saveVolume(clampedVolume);
|
|
6572
6572
|
setVolumeInHook(clampedVolume);
|
|
6573
6573
|
}, [setVolumeInHook]);
|
|
6574
|
-
const toggleMute =
|
|
6574
|
+
const toggleMute = React5.useCallback(() => {
|
|
6575
6575
|
setIsMutedState((prev) => {
|
|
6576
6576
|
const newMuted = !prev;
|
|
6577
6577
|
saveMuteState(newMuted);
|
|
@@ -6588,22 +6588,22 @@ function useVolume({
|
|
|
6588
6588
|
}
|
|
6589
6589
|
function useControls(system, onNotify) {
|
|
6590
6590
|
const defaultControls = getConsoleKeyboardDefaults(system || "SNES");
|
|
6591
|
-
const [controls, setControls] =
|
|
6591
|
+
const [controls, setControls] = React5.useState(() => {
|
|
6592
6592
|
if (typeof window !== "undefined") {
|
|
6593
6593
|
return loadKeyboardMapping(system);
|
|
6594
6594
|
}
|
|
6595
6595
|
return defaultControls;
|
|
6596
6596
|
});
|
|
6597
|
-
|
|
6597
|
+
React5.useEffect(() => {
|
|
6598
6598
|
const loaded = loadKeyboardMapping(system);
|
|
6599
6599
|
setControls(loaded);
|
|
6600
6600
|
}, [system]);
|
|
6601
|
-
const saveControls =
|
|
6601
|
+
const saveControls = React5.useCallback((newControls) => {
|
|
6602
6602
|
setControls(newControls);
|
|
6603
6603
|
saveKeyboardMapping(newControls, system);
|
|
6604
6604
|
onNotify?.("Controls saved", "success");
|
|
6605
6605
|
}, [system, onNotify]);
|
|
6606
|
-
const resetToDefaults =
|
|
6606
|
+
const resetToDefaults = React5.useCallback(() => {
|
|
6607
6607
|
setControls(defaultControls);
|
|
6608
6608
|
saveKeyboardMapping(defaultControls, system);
|
|
6609
6609
|
onNotify?.("Controls reset to defaults", "info");
|
|
@@ -6633,8 +6633,8 @@ function useGameSession(props) {
|
|
|
6633
6633
|
showToast
|
|
6634
6634
|
} = props;
|
|
6635
6635
|
const { controls, saveControls } = useControls(system, showToast);
|
|
6636
|
-
const [gamepadModalOpen, setGamepadModalOpen] =
|
|
6637
|
-
const [controlsModalOpen, setControlsModalOpen] =
|
|
6636
|
+
const [gamepadModalOpen, setGamepadModalOpen] = React5.useState(false);
|
|
6637
|
+
const [controlsModalOpen, setControlsModalOpen] = React5.useState(false);
|
|
6638
6638
|
const { gamepads, connectedCount } = useGamepad({
|
|
6639
6639
|
onConnect: (gamepad) => {
|
|
6640
6640
|
showToast(
|
|
@@ -6661,7 +6661,7 @@ function useGameSession(props) {
|
|
|
6661
6661
|
);
|
|
6662
6662
|
}
|
|
6663
6663
|
});
|
|
6664
|
-
const gamepadBindings =
|
|
6664
|
+
const gamepadBindings = React5.useMemo(() => {
|
|
6665
6665
|
return [];
|
|
6666
6666
|
}, [gamepads.length]);
|
|
6667
6667
|
const nostalgist = useNostalgist({
|
|
@@ -6705,7 +6705,7 @@ function useGameSession(props) {
|
|
|
6705
6705
|
toggleMute: toggleMuteInHook,
|
|
6706
6706
|
prepare
|
|
6707
6707
|
} = nostalgist;
|
|
6708
|
-
|
|
6708
|
+
React5.useEffect(() => {
|
|
6709
6709
|
return () => {
|
|
6710
6710
|
if (status === "running" || status === "paused") {
|
|
6711
6711
|
onSessionEnd?.();
|
|
@@ -6716,8 +6716,8 @@ function useGameSession(props) {
|
|
|
6716
6716
|
setVolume: setVolumeInHook,
|
|
6717
6717
|
toggleMute: toggleMuteInHook
|
|
6718
6718
|
});
|
|
6719
|
-
|
|
6720
|
-
|
|
6719
|
+
React5.useEffect(() => suppressEmulatorWarnings(), []);
|
|
6720
|
+
React5.useEffect(() => {
|
|
6721
6721
|
if (!romUrl || !system || status !== "idle") return;
|
|
6722
6722
|
const checkAndPrepare = async () => {
|
|
6723
6723
|
if (canvasRef.current && canvasRef.current.isConnected) {
|
|
@@ -6729,7 +6729,7 @@ function useGameSession(props) {
|
|
|
6729
6729
|
const rafId = requestAnimationFrame(checkAndPrepare);
|
|
6730
6730
|
return () => cancelAnimationFrame(rafId);
|
|
6731
6731
|
}, [romUrl, system, status, prepare]);
|
|
6732
|
-
const hardcoreRestrictions =
|
|
6732
|
+
const hardcoreRestrictions = React5.useMemo(() => {
|
|
6733
6733
|
const isHardcore = !!retroAchievementsConfig?.hardcore;
|
|
6734
6734
|
return {
|
|
6735
6735
|
isHardcore,
|
|
@@ -6800,17 +6800,17 @@ function useAutoSave({
|
|
|
6800
6800
|
queueRef,
|
|
6801
6801
|
autoSaveInterval = 6e4
|
|
6802
6802
|
}) {
|
|
6803
|
-
const [autoSavePaused, setAutoSavePaused] =
|
|
6804
|
-
const [autoSaveState, setAutoSaveState] =
|
|
6805
|
-
const [autoSaveProgress, setAutoSaveProgress] =
|
|
6806
|
-
const onAutoSaveRef =
|
|
6807
|
-
const nostalgistRef =
|
|
6808
|
-
|
|
6803
|
+
const [autoSavePaused, setAutoSavePaused] = React5.useState(false);
|
|
6804
|
+
const [autoSaveState, setAutoSaveState] = React5.useState("idle");
|
|
6805
|
+
const [autoSaveProgress, setAutoSaveProgress] = React5.useState(0);
|
|
6806
|
+
const onAutoSaveRef = React5.useRef(onAutoSave);
|
|
6807
|
+
const nostalgistRef = React5.useRef(nostalgist);
|
|
6808
|
+
React5.useEffect(() => {
|
|
6809
6809
|
onAutoSaveRef.current = onAutoSave;
|
|
6810
6810
|
nostalgistRef.current = nostalgist;
|
|
6811
6811
|
}, [onAutoSave, nostalgist]);
|
|
6812
|
-
const [loopTrigger, setLoopTrigger] =
|
|
6813
|
-
|
|
6812
|
+
const [loopTrigger, setLoopTrigger] = React5.useState(0);
|
|
6813
|
+
React5.useEffect(() => {
|
|
6814
6814
|
const currentNostalgist = nostalgist;
|
|
6815
6815
|
if (!onAutoSave || !currentNostalgist || currentNostalgist.status !== "running" || autoSavePaused) {
|
|
6816
6816
|
setAutoSaveState("idle");
|
|
@@ -6860,10 +6860,10 @@ function useAutoSave({
|
|
|
6860
6860
|
clearTimeout(saveTimeoutId);
|
|
6861
6861
|
};
|
|
6862
6862
|
}, [nostalgist?.status, autoSavePaused, !!onAutoSave, loopTrigger, autoSaveInterval]);
|
|
6863
|
-
const handleAutoSaveToggle =
|
|
6863
|
+
const handleAutoSaveToggle = React5.useCallback(() => {
|
|
6864
6864
|
setAutoSavePaused((prev) => !prev);
|
|
6865
6865
|
}, []);
|
|
6866
|
-
|
|
6866
|
+
React5.useEffect(() => {
|
|
6867
6867
|
if (!onAutoSave || !nostalgist || nostalgist.status !== "running") return;
|
|
6868
6868
|
const performEmergencySave = async () => {
|
|
6869
6869
|
try {
|
|
@@ -6925,12 +6925,12 @@ function useGameSaves({
|
|
|
6925
6925
|
onDeleteSaveState,
|
|
6926
6926
|
autoSaveInterval
|
|
6927
6927
|
}) {
|
|
6928
|
-
const [saveModalOpen, setSaveModalOpen] =
|
|
6929
|
-
const [saveModalMode, setSaveModalMode] =
|
|
6930
|
-
const [saveSlots, setSaveSlots] =
|
|
6931
|
-
const [isSlotLoading, setIsSlotLoading] =
|
|
6932
|
-
const [actioningSlot, setActioningSlot] =
|
|
6933
|
-
const queueRef =
|
|
6928
|
+
const [saveModalOpen, setSaveModalOpen] = React5.useState(false);
|
|
6929
|
+
const [saveModalMode, setSaveModalMode] = React5.useState("save");
|
|
6930
|
+
const [saveSlots, setSaveSlots] = React5.useState([]);
|
|
6931
|
+
const [isSlotLoading, setIsSlotLoading] = React5.useState(false);
|
|
6932
|
+
const [actioningSlot, setActioningSlot] = React5.useState(null);
|
|
6933
|
+
const queueRef = React5.useRef(new SaveQueue());
|
|
6934
6934
|
const {
|
|
6935
6935
|
autoSaveEnabled,
|
|
6936
6936
|
autoSavePaused,
|
|
@@ -6943,7 +6943,7 @@ function useGameSaves({
|
|
|
6943
6943
|
queueRef,
|
|
6944
6944
|
autoSaveInterval
|
|
6945
6945
|
});
|
|
6946
|
-
const refreshSlots =
|
|
6946
|
+
const refreshSlots = React5.useCallback(async () => {
|
|
6947
6947
|
if (!onGetSaveSlots) return;
|
|
6948
6948
|
setIsSlotLoading(true);
|
|
6949
6949
|
try {
|
|
@@ -7115,8 +7115,8 @@ function useGameCheats({
|
|
|
7115
7115
|
cheats = [],
|
|
7116
7116
|
onToggleCheat
|
|
7117
7117
|
}) {
|
|
7118
|
-
const [cheatsModalOpen, setCheatsModalOpen] =
|
|
7119
|
-
const [activeCheats, setActiveCheats] =
|
|
7118
|
+
const [cheatsModalOpen, setCheatsModalOpen] = React5.useState(false);
|
|
7119
|
+
const [activeCheats, setActiveCheats] = React5.useState(/* @__PURE__ */ new Set());
|
|
7120
7120
|
const handleToggleCheat = (cheatId) => {
|
|
7121
7121
|
if (!nostalgist) return;
|
|
7122
7122
|
const newActiveCheats = new Set(activeCheats);
|
|
@@ -7148,16 +7148,16 @@ function useGameCheats({
|
|
|
7148
7148
|
function useGameRecording({
|
|
7149
7149
|
getCanvasElement
|
|
7150
7150
|
}) {
|
|
7151
|
-
const [isRecording, setIsRecording] =
|
|
7152
|
-
const [isPaused, setIsPaused] =
|
|
7153
|
-
const [recordingDuration, setRecordingDuration] =
|
|
7154
|
-
const mediaRecorderRef =
|
|
7155
|
-
const chunksRef =
|
|
7156
|
-
const startTimeRef =
|
|
7157
|
-
const pausedTimeRef =
|
|
7158
|
-
const durationIntervalRef =
|
|
7151
|
+
const [isRecording, setIsRecording] = React5.useState(false);
|
|
7152
|
+
const [isPaused, setIsPaused] = React5.useState(false);
|
|
7153
|
+
const [recordingDuration, setRecordingDuration] = React5.useState(0);
|
|
7154
|
+
const mediaRecorderRef = React5.useRef(null);
|
|
7155
|
+
const chunksRef = React5.useRef([]);
|
|
7156
|
+
const startTimeRef = React5.useRef(0);
|
|
7157
|
+
const pausedTimeRef = React5.useRef(0);
|
|
7158
|
+
const durationIntervalRef = React5.useRef(null);
|
|
7159
7159
|
const isSupported = typeof MediaRecorder !== "undefined" && MediaRecorder.isTypeSupported("video/webm");
|
|
7160
|
-
const startRecording =
|
|
7160
|
+
const startRecording = React5.useCallback(() => {
|
|
7161
7161
|
const canvas = getCanvasElement();
|
|
7162
7162
|
if (!canvas || !isSupported) {
|
|
7163
7163
|
console.warn("[Recording] Canvas not found or MediaRecorder not supported");
|
|
@@ -7195,7 +7195,7 @@ function useGameRecording({
|
|
|
7195
7195
|
console.error("[Recording] Failed to start:", err);
|
|
7196
7196
|
}
|
|
7197
7197
|
}, [getCanvasElement, isSupported, isPaused]);
|
|
7198
|
-
const stopRecording =
|
|
7198
|
+
const stopRecording = React5.useCallback(async () => {
|
|
7199
7199
|
return new Promise((resolve) => {
|
|
7200
7200
|
const mediaRecorder = mediaRecorderRef.current;
|
|
7201
7201
|
if (!mediaRecorder || mediaRecorder.state === "inactive") {
|
|
@@ -7217,7 +7217,7 @@ function useGameRecording({
|
|
|
7217
7217
|
mediaRecorder.stop();
|
|
7218
7218
|
});
|
|
7219
7219
|
}, []);
|
|
7220
|
-
const pauseRecording =
|
|
7220
|
+
const pauseRecording = React5.useCallback(() => {
|
|
7221
7221
|
const mediaRecorder = mediaRecorderRef.current;
|
|
7222
7222
|
if (mediaRecorder && mediaRecorder.state === "recording") {
|
|
7223
7223
|
mediaRecorder.pause();
|
|
@@ -7226,7 +7226,7 @@ function useGameRecording({
|
|
|
7226
7226
|
console.log("[Recording] Paused");
|
|
7227
7227
|
}
|
|
7228
7228
|
}, []);
|
|
7229
|
-
const resumeRecording =
|
|
7229
|
+
const resumeRecording = React5.useCallback(() => {
|
|
7230
7230
|
const mediaRecorder = mediaRecorderRef.current;
|
|
7231
7231
|
if (mediaRecorder && mediaRecorder.state === "paused") {
|
|
7232
7232
|
pausedTimeRef.current = Date.now() - pausedTimeRef.current;
|
|
@@ -7235,7 +7235,7 @@ function useGameRecording({
|
|
|
7235
7235
|
console.log("[Recording] Resumed");
|
|
7236
7236
|
}
|
|
7237
7237
|
}, []);
|
|
7238
|
-
|
|
7238
|
+
React5.useEffect(() => {
|
|
7239
7239
|
return () => {
|
|
7240
7240
|
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
|
|
7241
7241
|
mediaRecorderRef.current.stop();
|
|
@@ -7409,9 +7409,9 @@ var DEFAULT_SETTINGS = {
|
|
|
7409
7409
|
showInputDisplay: false
|
|
7410
7410
|
};
|
|
7411
7411
|
function usePlayerPersistence(onSettingsChange) {
|
|
7412
|
-
const [settings, setSettings] =
|
|
7413
|
-
const [isLoaded, setIsLoaded] =
|
|
7414
|
-
|
|
7412
|
+
const [settings, setSettings] = React5.useState(DEFAULT_SETTINGS);
|
|
7413
|
+
const [isLoaded, setIsLoaded] = React5.useState(false);
|
|
7414
|
+
React5.useEffect(() => {
|
|
7415
7415
|
try {
|
|
7416
7416
|
const stored = localStorage.getItem(STORAGE_KEY2);
|
|
7417
7417
|
if (stored) {
|
|
@@ -7423,7 +7423,7 @@ function usePlayerPersistence(onSettingsChange) {
|
|
|
7423
7423
|
}
|
|
7424
7424
|
setIsLoaded(true);
|
|
7425
7425
|
}, []);
|
|
7426
|
-
const updateSettings =
|
|
7426
|
+
const updateSettings = React5.useCallback((updates) => {
|
|
7427
7427
|
setSettings((prev) => {
|
|
7428
7428
|
const next = { ...prev, ...updates };
|
|
7429
7429
|
try {
|
|
@@ -7440,10 +7440,10 @@ function usePlayerPersistence(onSettingsChange) {
|
|
|
7440
7440
|
updateSettings
|
|
7441
7441
|
};
|
|
7442
7442
|
}
|
|
7443
|
-
var GamePlayer =
|
|
7443
|
+
var GamePlayer = React5.memo(function GamePlayer2(props) {
|
|
7444
7444
|
const { settings, updateSettings, isLoaded: settingsLoaded } = usePlayerPersistence();
|
|
7445
|
-
const [biosModalOpen, setBiosModalOpen] =
|
|
7446
|
-
const [showShortcutsModal, setShowShortcutsModal] =
|
|
7445
|
+
const [biosModalOpen, setBiosModalOpen] = React5.useState(false);
|
|
7446
|
+
const [showShortcutsModal, setShowShortcutsModal] = React5.useState(false);
|
|
7447
7447
|
const effectiveShader = props.shader !== void 0 ? props.shader : settings.shader;
|
|
7448
7448
|
const {
|
|
7449
7449
|
// Refs
|
|
@@ -7539,65 +7539,65 @@ var GamePlayer = React3.memo(function GamePlayer2(props) {
|
|
|
7539
7539
|
status,
|
|
7540
7540
|
isPerformanceMode
|
|
7541
7541
|
} = nostalgist;
|
|
7542
|
-
|
|
7542
|
+
React5.useEffect(() => {
|
|
7543
7543
|
if (settingsLoaded) {
|
|
7544
7544
|
setVolume(settings.volume);
|
|
7545
7545
|
if (muted !== settings.muted) toggleMute();
|
|
7546
7546
|
}
|
|
7547
7547
|
}, [settingsLoaded]);
|
|
7548
7548
|
const { system, systemColor = "#00FF41", cheats = [], onExit } = props;
|
|
7549
|
-
const handlePauseToggle =
|
|
7549
|
+
const handlePauseToggle = React5.useCallback(() => {
|
|
7550
7550
|
status === "ready" ? start() : togglePause();
|
|
7551
7551
|
}, [status, start, togglePause]);
|
|
7552
|
-
const handleScreenshot =
|
|
7552
|
+
const handleScreenshot = React5.useCallback(async () => {
|
|
7553
7553
|
const result = await screenshot();
|
|
7554
7554
|
if (result && props.onScreenshotCaptured) {
|
|
7555
7555
|
props.onScreenshotCaptured(result);
|
|
7556
7556
|
}
|
|
7557
7557
|
}, [screenshot, props.onScreenshotCaptured]);
|
|
7558
|
-
const handleShowControls =
|
|
7558
|
+
const handleShowControls = React5.useCallback(() => {
|
|
7559
7559
|
pause();
|
|
7560
7560
|
setControlsModalOpen(true);
|
|
7561
7561
|
}, [pause, setControlsModalOpen]);
|
|
7562
|
-
const handleShowCheats =
|
|
7562
|
+
const handleShowCheats = React5.useCallback(() => {
|
|
7563
7563
|
pause();
|
|
7564
7564
|
setCheatsModalOpen(true);
|
|
7565
7565
|
}, [pause, setCheatsModalOpen]);
|
|
7566
|
-
const handleShowRA =
|
|
7566
|
+
const handleShowRA = React5.useCallback(() => {
|
|
7567
7567
|
pause();
|
|
7568
7568
|
setRaSidebarOpen(true);
|
|
7569
7569
|
}, [pause, setRaSidebarOpen]);
|
|
7570
|
-
const handleShowGamepadSettings =
|
|
7570
|
+
const handleShowGamepadSettings = React5.useCallback(() => {
|
|
7571
7571
|
pause();
|
|
7572
7572
|
setGamepadModalOpen(true);
|
|
7573
7573
|
}, [pause, setGamepadModalOpen]);
|
|
7574
|
-
const handleExitClick =
|
|
7574
|
+
const handleExitClick = React5.useCallback(() => {
|
|
7575
7575
|
onExit?.();
|
|
7576
7576
|
}, [onExit]);
|
|
7577
|
-
const handleBiosSelection =
|
|
7577
|
+
const handleBiosSelection = React5.useCallback(() => {
|
|
7578
7578
|
setBiosModalOpen(true);
|
|
7579
7579
|
}, [setBiosModalOpen]);
|
|
7580
|
-
const handleVolumeChange =
|
|
7580
|
+
const handleVolumeChange = React5.useCallback((val) => {
|
|
7581
7581
|
setVolume(val);
|
|
7582
7582
|
updateSettings({ volume: val });
|
|
7583
7583
|
}, [setVolume, updateSettings]);
|
|
7584
|
-
const handleToggleMute =
|
|
7584
|
+
const handleToggleMute = React5.useCallback(() => {
|
|
7585
7585
|
toggleMute();
|
|
7586
7586
|
updateSettings({ muted: !muted });
|
|
7587
7587
|
}, [toggleMute, updateSettings, muted]);
|
|
7588
|
-
const handleShaderChange =
|
|
7588
|
+
const handleShaderChange = React5.useCallback((newShader, requiresRestart) => {
|
|
7589
7589
|
updateSettings({ shader: newShader });
|
|
7590
7590
|
if (props.onShaderChange) {
|
|
7591
7591
|
props.onShaderChange(newShader, requiresRestart);
|
|
7592
7592
|
}
|
|
7593
7593
|
}, [updateSettings, props.onShaderChange]);
|
|
7594
|
-
const handleTogglePerformanceOverlay =
|
|
7594
|
+
const handleTogglePerformanceOverlay = React5.useCallback(() => {
|
|
7595
7595
|
updateSettings({ showPerformanceOverlay: !settings.showPerformanceOverlay });
|
|
7596
7596
|
}, [updateSettings, settings.showPerformanceOverlay]);
|
|
7597
|
-
const handleToggleInputDisplay =
|
|
7597
|
+
const handleToggleInputDisplay = React5.useCallback(() => {
|
|
7598
7598
|
updateSettings({ showInputDisplay: !settings.showInputDisplay });
|
|
7599
7599
|
}, [updateSettings, settings.showInputDisplay]);
|
|
7600
|
-
const handleToggleRecording =
|
|
7600
|
+
const handleToggleRecording = React5.useCallback(async () => {
|
|
7601
7601
|
if (!recordingSupported) {
|
|
7602
7602
|
console.warn("[Recording] Not supported in this browser");
|
|
7603
7603
|
return;
|
|
@@ -7618,14 +7618,14 @@ var GamePlayer = React3.memo(function GamePlayer2(props) {
|
|
|
7618
7618
|
startRecording();
|
|
7619
7619
|
}
|
|
7620
7620
|
}, [isRecording, recordingSupported, startRecording, stopRecording]);
|
|
7621
|
-
const handleToggleShortcuts =
|
|
7621
|
+
const handleToggleShortcuts = React5.useCallback(() => {
|
|
7622
7622
|
setShowShortcutsModal((prev) => {
|
|
7623
7623
|
if (!prev) pause();
|
|
7624
7624
|
else resume();
|
|
7625
7625
|
return !prev;
|
|
7626
7626
|
});
|
|
7627
7627
|
}, [pause, resume]);
|
|
7628
|
-
|
|
7628
|
+
React5.useEffect(() => {
|
|
7629
7629
|
const handleKeyDown = (e) => {
|
|
7630
7630
|
if (e.key === "F1") {
|
|
7631
7631
|
e.preventDefault();
|
|
@@ -7677,7 +7677,7 @@ var GamePlayer = React3.memo(function GamePlayer2(props) {
|
|
|
7677
7677
|
onSelectBios: props.onSelectBios ? handleBiosSelection : void 0
|
|
7678
7678
|
}
|
|
7679
7679
|
),
|
|
7680
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7680
|
+
isFullscreen2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
7681
7681
|
VirtualController,
|
|
7682
7682
|
{
|
|
7683
7683
|
system,
|
|
@@ -7870,9 +7870,9 @@ function AchievementPopup({
|
|
|
7870
7870
|
onDismiss,
|
|
7871
7871
|
autoDismissMs = 5e3
|
|
7872
7872
|
}) {
|
|
7873
|
-
const [isVisible, setIsVisible] =
|
|
7874
|
-
const [isExiting, setIsExiting] =
|
|
7875
|
-
|
|
7873
|
+
const [isVisible, setIsVisible] = React5.useState(false);
|
|
7874
|
+
const [isExiting, setIsExiting] = React5.useState(false);
|
|
7875
|
+
React5.useEffect(() => {
|
|
7876
7876
|
requestAnimationFrame(() => {
|
|
7877
7877
|
setIsVisible(true);
|
|
7878
7878
|
});
|
|
@@ -7949,15 +7949,15 @@ var SHADER_PRESETS = [
|
|
|
7949
7949
|
{ id: "handheld/lcd-grid-v2", name: "LCD Grid", description: "Game Boy style LCD effect" },
|
|
7950
7950
|
{ id: "scanlines", name: "Scanlines", description: "Simple horizontal scanlines" }
|
|
7951
7951
|
];
|
|
7952
|
-
var ShaderSelector =
|
|
7952
|
+
var ShaderSelector = React5.memo(function ShaderSelector2({
|
|
7953
7953
|
currentShader,
|
|
7954
7954
|
onShaderChange,
|
|
7955
7955
|
disabled = false,
|
|
7956
7956
|
systemColor = "#00FF41"
|
|
7957
7957
|
}) {
|
|
7958
|
-
const [isOpen, setIsOpen] =
|
|
7959
|
-
const dropdownRef =
|
|
7960
|
-
|
|
7958
|
+
const [isOpen, setIsOpen] = React5.useState(false);
|
|
7959
|
+
const dropdownRef = React5.useRef(null);
|
|
7960
|
+
React5.useEffect(() => {
|
|
7961
7961
|
const handleClickOutside = (e) => {
|
|
7962
7962
|
if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
|
|
7963
7963
|
setIsOpen(false);
|
|
@@ -8031,11 +8031,11 @@ var SHORTCUTS2 = [
|
|
|
8031
8031
|
{ key: "F5", description: "Record" },
|
|
8032
8032
|
{ key: "F9", description: "Mute" }
|
|
8033
8033
|
];
|
|
8034
|
-
var ShortcutsReference =
|
|
8034
|
+
var ShortcutsReference = React5.memo(function ShortcutsReference2({
|
|
8035
8035
|
systemColor = "#00FF41",
|
|
8036
8036
|
isExpanded: initialExpanded = false
|
|
8037
8037
|
}) {
|
|
8038
|
-
const [isExpanded, setIsExpanded] =
|
|
8038
|
+
const [isExpanded, setIsExpanded] = React5.useState(initialExpanded);
|
|
8039
8039
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8040
8040
|
"div",
|
|
8041
8041
|
{
|