koin.js 1.0.12 → 1.0.14
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 +257 -130
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +257 -130
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2276,7 +2276,8 @@ var SIX_BUTTON_LAYOUT = {
|
|
|
2276
2276
|
{ type: "y", label: "A", x: 72, y: 64, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true },
|
|
2277
2277
|
{ type: "b", label: "B", x: 82, y: 60, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true },
|
|
2278
2278
|
{ type: "a", label: "C", x: 92, y: 56, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true },
|
|
2279
|
-
{ type: "
|
|
2279
|
+
{ type: "select", label: "SELECT", x: SELECT_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" },
|
|
2280
|
+
{ type: "start", label: "START", x: START_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" }
|
|
2280
2281
|
]
|
|
2281
2282
|
};
|
|
2282
2283
|
var SATURN_LAYOUT = {
|
|
@@ -2295,7 +2296,8 @@ var SATURN_LAYOUT = {
|
|
|
2295
2296
|
// Triggers (L2/R2 for Saturn L/R)
|
|
2296
2297
|
{ type: "l2", label: "L", x: 8, y: 20, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2297
2298
|
{ type: "r2", label: "R", x: 92, y: 20, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2298
|
-
{ type: "
|
|
2299
|
+
{ type: "select", label: "SELECT", x: SELECT_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" },
|
|
2300
|
+
{ type: "start", label: "START", x: START_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" }
|
|
2299
2301
|
]
|
|
2300
2302
|
};
|
|
2301
2303
|
var NEOGEO_LAYOUT = {
|
|
@@ -2344,9 +2346,10 @@ var N64_LAYOUT = {
|
|
|
2344
2346
|
// Shoulders
|
|
2345
2347
|
{ type: "l", label: "L", x: 8, y: 20, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2346
2348
|
{ type: "r", label: "R", x: 92, y: 20, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2347
|
-
// Z trigger (use
|
|
2348
|
-
{ type: "
|
|
2349
|
-
{ type: "
|
|
2349
|
+
// Z trigger (use l3 button for Z trigger)
|
|
2350
|
+
{ type: "l3", label: "Z", x: 8, y: 35, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2351
|
+
{ type: "select", label: "SELECT", x: SELECT_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" },
|
|
2352
|
+
{ type: "start", label: "START", x: START_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" }
|
|
2350
2353
|
]
|
|
2351
2354
|
};
|
|
2352
2355
|
var DREAMCAST_LAYOUT = {
|
|
@@ -2361,7 +2364,8 @@ var DREAMCAST_LAYOUT = {
|
|
|
2361
2364
|
// Triggers
|
|
2362
2365
|
{ type: "l", label: "L", x: 8, y: 20, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2363
2366
|
{ type: "r", label: "R", x: 92, y: 20, size: BUTTON_MEDIUM, showInPortrait: true, showInLandscape: true, shape: "rect" },
|
|
2364
|
-
{ type: "
|
|
2367
|
+
{ type: "select", label: "SELECT", x: SELECT_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" },
|
|
2368
|
+
{ type: "start", label: "START", x: START_X, y: START_SELECT_Y, size: BUTTON_SMALL, showInPortrait: true, showInLandscape: true, shape: "pill" }
|
|
2365
2369
|
]
|
|
2366
2370
|
};
|
|
2367
2371
|
function getLayoutForSystem(system) {
|
|
@@ -2383,26 +2387,49 @@ function getLayoutForSystem(system) {
|
|
|
2383
2387
|
if (s.includes("ATARI")) return TWO_BUTTON_LAYOUT;
|
|
2384
2388
|
return TWO_BUTTON_LAYOUT;
|
|
2385
2389
|
}
|
|
2386
|
-
|
|
2390
|
+
|
|
2391
|
+
// src/components/VirtualController/utils/dragConstraints.ts
|
|
2392
|
+
function constrainToViewport({
|
|
2393
|
+
newXPercent,
|
|
2394
|
+
newYPercent,
|
|
2395
|
+
elementSize,
|
|
2396
|
+
containerWidth,
|
|
2397
|
+
containerHeight
|
|
2398
|
+
}) {
|
|
2399
|
+
const xMargin = elementSize / 2 / containerWidth * 100;
|
|
2400
|
+
const yMargin = elementSize / 2 / containerHeight * 100;
|
|
2401
|
+
return {
|
|
2402
|
+
x: Math.max(xMargin, Math.min(100 - xMargin, newXPercent)),
|
|
2403
|
+
y: Math.max(yMargin, Math.min(100 - yMargin, newYPercent))
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
// src/components/VirtualController/hooks/useDrag.ts
|
|
2408
|
+
var DEFAULT_HOLD_DELAY = 350;
|
|
2409
|
+
var DEFAULT_CENTER_THRESHOLD = 0.4;
|
|
2387
2410
|
var DRAG_MOVE_THRESHOLD = 10;
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
buttonType,
|
|
2391
|
-
isSystemButton,
|
|
2392
|
-
buttonSize,
|
|
2411
|
+
function useDrag({
|
|
2412
|
+
elementSize,
|
|
2393
2413
|
displayX,
|
|
2394
2414
|
displayY,
|
|
2395
2415
|
containerWidth,
|
|
2396
2416
|
containerHeight,
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2417
|
+
onPositionChange,
|
|
2418
|
+
holdDelay = DEFAULT_HOLD_DELAY,
|
|
2419
|
+
centerThreshold = DEFAULT_CENTER_THRESHOLD,
|
|
2420
|
+
onDragStart,
|
|
2421
|
+
onDragEnd
|
|
2401
2422
|
}) {
|
|
2423
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
2402
2424
|
const isDraggingRef = useRef(false);
|
|
2403
|
-
const dragStartRef = useRef({ x: 0, y: 0 });
|
|
2404
2425
|
const dragTimerRef = useRef(null);
|
|
2405
2426
|
const touchStartPosRef = useRef({ x: 0, y: 0 });
|
|
2427
|
+
const dragStartRef = useRef({
|
|
2428
|
+
elementX: 0,
|
|
2429
|
+
elementY: 0,
|
|
2430
|
+
touchX: 0,
|
|
2431
|
+
touchY: 0
|
|
2432
|
+
});
|
|
2406
2433
|
const clearDragTimer = useCallback(() => {
|
|
2407
2434
|
if (dragTimerRef.current) {
|
|
2408
2435
|
clearTimeout(dragTimerRef.current);
|
|
@@ -2412,23 +2439,129 @@ function useTouchHandlers({
|
|
|
2412
2439
|
const startDragging = useCallback(
|
|
2413
2440
|
(touchX, touchY) => {
|
|
2414
2441
|
isDraggingRef.current = true;
|
|
2442
|
+
setIsDragging(true);
|
|
2415
2443
|
dragStartRef.current = {
|
|
2416
|
-
|
|
2417
|
-
|
|
2444
|
+
elementX: displayX,
|
|
2445
|
+
elementY: displayY,
|
|
2446
|
+
touchX,
|
|
2447
|
+
touchY
|
|
2418
2448
|
};
|
|
2419
2449
|
if (navigator.vibrate) {
|
|
2420
2450
|
navigator.vibrate([10, 30, 10]);
|
|
2421
2451
|
}
|
|
2452
|
+
onDragStart?.();
|
|
2453
|
+
},
|
|
2454
|
+
[displayX, displayY, onDragStart]
|
|
2455
|
+
);
|
|
2456
|
+
const checkDragStart = useCallback(
|
|
2457
|
+
(touchX, touchY, elementRect) => {
|
|
2458
|
+
if (!onPositionChange) return false;
|
|
2459
|
+
touchStartPosRef.current = { x: touchX, y: touchY };
|
|
2460
|
+
const centerX = elementRect.left + elementRect.width / 2;
|
|
2461
|
+
const centerY = elementRect.top + elementRect.height / 2;
|
|
2462
|
+
const distFromCenter = Math.sqrt(
|
|
2463
|
+
Math.pow(touchX - centerX, 2) + Math.pow(touchY - centerY, 2)
|
|
2464
|
+
);
|
|
2465
|
+
const centerRadius = elementSize * centerThreshold;
|
|
2466
|
+
if (distFromCenter < centerRadius) {
|
|
2467
|
+
dragTimerRef.current = setTimeout(() => {
|
|
2468
|
+
if (!isDraggingRef.current) {
|
|
2469
|
+
startDragging(touchX, touchY);
|
|
2470
|
+
}
|
|
2471
|
+
}, holdDelay);
|
|
2472
|
+
return true;
|
|
2473
|
+
}
|
|
2474
|
+
return false;
|
|
2475
|
+
},
|
|
2476
|
+
[onPositionChange, elementSize, centerThreshold, holdDelay, startDragging]
|
|
2477
|
+
);
|
|
2478
|
+
const checkMoveThreshold = useCallback(
|
|
2479
|
+
(touchX, touchY) => {
|
|
2480
|
+
if (!onPositionChange || isDraggingRef.current) return false;
|
|
2481
|
+
const moveDistance = Math.sqrt(
|
|
2482
|
+
Math.pow(touchX - touchStartPosRef.current.x, 2) + Math.pow(touchY - touchStartPosRef.current.y, 2)
|
|
2483
|
+
);
|
|
2484
|
+
if (moveDistance > DRAG_MOVE_THRESHOLD) {
|
|
2485
|
+
clearDragTimer();
|
|
2486
|
+
startDragging(touchX, touchY);
|
|
2487
|
+
return true;
|
|
2488
|
+
}
|
|
2489
|
+
return false;
|
|
2490
|
+
},
|
|
2491
|
+
[onPositionChange, clearDragTimer, startDragging]
|
|
2492
|
+
);
|
|
2493
|
+
const handleDragMove = useCallback(
|
|
2494
|
+
(touchX, touchY) => {
|
|
2495
|
+
if (!isDraggingRef.current || !onPositionChange) return;
|
|
2496
|
+
const deltaX = touchX - dragStartRef.current.touchX;
|
|
2497
|
+
const deltaY = touchY - dragStartRef.current.touchY;
|
|
2498
|
+
const newXPercent = dragStartRef.current.elementX + deltaX / containerWidth * 100;
|
|
2499
|
+
const newYPercent = dragStartRef.current.elementY + deltaY / containerHeight * 100;
|
|
2500
|
+
const constrained = constrainToViewport({
|
|
2501
|
+
newXPercent,
|
|
2502
|
+
newYPercent,
|
|
2503
|
+
elementSize,
|
|
2504
|
+
containerWidth,
|
|
2505
|
+
containerHeight
|
|
2506
|
+
});
|
|
2507
|
+
onPositionChange(constrained.x, constrained.y);
|
|
2508
|
+
},
|
|
2509
|
+
[onPositionChange, containerWidth, containerHeight, elementSize]
|
|
2510
|
+
);
|
|
2511
|
+
const handleDragEnd = useCallback(() => {
|
|
2512
|
+
clearDragTimer();
|
|
2513
|
+
if (isDraggingRef.current) {
|
|
2514
|
+
isDraggingRef.current = false;
|
|
2515
|
+
setIsDragging(false);
|
|
2516
|
+
onDragEnd?.();
|
|
2517
|
+
}
|
|
2518
|
+
}, [clearDragTimer, onDragEnd]);
|
|
2519
|
+
return {
|
|
2520
|
+
isDragging,
|
|
2521
|
+
checkDragStart,
|
|
2522
|
+
handleDragMove,
|
|
2523
|
+
handleDragEnd,
|
|
2524
|
+
clearDragTimer,
|
|
2525
|
+
checkMoveThreshold
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
// src/components/VirtualController/hooks/useTouchHandlers.ts
|
|
2530
|
+
function useTouchHandlers({
|
|
2531
|
+
buttonType,
|
|
2532
|
+
isSystemButton,
|
|
2533
|
+
buttonSize,
|
|
2534
|
+
displayX,
|
|
2535
|
+
displayY,
|
|
2536
|
+
containerWidth,
|
|
2537
|
+
containerHeight,
|
|
2538
|
+
onPress,
|
|
2539
|
+
onPressDown,
|
|
2540
|
+
onRelease,
|
|
2541
|
+
onPositionChange
|
|
2542
|
+
}) {
|
|
2543
|
+
const isDraggingRef = useRef(false);
|
|
2544
|
+
const drag = useDrag({
|
|
2545
|
+
elementSize: buttonSize,
|
|
2546
|
+
displayX,
|
|
2547
|
+
displayY,
|
|
2548
|
+
containerWidth,
|
|
2549
|
+
containerHeight,
|
|
2550
|
+
onPositionChange,
|
|
2551
|
+
centerThreshold: 0.4,
|
|
2552
|
+
onDragStart: () => {
|
|
2553
|
+
isDraggingRef.current = true;
|
|
2422
2554
|
if (!isSystemButton) {
|
|
2423
2555
|
onRelease(buttonType);
|
|
2424
2556
|
}
|
|
2425
2557
|
},
|
|
2426
|
-
|
|
2427
|
-
|
|
2558
|
+
onDragEnd: () => {
|
|
2559
|
+
isDraggingRef.current = false;
|
|
2560
|
+
}
|
|
2561
|
+
});
|
|
2428
2562
|
const handleTouchStart = useCallback(
|
|
2429
2563
|
(e) => {
|
|
2430
2564
|
const touch = e.touches[0];
|
|
2431
|
-
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY };
|
|
2432
2565
|
e.preventDefault();
|
|
2433
2566
|
e.stopPropagation();
|
|
2434
2567
|
if (navigator.vibrate) {
|
|
@@ -2443,57 +2576,32 @@ function useTouchHandlers({
|
|
|
2443
2576
|
const target = e.currentTarget;
|
|
2444
2577
|
if (!target) return;
|
|
2445
2578
|
const rect = target.getBoundingClientRect();
|
|
2446
|
-
|
|
2447
|
-
const centerY = rect.top + rect.height / 2;
|
|
2448
|
-
const distance = Math.sqrt(
|
|
2449
|
-
Math.pow(touch.clientX - centerX, 2) + Math.pow(touch.clientY - centerY, 2)
|
|
2450
|
-
);
|
|
2451
|
-
const dragThreshold = buttonSize * DRAG_CENTER_THRESHOLD;
|
|
2452
|
-
if (distance < dragThreshold) {
|
|
2453
|
-
dragTimerRef.current = setTimeout(() => {
|
|
2454
|
-
if (!isDraggingRef.current) {
|
|
2455
|
-
startDragging(touch.clientX, touch.clientY);
|
|
2456
|
-
}
|
|
2457
|
-
}, DRAG_HOLD_DELAY);
|
|
2458
|
-
}
|
|
2579
|
+
drag.checkDragStart(touch.clientX, touch.clientY, rect);
|
|
2459
2580
|
}
|
|
2460
2581
|
},
|
|
2461
|
-
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange,
|
|
2582
|
+
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange, drag]
|
|
2462
2583
|
);
|
|
2463
2584
|
const handleTouchMove = useCallback(
|
|
2464
2585
|
(e) => {
|
|
2465
2586
|
const touch = e.touches[0];
|
|
2466
2587
|
if (onPositionChange && !isDraggingRef.current) {
|
|
2467
|
-
|
|
2468
|
-
Math.pow(touch.clientX - touchStartPosRef.current.x, 2) + Math.pow(touch.clientY - touchStartPosRef.current.y, 2)
|
|
2469
|
-
);
|
|
2470
|
-
if (moveDistance > DRAG_MOVE_THRESHOLD) {
|
|
2471
|
-
clearDragTimer();
|
|
2472
|
-
startDragging(touch.clientX, touch.clientY);
|
|
2473
|
-
}
|
|
2588
|
+
drag.checkMoveThreshold(touch.clientX, touch.clientY);
|
|
2474
2589
|
}
|
|
2475
|
-
if (isDraggingRef.current
|
|
2590
|
+
if (isDraggingRef.current) {
|
|
2476
2591
|
e.preventDefault();
|
|
2477
2592
|
e.stopPropagation();
|
|
2478
|
-
|
|
2479
|
-
const newY = touch.clientY - dragStartRef.current.y;
|
|
2480
|
-
const newXPercent = newX / containerWidth * 100;
|
|
2481
|
-
const newYPercent = newY / containerHeight * 100;
|
|
2482
|
-
const margin = buttonSize / 2 / Math.min(containerWidth, containerHeight) * 100;
|
|
2483
|
-
const constrainedX = Math.max(margin, Math.min(100 - margin, newXPercent));
|
|
2484
|
-
const constrainedY = Math.max(margin, Math.min(100 - margin, newYPercent));
|
|
2485
|
-
onPositionChange(constrainedX, constrainedY);
|
|
2593
|
+
drag.handleDragMove(touch.clientX, touch.clientY);
|
|
2486
2594
|
}
|
|
2487
2595
|
},
|
|
2488
|
-
[onPositionChange,
|
|
2596
|
+
[onPositionChange, drag]
|
|
2489
2597
|
);
|
|
2490
2598
|
const handleTouchEnd = useCallback(
|
|
2491
2599
|
(e) => {
|
|
2492
|
-
clearDragTimer();
|
|
2600
|
+
drag.clearDragTimer();
|
|
2493
2601
|
if (isDraggingRef.current) {
|
|
2494
2602
|
e.preventDefault();
|
|
2495
2603
|
e.stopPropagation();
|
|
2496
|
-
|
|
2604
|
+
drag.handleDragEnd();
|
|
2497
2605
|
return;
|
|
2498
2606
|
}
|
|
2499
2607
|
e.preventDefault();
|
|
@@ -2502,15 +2610,15 @@ function useTouchHandlers({
|
|
|
2502
2610
|
onRelease(buttonType);
|
|
2503
2611
|
}
|
|
2504
2612
|
},
|
|
2505
|
-
[
|
|
2613
|
+
[drag, isSystemButton, buttonType, onRelease]
|
|
2506
2614
|
);
|
|
2507
2615
|
const handleTouchCancel = useCallback(
|
|
2508
2616
|
(e) => {
|
|
2509
|
-
clearDragTimer();
|
|
2617
|
+
drag.clearDragTimer();
|
|
2510
2618
|
if (isDraggingRef.current) {
|
|
2511
2619
|
e.preventDefault();
|
|
2512
2620
|
e.stopPropagation();
|
|
2513
|
-
|
|
2621
|
+
drag.handleDragEnd();
|
|
2514
2622
|
return;
|
|
2515
2623
|
}
|
|
2516
2624
|
e.preventDefault();
|
|
@@ -2519,11 +2627,11 @@ function useTouchHandlers({
|
|
|
2519
2627
|
onRelease(buttonType);
|
|
2520
2628
|
}
|
|
2521
2629
|
},
|
|
2522
|
-
[
|
|
2630
|
+
[drag, isSystemButton, buttonType, onRelease]
|
|
2523
2631
|
);
|
|
2524
2632
|
const cleanup = useCallback(() => {
|
|
2525
|
-
clearDragTimer();
|
|
2526
|
-
}, [
|
|
2633
|
+
drag.clearDragTimer();
|
|
2634
|
+
}, [drag]);
|
|
2527
2635
|
return {
|
|
2528
2636
|
handleTouchStart,
|
|
2529
2637
|
handleTouchMove,
|
|
@@ -3379,7 +3487,6 @@ function dispatchKeyboardEvent(type, code) {
|
|
|
3379
3487
|
canvas.dispatchEvent(event);
|
|
3380
3488
|
return true;
|
|
3381
3489
|
}
|
|
3382
|
-
var DRAG_HOLD_DELAY2 = 350;
|
|
3383
3490
|
var CENTER_TOUCH_RADIUS = 0.25;
|
|
3384
3491
|
var Dpad = React2.memo(function Dpad2({
|
|
3385
3492
|
size = 180,
|
|
@@ -3396,10 +3503,6 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3396
3503
|
const dpadRef = useRef(null);
|
|
3397
3504
|
const activeTouchRef = useRef(null);
|
|
3398
3505
|
const activeDirectionsRef = useRef(/* @__PURE__ */ new Set());
|
|
3399
|
-
const [isDragging, setIsDragging] = useState(false);
|
|
3400
|
-
const dragTimerRef = useRef(null);
|
|
3401
|
-
const dragStartRef = useRef({ x: 0, y: 0, touchX: 0, touchY: 0 });
|
|
3402
|
-
const touchStartPosRef = useRef({ x: 0, y: 0, time: 0 });
|
|
3403
3506
|
const upPathRef = useRef(null);
|
|
3404
3507
|
const downPathRef = useRef(null);
|
|
3405
3508
|
const leftPathRef = useRef(null);
|
|
@@ -3407,6 +3510,13 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3407
3510
|
const centerCircleRef = useRef(null);
|
|
3408
3511
|
const displayX = customPosition ? customPosition.x : x;
|
|
3409
3512
|
const displayY = customPosition ? customPosition.y : y;
|
|
3513
|
+
const releaseAllDirections = useCallback((getKeyCode2) => {
|
|
3514
|
+
activeDirectionsRef.current.forEach((dir) => {
|
|
3515
|
+
const keyCode = getKeyCode2(dir);
|
|
3516
|
+
if (keyCode) dispatchKeyboardEvent("keyup", keyCode);
|
|
3517
|
+
});
|
|
3518
|
+
activeDirectionsRef.current = /* @__PURE__ */ new Set();
|
|
3519
|
+
}, []);
|
|
3410
3520
|
const getKeyCode = useCallback((direction) => {
|
|
3411
3521
|
if (!controls) {
|
|
3412
3522
|
const defaults = {
|
|
@@ -3419,6 +3529,19 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3419
3529
|
}
|
|
3420
3530
|
return controls[direction] || "";
|
|
3421
3531
|
}, [controls]);
|
|
3532
|
+
const drag = useDrag({
|
|
3533
|
+
elementSize: size,
|
|
3534
|
+
displayX,
|
|
3535
|
+
displayY,
|
|
3536
|
+
containerWidth,
|
|
3537
|
+
containerHeight,
|
|
3538
|
+
onPositionChange,
|
|
3539
|
+
centerThreshold: CENTER_TOUCH_RADIUS,
|
|
3540
|
+
onDragStart: () => {
|
|
3541
|
+
releaseAllDirections(getKeyCode);
|
|
3542
|
+
updateVisuals(/* @__PURE__ */ new Set());
|
|
3543
|
+
}
|
|
3544
|
+
});
|
|
3422
3545
|
const getDirectionsFromTouch = useCallback((touchX, touchY, rect) => {
|
|
3423
3546
|
const centerX = rect.left + rect.width / 2;
|
|
3424
3547
|
const centerY = rect.top + rect.height / 2;
|
|
@@ -3480,51 +3603,20 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3480
3603
|
activeDirectionsRef.current = newDirections;
|
|
3481
3604
|
updateVisuals(newDirections);
|
|
3482
3605
|
}, [getKeyCode, updateVisuals]);
|
|
3483
|
-
const clearDragTimer = useCallback(() => {
|
|
3484
|
-
if (dragTimerRef.current) {
|
|
3485
|
-
clearTimeout(dragTimerRef.current);
|
|
3486
|
-
dragTimerRef.current = null;
|
|
3487
|
-
}
|
|
3488
|
-
}, []);
|
|
3489
|
-
const startDragging = useCallback((touchX, touchY) => {
|
|
3490
|
-
setIsDragging(true);
|
|
3491
|
-
dragStartRef.current = {
|
|
3492
|
-
x: displayX,
|
|
3493
|
-
y: displayY,
|
|
3494
|
-
touchX,
|
|
3495
|
-
touchY
|
|
3496
|
-
};
|
|
3497
|
-
activeDirectionsRef.current.forEach((dir) => {
|
|
3498
|
-
const keyCode = getKeyCode(dir);
|
|
3499
|
-
if (keyCode) dispatchKeyboardEvent("keyup", keyCode);
|
|
3500
|
-
});
|
|
3501
|
-
activeDirectionsRef.current = /* @__PURE__ */ new Set();
|
|
3502
|
-
updateVisuals(/* @__PURE__ */ new Set());
|
|
3503
|
-
if (navigator.vibrate) navigator.vibrate([10, 30, 10]);
|
|
3504
|
-
}, [displayX, displayY, getKeyCode, updateVisuals]);
|
|
3505
3606
|
const handleTouchStart = useCallback((e) => {
|
|
3506
3607
|
e.preventDefault();
|
|
3507
3608
|
if (activeTouchRef.current !== null) return;
|
|
3508
3609
|
const touch = e.changedTouches[0];
|
|
3509
3610
|
activeTouchRef.current = touch.identifier;
|
|
3510
|
-
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
|
|
3511
3611
|
const rect = dpadRef.current?.getBoundingClientRect();
|
|
3512
3612
|
if (!rect) return;
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
const distFromCenter = Math.sqrt(
|
|
3516
|
-
Math.pow(touch.clientX - centerX, 2) + Math.pow(touch.clientY - centerY, 2)
|
|
3517
|
-
);
|
|
3518
|
-
const centerRadius = size * CENTER_TOUCH_RADIUS;
|
|
3519
|
-
if (distFromCenter < centerRadius && onPositionChange) {
|
|
3520
|
-
dragTimerRef.current = setTimeout(() => {
|
|
3521
|
-
startDragging(touch.clientX, touch.clientY);
|
|
3522
|
-
}, DRAG_HOLD_DELAY2);
|
|
3613
|
+
if (onPositionChange) {
|
|
3614
|
+
drag.checkDragStart(touch.clientX, touch.clientY, rect);
|
|
3523
3615
|
}
|
|
3524
|
-
if (!isDragging) {
|
|
3616
|
+
if (!drag.isDragging) {
|
|
3525
3617
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
3526
3618
|
}
|
|
3527
|
-
}, [getDirectionsFromTouch, updateDirections,
|
|
3619
|
+
}, [getDirectionsFromTouch, updateDirections, onPositionChange, drag]);
|
|
3528
3620
|
const handleTouchMove = useCallback((e) => {
|
|
3529
3621
|
e.preventDefault();
|
|
3530
3622
|
let touch = null;
|
|
@@ -3535,31 +3627,19 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3535
3627
|
}
|
|
3536
3628
|
}
|
|
3537
3629
|
if (!touch) return;
|
|
3538
|
-
if (isDragging
|
|
3539
|
-
|
|
3540
|
-
const deltaY = touch.clientY - dragStartRef.current.touchY;
|
|
3541
|
-
const newXPercent = dragStartRef.current.x + deltaX / containerWidth * 100;
|
|
3542
|
-
const newYPercent = dragStartRef.current.y + deltaY / containerHeight * 100;
|
|
3543
|
-
const margin = size / 2 / Math.min(containerWidth, containerHeight) * 100;
|
|
3544
|
-
const constrainedX = Math.max(margin, Math.min(100 - margin, newXPercent));
|
|
3545
|
-
const constrainedY = Math.max(margin, Math.min(100 - margin, newYPercent));
|
|
3546
|
-
onPositionChange(constrainedX, constrainedY);
|
|
3630
|
+
if (drag.isDragging) {
|
|
3631
|
+
drag.handleDragMove(touch.clientX, touch.clientY);
|
|
3547
3632
|
} else {
|
|
3548
|
-
const moveDistance = Math.sqrt(
|
|
3549
|
-
Math.pow(touch.clientX - touchStartPosRef.current.x, 2) + Math.pow(touch.clientY - touchStartPosRef.current.y, 2)
|
|
3550
|
-
);
|
|
3551
|
-
if (moveDistance > 15) {
|
|
3552
|
-
clearDragTimer();
|
|
3553
|
-
}
|
|
3554
3633
|
const rect = dpadRef.current?.getBoundingClientRect();
|
|
3555
3634
|
if (rect) {
|
|
3635
|
+
drag.clearDragTimer();
|
|
3556
3636
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
3557
3637
|
}
|
|
3558
3638
|
}
|
|
3559
|
-
}, [
|
|
3639
|
+
}, [drag, getDirectionsFromTouch, updateDirections]);
|
|
3560
3640
|
const handleTouchEnd = useCallback((e) => {
|
|
3561
3641
|
e.preventDefault();
|
|
3562
|
-
clearDragTimer();
|
|
3642
|
+
drag.clearDragTimer();
|
|
3563
3643
|
let touchEnded = false;
|
|
3564
3644
|
for (let i = 0; i < e.changedTouches.length; i++) {
|
|
3565
3645
|
if (e.changedTouches[i].identifier === activeTouchRef.current) {
|
|
@@ -3569,8 +3649,8 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3569
3649
|
}
|
|
3570
3650
|
if (touchEnded) {
|
|
3571
3651
|
activeTouchRef.current = null;
|
|
3572
|
-
if (isDragging) {
|
|
3573
|
-
|
|
3652
|
+
if (drag.isDragging) {
|
|
3653
|
+
drag.handleDragEnd();
|
|
3574
3654
|
} else {
|
|
3575
3655
|
activeDirectionsRef.current.forEach((dir) => {
|
|
3576
3656
|
const keyCode = getKeyCode(dir);
|
|
@@ -3580,7 +3660,7 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3580
3660
|
updateVisuals(/* @__PURE__ */ new Set());
|
|
3581
3661
|
}
|
|
3582
3662
|
}
|
|
3583
|
-
}, [getKeyCode, updateVisuals,
|
|
3663
|
+
}, [getKeyCode, updateVisuals, drag]);
|
|
3584
3664
|
useEffect(() => {
|
|
3585
3665
|
const dpad = dpadRef.current;
|
|
3586
3666
|
if (!dpad) return;
|
|
@@ -3593,9 +3673,9 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3593
3673
|
dpad.removeEventListener("touchmove", handleTouchMove);
|
|
3594
3674
|
dpad.removeEventListener("touchend", handleTouchEnd);
|
|
3595
3675
|
dpad.removeEventListener("touchcancel", handleTouchEnd);
|
|
3596
|
-
clearDragTimer();
|
|
3676
|
+
drag.clearDragTimer();
|
|
3597
3677
|
};
|
|
3598
|
-
}, [handleTouchStart, handleTouchMove, handleTouchEnd,
|
|
3678
|
+
}, [handleTouchStart, handleTouchMove, handleTouchEnd, drag]);
|
|
3599
3679
|
const leftPx = displayX / 100 * containerWidth - size / 2;
|
|
3600
3680
|
const topPx = displayY / 100 * containerHeight - size / 2;
|
|
3601
3681
|
const dUp = "M 35,5 L 65,5 L 65,35 L 50,50 L 35,35 Z";
|
|
@@ -3606,21 +3686,21 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3606
3686
|
"div",
|
|
3607
3687
|
{
|
|
3608
3688
|
ref: dpadRef,
|
|
3609
|
-
className: `absolute pointer-events-auto touch-manipulation select-none ${isDragging ? "opacity-60" : ""}`,
|
|
3689
|
+
className: `absolute pointer-events-auto touch-manipulation select-none ${drag.isDragging ? "opacity-60" : ""}`,
|
|
3610
3690
|
style: {
|
|
3611
3691
|
top: 0,
|
|
3612
3692
|
left: 0,
|
|
3613
|
-
transform: `translate3d(${leftPx}px, ${topPx}px, 0)${isDragging ? " scale(1.05)" : ""}`,
|
|
3693
|
+
transform: `translate3d(${leftPx}px, ${topPx}px, 0)${drag.isDragging ? " scale(1.05)" : ""}`,
|
|
3614
3694
|
width: size,
|
|
3615
3695
|
height: size,
|
|
3616
3696
|
opacity: isLandscape ? 0.75 : 0.9,
|
|
3617
3697
|
WebkitTouchCallout: "none",
|
|
3618
3698
|
WebkitUserSelect: "none",
|
|
3619
3699
|
touchAction: "none",
|
|
3620
|
-
transition: isDragging ? "none" : "transform 0.1s ease-out"
|
|
3700
|
+
transition: drag.isDragging ? "none" : "transform 0.1s ease-out"
|
|
3621
3701
|
},
|
|
3622
3702
|
children: [
|
|
3623
|
-
/* @__PURE__ */ jsx("div", { className: `absolute inset-0 rounded-full bg-black/40 backdrop-blur-md border shadow-lg ${isDragging ? "border-white/50 ring-2 ring-white/30" : "border-white/10"}` }),
|
|
3703
|
+
/* @__PURE__ */ jsx("div", { className: `absolute inset-0 rounded-full bg-black/40 backdrop-blur-md border shadow-lg ${drag.isDragging ? "border-white/50 ring-2 ring-white/30" : "border-white/10"}` }),
|
|
3624
3704
|
/* @__PURE__ */ jsxs("svg", { width: "100%", height: "100%", viewBox: "0 0 100 100", className: "drop-shadow-xl relative z-10", children: [
|
|
3625
3705
|
/* @__PURE__ */ jsx("path", { ref: upPathRef, d: dUp, fill: "rgba(255,255,255,0.05)", stroke: "rgba(255,255,255,0.2)", strokeWidth: "1", className: "transition-all duration-75" }),
|
|
3626
3706
|
/* @__PURE__ */ jsx("path", { ref: rightPathRef, d: dRight, fill: "rgba(255,255,255,0.05)", stroke: "rgba(255,255,255,0.2)", strokeWidth: "1", className: "transition-all duration-75" }),
|
|
@@ -3633,9 +3713,9 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3633
3713
|
cx: "50",
|
|
3634
3714
|
cy: "50",
|
|
3635
3715
|
r: "12",
|
|
3636
|
-
fill: isDragging ? systemColor : "rgba(0,0,0,0.5)",
|
|
3637
|
-
stroke: isDragging ? "#fff" : "rgba(255,255,255,0.3)",
|
|
3638
|
-
strokeWidth: isDragging ? 2 : 1
|
|
3716
|
+
fill: drag.isDragging ? systemColor : "rgba(0,0,0,0.5)",
|
|
3717
|
+
stroke: drag.isDragging ? "#fff" : "rgba(255,255,255,0.3)",
|
|
3718
|
+
strokeWidth: drag.isDragging ? 2 : 1
|
|
3639
3719
|
}
|
|
3640
3720
|
),
|
|
3641
3721
|
/* @__PURE__ */ jsx("path", { d: "M 50,15 L 50,25 M 45,20 L 50,15 L 55,20", stroke: "white", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", fill: "none", opacity: "0.8", pointerEvents: "none" }),
|
|
@@ -4063,6 +4143,45 @@ function FloatingFullscreenButton({ onClick, disabled = false }) {
|
|
|
4063
4143
|
}
|
|
4064
4144
|
);
|
|
4065
4145
|
}
|
|
4146
|
+
function FloatingPauseButton({
|
|
4147
|
+
isPaused,
|
|
4148
|
+
onClick,
|
|
4149
|
+
disabled = false,
|
|
4150
|
+
systemColor = "#00FF41"
|
|
4151
|
+
}) {
|
|
4152
|
+
return /* @__PURE__ */ jsx(
|
|
4153
|
+
"button",
|
|
4154
|
+
{
|
|
4155
|
+
onClick,
|
|
4156
|
+
disabled,
|
|
4157
|
+
className: `
|
|
4158
|
+
fixed top-3 left-3 z-50
|
|
4159
|
+
px-3 py-2 rounded-xl
|
|
4160
|
+
bg-black/80 backdrop-blur-md
|
|
4161
|
+
border-2
|
|
4162
|
+
shadow-xl
|
|
4163
|
+
flex items-center gap-2
|
|
4164
|
+
transition-all duration-300
|
|
4165
|
+
hover:scale-105
|
|
4166
|
+
active:scale-95
|
|
4167
|
+
disabled:opacity-40 disabled:cursor-not-allowed
|
|
4168
|
+
touch-manipulation
|
|
4169
|
+
`,
|
|
4170
|
+
style: {
|
|
4171
|
+
paddingTop: "max(env(safe-area-inset-top, 0px), 8px)",
|
|
4172
|
+
borderColor: isPaused ? systemColor : "rgba(255,255,255,0.3)"
|
|
4173
|
+
},
|
|
4174
|
+
"aria-label": isPaused ? "Resume game" : "Pause game",
|
|
4175
|
+
children: isPaused ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4176
|
+
/* @__PURE__ */ jsx(Play, { size: 16, style: { color: systemColor }, fill: systemColor }),
|
|
4177
|
+
/* @__PURE__ */ jsx("span", { className: "text-white text-xs font-bold uppercase tracking-wider", children: "Play" })
|
|
4178
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4179
|
+
/* @__PURE__ */ jsx(Pause, { size: 16, className: "text-white/80" }),
|
|
4180
|
+
/* @__PURE__ */ jsx("span", { className: "text-white text-xs font-bold uppercase tracking-wider", children: "Pause" })
|
|
4181
|
+
] })
|
|
4182
|
+
}
|
|
4183
|
+
);
|
|
4184
|
+
}
|
|
4066
4185
|
function LoadingSpinner({ color, size = "lg" }) {
|
|
4067
4186
|
const sizeClass = size === "lg" ? "w-12 h-12" : "w-8 h-8";
|
|
4068
4187
|
return /* @__PURE__ */ jsx(Loader2, { className: `${sizeClass} animate-spin`, style: { color } });
|
|
@@ -9196,6 +9315,14 @@ var GamePlayerInner = memo(function GamePlayerInner2(props) {
|
|
|
9196
9315
|
disabled: status === "loading" || status === "error"
|
|
9197
9316
|
}
|
|
9198
9317
|
),
|
|
9318
|
+
isFullscreen2 && isMobile && (status === "running" || status === "paused") && /* @__PURE__ */ jsx(
|
|
9319
|
+
FloatingPauseButton,
|
|
9320
|
+
{
|
|
9321
|
+
isPaused,
|
|
9322
|
+
onClick: handlePauseToggle,
|
|
9323
|
+
systemColor
|
|
9324
|
+
}
|
|
9325
|
+
),
|
|
9199
9326
|
/* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 z-40 flex flex-col items-end gap-2 pointer-events-auto", children: [
|
|
9200
9327
|
/* @__PURE__ */ jsx(
|
|
9201
9328
|
RecordingIndicator_default,
|