koin.js 1.0.13 → 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 +247 -124
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +247 -124
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2393,26 +2393,49 @@ function getLayoutForSystem(system) {
|
|
|
2393
2393
|
if (s.includes("ATARI")) return TWO_BUTTON_LAYOUT;
|
|
2394
2394
|
return TWO_BUTTON_LAYOUT;
|
|
2395
2395
|
}
|
|
2396
|
-
|
|
2396
|
+
|
|
2397
|
+
// src/components/VirtualController/utils/dragConstraints.ts
|
|
2398
|
+
function constrainToViewport({
|
|
2399
|
+
newXPercent,
|
|
2400
|
+
newYPercent,
|
|
2401
|
+
elementSize,
|
|
2402
|
+
containerWidth,
|
|
2403
|
+
containerHeight
|
|
2404
|
+
}) {
|
|
2405
|
+
const xMargin = elementSize / 2 / containerWidth * 100;
|
|
2406
|
+
const yMargin = elementSize / 2 / containerHeight * 100;
|
|
2407
|
+
return {
|
|
2408
|
+
x: Math.max(xMargin, Math.min(100 - xMargin, newXPercent)),
|
|
2409
|
+
y: Math.max(yMargin, Math.min(100 - yMargin, newYPercent))
|
|
2410
|
+
};
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
// src/components/VirtualController/hooks/useDrag.ts
|
|
2414
|
+
var DEFAULT_HOLD_DELAY = 350;
|
|
2415
|
+
var DEFAULT_CENTER_THRESHOLD = 0.4;
|
|
2397
2416
|
var DRAG_MOVE_THRESHOLD = 10;
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
buttonType,
|
|
2401
|
-
isSystemButton,
|
|
2402
|
-
buttonSize,
|
|
2417
|
+
function useDrag({
|
|
2418
|
+
elementSize,
|
|
2403
2419
|
displayX,
|
|
2404
2420
|
displayY,
|
|
2405
2421
|
containerWidth,
|
|
2406
2422
|
containerHeight,
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2423
|
+
onPositionChange,
|
|
2424
|
+
holdDelay = DEFAULT_HOLD_DELAY,
|
|
2425
|
+
centerThreshold = DEFAULT_CENTER_THRESHOLD,
|
|
2426
|
+
onDragStart,
|
|
2427
|
+
onDragEnd
|
|
2411
2428
|
}) {
|
|
2429
|
+
const [isDragging, setIsDragging] = React2.useState(false);
|
|
2412
2430
|
const isDraggingRef = React2.useRef(false);
|
|
2413
|
-
const dragStartRef = React2.useRef({ x: 0, y: 0 });
|
|
2414
2431
|
const dragTimerRef = React2.useRef(null);
|
|
2415
2432
|
const touchStartPosRef = React2.useRef({ x: 0, y: 0 });
|
|
2433
|
+
const dragStartRef = React2.useRef({
|
|
2434
|
+
elementX: 0,
|
|
2435
|
+
elementY: 0,
|
|
2436
|
+
touchX: 0,
|
|
2437
|
+
touchY: 0
|
|
2438
|
+
});
|
|
2416
2439
|
const clearDragTimer = React2.useCallback(() => {
|
|
2417
2440
|
if (dragTimerRef.current) {
|
|
2418
2441
|
clearTimeout(dragTimerRef.current);
|
|
@@ -2422,23 +2445,129 @@ function useTouchHandlers({
|
|
|
2422
2445
|
const startDragging = React2.useCallback(
|
|
2423
2446
|
(touchX, touchY) => {
|
|
2424
2447
|
isDraggingRef.current = true;
|
|
2448
|
+
setIsDragging(true);
|
|
2425
2449
|
dragStartRef.current = {
|
|
2426
|
-
|
|
2427
|
-
|
|
2450
|
+
elementX: displayX,
|
|
2451
|
+
elementY: displayY,
|
|
2452
|
+
touchX,
|
|
2453
|
+
touchY
|
|
2428
2454
|
};
|
|
2429
2455
|
if (navigator.vibrate) {
|
|
2430
2456
|
navigator.vibrate([10, 30, 10]);
|
|
2431
2457
|
}
|
|
2458
|
+
onDragStart?.();
|
|
2459
|
+
},
|
|
2460
|
+
[displayX, displayY, onDragStart]
|
|
2461
|
+
);
|
|
2462
|
+
const checkDragStart = React2.useCallback(
|
|
2463
|
+
(touchX, touchY, elementRect) => {
|
|
2464
|
+
if (!onPositionChange) return false;
|
|
2465
|
+
touchStartPosRef.current = { x: touchX, y: touchY };
|
|
2466
|
+
const centerX = elementRect.left + elementRect.width / 2;
|
|
2467
|
+
const centerY = elementRect.top + elementRect.height / 2;
|
|
2468
|
+
const distFromCenter = Math.sqrt(
|
|
2469
|
+
Math.pow(touchX - centerX, 2) + Math.pow(touchY - centerY, 2)
|
|
2470
|
+
);
|
|
2471
|
+
const centerRadius = elementSize * centerThreshold;
|
|
2472
|
+
if (distFromCenter < centerRadius) {
|
|
2473
|
+
dragTimerRef.current = setTimeout(() => {
|
|
2474
|
+
if (!isDraggingRef.current) {
|
|
2475
|
+
startDragging(touchX, touchY);
|
|
2476
|
+
}
|
|
2477
|
+
}, holdDelay);
|
|
2478
|
+
return true;
|
|
2479
|
+
}
|
|
2480
|
+
return false;
|
|
2481
|
+
},
|
|
2482
|
+
[onPositionChange, elementSize, centerThreshold, holdDelay, startDragging]
|
|
2483
|
+
);
|
|
2484
|
+
const checkMoveThreshold = React2.useCallback(
|
|
2485
|
+
(touchX, touchY) => {
|
|
2486
|
+
if (!onPositionChange || isDraggingRef.current) return false;
|
|
2487
|
+
const moveDistance = Math.sqrt(
|
|
2488
|
+
Math.pow(touchX - touchStartPosRef.current.x, 2) + Math.pow(touchY - touchStartPosRef.current.y, 2)
|
|
2489
|
+
);
|
|
2490
|
+
if (moveDistance > DRAG_MOVE_THRESHOLD) {
|
|
2491
|
+
clearDragTimer();
|
|
2492
|
+
startDragging(touchX, touchY);
|
|
2493
|
+
return true;
|
|
2494
|
+
}
|
|
2495
|
+
return false;
|
|
2496
|
+
},
|
|
2497
|
+
[onPositionChange, clearDragTimer, startDragging]
|
|
2498
|
+
);
|
|
2499
|
+
const handleDragMove = React2.useCallback(
|
|
2500
|
+
(touchX, touchY) => {
|
|
2501
|
+
if (!isDraggingRef.current || !onPositionChange) return;
|
|
2502
|
+
const deltaX = touchX - dragStartRef.current.touchX;
|
|
2503
|
+
const deltaY = touchY - dragStartRef.current.touchY;
|
|
2504
|
+
const newXPercent = dragStartRef.current.elementX + deltaX / containerWidth * 100;
|
|
2505
|
+
const newYPercent = dragStartRef.current.elementY + deltaY / containerHeight * 100;
|
|
2506
|
+
const constrained = constrainToViewport({
|
|
2507
|
+
newXPercent,
|
|
2508
|
+
newYPercent,
|
|
2509
|
+
elementSize,
|
|
2510
|
+
containerWidth,
|
|
2511
|
+
containerHeight
|
|
2512
|
+
});
|
|
2513
|
+
onPositionChange(constrained.x, constrained.y);
|
|
2514
|
+
},
|
|
2515
|
+
[onPositionChange, containerWidth, containerHeight, elementSize]
|
|
2516
|
+
);
|
|
2517
|
+
const handleDragEnd = React2.useCallback(() => {
|
|
2518
|
+
clearDragTimer();
|
|
2519
|
+
if (isDraggingRef.current) {
|
|
2520
|
+
isDraggingRef.current = false;
|
|
2521
|
+
setIsDragging(false);
|
|
2522
|
+
onDragEnd?.();
|
|
2523
|
+
}
|
|
2524
|
+
}, [clearDragTimer, onDragEnd]);
|
|
2525
|
+
return {
|
|
2526
|
+
isDragging,
|
|
2527
|
+
checkDragStart,
|
|
2528
|
+
handleDragMove,
|
|
2529
|
+
handleDragEnd,
|
|
2530
|
+
clearDragTimer,
|
|
2531
|
+
checkMoveThreshold
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
// src/components/VirtualController/hooks/useTouchHandlers.ts
|
|
2536
|
+
function useTouchHandlers({
|
|
2537
|
+
buttonType,
|
|
2538
|
+
isSystemButton,
|
|
2539
|
+
buttonSize,
|
|
2540
|
+
displayX,
|
|
2541
|
+
displayY,
|
|
2542
|
+
containerWidth,
|
|
2543
|
+
containerHeight,
|
|
2544
|
+
onPress,
|
|
2545
|
+
onPressDown,
|
|
2546
|
+
onRelease,
|
|
2547
|
+
onPositionChange
|
|
2548
|
+
}) {
|
|
2549
|
+
const isDraggingRef = React2.useRef(false);
|
|
2550
|
+
const drag = useDrag({
|
|
2551
|
+
elementSize: buttonSize,
|
|
2552
|
+
displayX,
|
|
2553
|
+
displayY,
|
|
2554
|
+
containerWidth,
|
|
2555
|
+
containerHeight,
|
|
2556
|
+
onPositionChange,
|
|
2557
|
+
centerThreshold: 0.4,
|
|
2558
|
+
onDragStart: () => {
|
|
2559
|
+
isDraggingRef.current = true;
|
|
2432
2560
|
if (!isSystemButton) {
|
|
2433
2561
|
onRelease(buttonType);
|
|
2434
2562
|
}
|
|
2435
2563
|
},
|
|
2436
|
-
|
|
2437
|
-
|
|
2564
|
+
onDragEnd: () => {
|
|
2565
|
+
isDraggingRef.current = false;
|
|
2566
|
+
}
|
|
2567
|
+
});
|
|
2438
2568
|
const handleTouchStart = React2.useCallback(
|
|
2439
2569
|
(e) => {
|
|
2440
2570
|
const touch = e.touches[0];
|
|
2441
|
-
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY };
|
|
2442
2571
|
e.preventDefault();
|
|
2443
2572
|
e.stopPropagation();
|
|
2444
2573
|
if (navigator.vibrate) {
|
|
@@ -2453,57 +2582,32 @@ function useTouchHandlers({
|
|
|
2453
2582
|
const target = e.currentTarget;
|
|
2454
2583
|
if (!target) return;
|
|
2455
2584
|
const rect = target.getBoundingClientRect();
|
|
2456
|
-
|
|
2457
|
-
const centerY = rect.top + rect.height / 2;
|
|
2458
|
-
const distance = Math.sqrt(
|
|
2459
|
-
Math.pow(touch.clientX - centerX, 2) + Math.pow(touch.clientY - centerY, 2)
|
|
2460
|
-
);
|
|
2461
|
-
const dragThreshold = buttonSize * DRAG_CENTER_THRESHOLD;
|
|
2462
|
-
if (distance < dragThreshold) {
|
|
2463
|
-
dragTimerRef.current = setTimeout(() => {
|
|
2464
|
-
if (!isDraggingRef.current) {
|
|
2465
|
-
startDragging(touch.clientX, touch.clientY);
|
|
2466
|
-
}
|
|
2467
|
-
}, DRAG_HOLD_DELAY);
|
|
2468
|
-
}
|
|
2585
|
+
drag.checkDragStart(touch.clientX, touch.clientY, rect);
|
|
2469
2586
|
}
|
|
2470
2587
|
},
|
|
2471
|
-
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange,
|
|
2588
|
+
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange, drag]
|
|
2472
2589
|
);
|
|
2473
2590
|
const handleTouchMove = React2.useCallback(
|
|
2474
2591
|
(e) => {
|
|
2475
2592
|
const touch = e.touches[0];
|
|
2476
2593
|
if (onPositionChange && !isDraggingRef.current) {
|
|
2477
|
-
|
|
2478
|
-
Math.pow(touch.clientX - touchStartPosRef.current.x, 2) + Math.pow(touch.clientY - touchStartPosRef.current.y, 2)
|
|
2479
|
-
);
|
|
2480
|
-
if (moveDistance > DRAG_MOVE_THRESHOLD) {
|
|
2481
|
-
clearDragTimer();
|
|
2482
|
-
startDragging(touch.clientX, touch.clientY);
|
|
2483
|
-
}
|
|
2594
|
+
drag.checkMoveThreshold(touch.clientX, touch.clientY);
|
|
2484
2595
|
}
|
|
2485
|
-
if (isDraggingRef.current
|
|
2596
|
+
if (isDraggingRef.current) {
|
|
2486
2597
|
e.preventDefault();
|
|
2487
2598
|
e.stopPropagation();
|
|
2488
|
-
|
|
2489
|
-
const newY = touch.clientY - dragStartRef.current.y;
|
|
2490
|
-
const newXPercent = newX / containerWidth * 100;
|
|
2491
|
-
const newYPercent = newY / containerHeight * 100;
|
|
2492
|
-
const margin = buttonSize / 2 / Math.min(containerWidth, containerHeight) * 100;
|
|
2493
|
-
const constrainedX = Math.max(margin, Math.min(100 - margin, newXPercent));
|
|
2494
|
-
const constrainedY = Math.max(margin, Math.min(100 - margin, newYPercent));
|
|
2495
|
-
onPositionChange(constrainedX, constrainedY);
|
|
2599
|
+
drag.handleDragMove(touch.clientX, touch.clientY);
|
|
2496
2600
|
}
|
|
2497
2601
|
},
|
|
2498
|
-
[onPositionChange,
|
|
2602
|
+
[onPositionChange, drag]
|
|
2499
2603
|
);
|
|
2500
2604
|
const handleTouchEnd = React2.useCallback(
|
|
2501
2605
|
(e) => {
|
|
2502
|
-
clearDragTimer();
|
|
2606
|
+
drag.clearDragTimer();
|
|
2503
2607
|
if (isDraggingRef.current) {
|
|
2504
2608
|
e.preventDefault();
|
|
2505
2609
|
e.stopPropagation();
|
|
2506
|
-
|
|
2610
|
+
drag.handleDragEnd();
|
|
2507
2611
|
return;
|
|
2508
2612
|
}
|
|
2509
2613
|
e.preventDefault();
|
|
@@ -2512,15 +2616,15 @@ function useTouchHandlers({
|
|
|
2512
2616
|
onRelease(buttonType);
|
|
2513
2617
|
}
|
|
2514
2618
|
},
|
|
2515
|
-
[
|
|
2619
|
+
[drag, isSystemButton, buttonType, onRelease]
|
|
2516
2620
|
);
|
|
2517
2621
|
const handleTouchCancel = React2.useCallback(
|
|
2518
2622
|
(e) => {
|
|
2519
|
-
clearDragTimer();
|
|
2623
|
+
drag.clearDragTimer();
|
|
2520
2624
|
if (isDraggingRef.current) {
|
|
2521
2625
|
e.preventDefault();
|
|
2522
2626
|
e.stopPropagation();
|
|
2523
|
-
|
|
2627
|
+
drag.handleDragEnd();
|
|
2524
2628
|
return;
|
|
2525
2629
|
}
|
|
2526
2630
|
e.preventDefault();
|
|
@@ -2529,11 +2633,11 @@ function useTouchHandlers({
|
|
|
2529
2633
|
onRelease(buttonType);
|
|
2530
2634
|
}
|
|
2531
2635
|
},
|
|
2532
|
-
[
|
|
2636
|
+
[drag, isSystemButton, buttonType, onRelease]
|
|
2533
2637
|
);
|
|
2534
2638
|
const cleanup = React2.useCallback(() => {
|
|
2535
|
-
clearDragTimer();
|
|
2536
|
-
}, [
|
|
2639
|
+
drag.clearDragTimer();
|
|
2640
|
+
}, [drag]);
|
|
2537
2641
|
return {
|
|
2538
2642
|
handleTouchStart,
|
|
2539
2643
|
handleTouchMove,
|
|
@@ -3389,7 +3493,6 @@ function dispatchKeyboardEvent(type, code) {
|
|
|
3389
3493
|
canvas.dispatchEvent(event);
|
|
3390
3494
|
return true;
|
|
3391
3495
|
}
|
|
3392
|
-
var DRAG_HOLD_DELAY2 = 350;
|
|
3393
3496
|
var CENTER_TOUCH_RADIUS = 0.25;
|
|
3394
3497
|
var Dpad = React2__default.default.memo(function Dpad2({
|
|
3395
3498
|
size = 180,
|
|
@@ -3406,10 +3509,6 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3406
3509
|
const dpadRef = React2.useRef(null);
|
|
3407
3510
|
const activeTouchRef = React2.useRef(null);
|
|
3408
3511
|
const activeDirectionsRef = React2.useRef(/* @__PURE__ */ new Set());
|
|
3409
|
-
const [isDragging, setIsDragging] = React2.useState(false);
|
|
3410
|
-
const dragTimerRef = React2.useRef(null);
|
|
3411
|
-
const dragStartRef = React2.useRef({ x: 0, y: 0, touchX: 0, touchY: 0 });
|
|
3412
|
-
const touchStartPosRef = React2.useRef({ x: 0, y: 0, time: 0 });
|
|
3413
3512
|
const upPathRef = React2.useRef(null);
|
|
3414
3513
|
const downPathRef = React2.useRef(null);
|
|
3415
3514
|
const leftPathRef = React2.useRef(null);
|
|
@@ -3417,6 +3516,13 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3417
3516
|
const centerCircleRef = React2.useRef(null);
|
|
3418
3517
|
const displayX = customPosition ? customPosition.x : x;
|
|
3419
3518
|
const displayY = customPosition ? customPosition.y : y;
|
|
3519
|
+
const releaseAllDirections = React2.useCallback((getKeyCode2) => {
|
|
3520
|
+
activeDirectionsRef.current.forEach((dir) => {
|
|
3521
|
+
const keyCode = getKeyCode2(dir);
|
|
3522
|
+
if (keyCode) dispatchKeyboardEvent("keyup", keyCode);
|
|
3523
|
+
});
|
|
3524
|
+
activeDirectionsRef.current = /* @__PURE__ */ new Set();
|
|
3525
|
+
}, []);
|
|
3420
3526
|
const getKeyCode = React2.useCallback((direction) => {
|
|
3421
3527
|
if (!controls) {
|
|
3422
3528
|
const defaults = {
|
|
@@ -3429,6 +3535,19 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3429
3535
|
}
|
|
3430
3536
|
return controls[direction] || "";
|
|
3431
3537
|
}, [controls]);
|
|
3538
|
+
const drag = useDrag({
|
|
3539
|
+
elementSize: size,
|
|
3540
|
+
displayX,
|
|
3541
|
+
displayY,
|
|
3542
|
+
containerWidth,
|
|
3543
|
+
containerHeight,
|
|
3544
|
+
onPositionChange,
|
|
3545
|
+
centerThreshold: CENTER_TOUCH_RADIUS,
|
|
3546
|
+
onDragStart: () => {
|
|
3547
|
+
releaseAllDirections(getKeyCode);
|
|
3548
|
+
updateVisuals(/* @__PURE__ */ new Set());
|
|
3549
|
+
}
|
|
3550
|
+
});
|
|
3432
3551
|
const getDirectionsFromTouch = React2.useCallback((touchX, touchY, rect) => {
|
|
3433
3552
|
const centerX = rect.left + rect.width / 2;
|
|
3434
3553
|
const centerY = rect.top + rect.height / 2;
|
|
@@ -3490,51 +3609,20 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3490
3609
|
activeDirectionsRef.current = newDirections;
|
|
3491
3610
|
updateVisuals(newDirections);
|
|
3492
3611
|
}, [getKeyCode, updateVisuals]);
|
|
3493
|
-
const clearDragTimer = React2.useCallback(() => {
|
|
3494
|
-
if (dragTimerRef.current) {
|
|
3495
|
-
clearTimeout(dragTimerRef.current);
|
|
3496
|
-
dragTimerRef.current = null;
|
|
3497
|
-
}
|
|
3498
|
-
}, []);
|
|
3499
|
-
const startDragging = React2.useCallback((touchX, touchY) => {
|
|
3500
|
-
setIsDragging(true);
|
|
3501
|
-
dragStartRef.current = {
|
|
3502
|
-
x: displayX,
|
|
3503
|
-
y: displayY,
|
|
3504
|
-
touchX,
|
|
3505
|
-
touchY
|
|
3506
|
-
};
|
|
3507
|
-
activeDirectionsRef.current.forEach((dir) => {
|
|
3508
|
-
const keyCode = getKeyCode(dir);
|
|
3509
|
-
if (keyCode) dispatchKeyboardEvent("keyup", keyCode);
|
|
3510
|
-
});
|
|
3511
|
-
activeDirectionsRef.current = /* @__PURE__ */ new Set();
|
|
3512
|
-
updateVisuals(/* @__PURE__ */ new Set());
|
|
3513
|
-
if (navigator.vibrate) navigator.vibrate([10, 30, 10]);
|
|
3514
|
-
}, [displayX, displayY, getKeyCode, updateVisuals]);
|
|
3515
3612
|
const handleTouchStart = React2.useCallback((e) => {
|
|
3516
3613
|
e.preventDefault();
|
|
3517
3614
|
if (activeTouchRef.current !== null) return;
|
|
3518
3615
|
const touch = e.changedTouches[0];
|
|
3519
3616
|
activeTouchRef.current = touch.identifier;
|
|
3520
|
-
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
|
|
3521
3617
|
const rect = dpadRef.current?.getBoundingClientRect();
|
|
3522
3618
|
if (!rect) return;
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
const distFromCenter = Math.sqrt(
|
|
3526
|
-
Math.pow(touch.clientX - centerX, 2) + Math.pow(touch.clientY - centerY, 2)
|
|
3527
|
-
);
|
|
3528
|
-
const centerRadius = size * CENTER_TOUCH_RADIUS;
|
|
3529
|
-
if (distFromCenter < centerRadius && onPositionChange) {
|
|
3530
|
-
dragTimerRef.current = setTimeout(() => {
|
|
3531
|
-
startDragging(touch.clientX, touch.clientY);
|
|
3532
|
-
}, DRAG_HOLD_DELAY2);
|
|
3619
|
+
if (onPositionChange) {
|
|
3620
|
+
drag.checkDragStart(touch.clientX, touch.clientY, rect);
|
|
3533
3621
|
}
|
|
3534
|
-
if (!isDragging) {
|
|
3622
|
+
if (!drag.isDragging) {
|
|
3535
3623
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
3536
3624
|
}
|
|
3537
|
-
}, [getDirectionsFromTouch, updateDirections,
|
|
3625
|
+
}, [getDirectionsFromTouch, updateDirections, onPositionChange, drag]);
|
|
3538
3626
|
const handleTouchMove = React2.useCallback((e) => {
|
|
3539
3627
|
e.preventDefault();
|
|
3540
3628
|
let touch = null;
|
|
@@ -3545,31 +3633,19 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3545
3633
|
}
|
|
3546
3634
|
}
|
|
3547
3635
|
if (!touch) return;
|
|
3548
|
-
if (isDragging
|
|
3549
|
-
|
|
3550
|
-
const deltaY = touch.clientY - dragStartRef.current.touchY;
|
|
3551
|
-
const newXPercent = dragStartRef.current.x + deltaX / containerWidth * 100;
|
|
3552
|
-
const newYPercent = dragStartRef.current.y + deltaY / containerHeight * 100;
|
|
3553
|
-
const margin = size / 2 / Math.min(containerWidth, containerHeight) * 100;
|
|
3554
|
-
const constrainedX = Math.max(margin, Math.min(100 - margin, newXPercent));
|
|
3555
|
-
const constrainedY = Math.max(margin, Math.min(100 - margin, newYPercent));
|
|
3556
|
-
onPositionChange(constrainedX, constrainedY);
|
|
3636
|
+
if (drag.isDragging) {
|
|
3637
|
+
drag.handleDragMove(touch.clientX, touch.clientY);
|
|
3557
3638
|
} else {
|
|
3558
|
-
const moveDistance = Math.sqrt(
|
|
3559
|
-
Math.pow(touch.clientX - touchStartPosRef.current.x, 2) + Math.pow(touch.clientY - touchStartPosRef.current.y, 2)
|
|
3560
|
-
);
|
|
3561
|
-
if (moveDistance > 15) {
|
|
3562
|
-
clearDragTimer();
|
|
3563
|
-
}
|
|
3564
3639
|
const rect = dpadRef.current?.getBoundingClientRect();
|
|
3565
3640
|
if (rect) {
|
|
3641
|
+
drag.clearDragTimer();
|
|
3566
3642
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
3567
3643
|
}
|
|
3568
3644
|
}
|
|
3569
|
-
}, [
|
|
3645
|
+
}, [drag, getDirectionsFromTouch, updateDirections]);
|
|
3570
3646
|
const handleTouchEnd = React2.useCallback((e) => {
|
|
3571
3647
|
e.preventDefault();
|
|
3572
|
-
clearDragTimer();
|
|
3648
|
+
drag.clearDragTimer();
|
|
3573
3649
|
let touchEnded = false;
|
|
3574
3650
|
for (let i = 0; i < e.changedTouches.length; i++) {
|
|
3575
3651
|
if (e.changedTouches[i].identifier === activeTouchRef.current) {
|
|
@@ -3579,8 +3655,8 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3579
3655
|
}
|
|
3580
3656
|
if (touchEnded) {
|
|
3581
3657
|
activeTouchRef.current = null;
|
|
3582
|
-
if (isDragging) {
|
|
3583
|
-
|
|
3658
|
+
if (drag.isDragging) {
|
|
3659
|
+
drag.handleDragEnd();
|
|
3584
3660
|
} else {
|
|
3585
3661
|
activeDirectionsRef.current.forEach((dir) => {
|
|
3586
3662
|
const keyCode = getKeyCode(dir);
|
|
@@ -3590,7 +3666,7 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3590
3666
|
updateVisuals(/* @__PURE__ */ new Set());
|
|
3591
3667
|
}
|
|
3592
3668
|
}
|
|
3593
|
-
}, [getKeyCode, updateVisuals,
|
|
3669
|
+
}, [getKeyCode, updateVisuals, drag]);
|
|
3594
3670
|
React2.useEffect(() => {
|
|
3595
3671
|
const dpad = dpadRef.current;
|
|
3596
3672
|
if (!dpad) return;
|
|
@@ -3603,9 +3679,9 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3603
3679
|
dpad.removeEventListener("touchmove", handleTouchMove);
|
|
3604
3680
|
dpad.removeEventListener("touchend", handleTouchEnd);
|
|
3605
3681
|
dpad.removeEventListener("touchcancel", handleTouchEnd);
|
|
3606
|
-
clearDragTimer();
|
|
3682
|
+
drag.clearDragTimer();
|
|
3607
3683
|
};
|
|
3608
|
-
}, [handleTouchStart, handleTouchMove, handleTouchEnd,
|
|
3684
|
+
}, [handleTouchStart, handleTouchMove, handleTouchEnd, drag]);
|
|
3609
3685
|
const leftPx = displayX / 100 * containerWidth - size / 2;
|
|
3610
3686
|
const topPx = displayY / 100 * containerHeight - size / 2;
|
|
3611
3687
|
const dUp = "M 35,5 L 65,5 L 65,35 L 50,50 L 35,35 Z";
|
|
@@ -3616,21 +3692,21 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3616
3692
|
"div",
|
|
3617
3693
|
{
|
|
3618
3694
|
ref: dpadRef,
|
|
3619
|
-
className: `absolute pointer-events-auto touch-manipulation select-none ${isDragging ? "opacity-60" : ""}`,
|
|
3695
|
+
className: `absolute pointer-events-auto touch-manipulation select-none ${drag.isDragging ? "opacity-60" : ""}`,
|
|
3620
3696
|
style: {
|
|
3621
3697
|
top: 0,
|
|
3622
3698
|
left: 0,
|
|
3623
|
-
transform: `translate3d(${leftPx}px, ${topPx}px, 0)${isDragging ? " scale(1.05)" : ""}`,
|
|
3699
|
+
transform: `translate3d(${leftPx}px, ${topPx}px, 0)${drag.isDragging ? " scale(1.05)" : ""}`,
|
|
3624
3700
|
width: size,
|
|
3625
3701
|
height: size,
|
|
3626
3702
|
opacity: isLandscape ? 0.75 : 0.9,
|
|
3627
3703
|
WebkitTouchCallout: "none",
|
|
3628
3704
|
WebkitUserSelect: "none",
|
|
3629
3705
|
touchAction: "none",
|
|
3630
|
-
transition: isDragging ? "none" : "transform 0.1s ease-out"
|
|
3706
|
+
transition: drag.isDragging ? "none" : "transform 0.1s ease-out"
|
|
3631
3707
|
},
|
|
3632
3708
|
children: [
|
|
3633
|
-
/* @__PURE__ */ jsxRuntime.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"}` }),
|
|
3709
|
+
/* @__PURE__ */ jsxRuntime.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"}` }),
|
|
3634
3710
|
/* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height: "100%", viewBox: "0 0 100 100", className: "drop-shadow-xl relative z-10", children: [
|
|
3635
3711
|
/* @__PURE__ */ jsxRuntime.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" }),
|
|
3636
3712
|
/* @__PURE__ */ jsxRuntime.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" }),
|
|
@@ -3643,9 +3719,9 @@ var Dpad = React2__default.default.memo(function Dpad2({
|
|
|
3643
3719
|
cx: "50",
|
|
3644
3720
|
cy: "50",
|
|
3645
3721
|
r: "12",
|
|
3646
|
-
fill: isDragging ? systemColor : "rgba(0,0,0,0.5)",
|
|
3647
|
-
stroke: isDragging ? "#fff" : "rgba(255,255,255,0.3)",
|
|
3648
|
-
strokeWidth: isDragging ? 2 : 1
|
|
3722
|
+
fill: drag.isDragging ? systemColor : "rgba(0,0,0,0.5)",
|
|
3723
|
+
stroke: drag.isDragging ? "#fff" : "rgba(255,255,255,0.3)",
|
|
3724
|
+
strokeWidth: drag.isDragging ? 2 : 1
|
|
3649
3725
|
}
|
|
3650
3726
|
),
|
|
3651
3727
|
/* @__PURE__ */ jsxRuntime.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" }),
|
|
@@ -4073,6 +4149,45 @@ function FloatingFullscreenButton({ onClick, disabled = false }) {
|
|
|
4073
4149
|
}
|
|
4074
4150
|
);
|
|
4075
4151
|
}
|
|
4152
|
+
function FloatingPauseButton({
|
|
4153
|
+
isPaused,
|
|
4154
|
+
onClick,
|
|
4155
|
+
disabled = false,
|
|
4156
|
+
systemColor = "#00FF41"
|
|
4157
|
+
}) {
|
|
4158
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4159
|
+
"button",
|
|
4160
|
+
{
|
|
4161
|
+
onClick,
|
|
4162
|
+
disabled,
|
|
4163
|
+
className: `
|
|
4164
|
+
fixed top-3 left-3 z-50
|
|
4165
|
+
px-3 py-2 rounded-xl
|
|
4166
|
+
bg-black/80 backdrop-blur-md
|
|
4167
|
+
border-2
|
|
4168
|
+
shadow-xl
|
|
4169
|
+
flex items-center gap-2
|
|
4170
|
+
transition-all duration-300
|
|
4171
|
+
hover:scale-105
|
|
4172
|
+
active:scale-95
|
|
4173
|
+
disabled:opacity-40 disabled:cursor-not-allowed
|
|
4174
|
+
touch-manipulation
|
|
4175
|
+
`,
|
|
4176
|
+
style: {
|
|
4177
|
+
paddingTop: "max(env(safe-area-inset-top, 0px), 8px)",
|
|
4178
|
+
borderColor: isPaused ? systemColor : "rgba(255,255,255,0.3)"
|
|
4179
|
+
},
|
|
4180
|
+
"aria-label": isPaused ? "Resume game" : "Pause game",
|
|
4181
|
+
children: isPaused ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4182
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Play, { size: 16, style: { color: systemColor }, fill: systemColor }),
|
|
4183
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white text-xs font-bold uppercase tracking-wider", children: "Play" })
|
|
4184
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4185
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { size: 16, className: "text-white/80" }),
|
|
4186
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white text-xs font-bold uppercase tracking-wider", children: "Pause" })
|
|
4187
|
+
] })
|
|
4188
|
+
}
|
|
4189
|
+
);
|
|
4190
|
+
}
|
|
4076
4191
|
function LoadingSpinner({ color, size = "lg" }) {
|
|
4077
4192
|
const sizeClass = size === "lg" ? "w-12 h-12" : "w-8 h-8";
|
|
4078
4193
|
return /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: `${sizeClass} animate-spin`, style: { color } });
|
|
@@ -9206,6 +9321,14 @@ var GamePlayerInner = React2.memo(function GamePlayerInner2(props) {
|
|
|
9206
9321
|
disabled: status === "loading" || status === "error"
|
|
9207
9322
|
}
|
|
9208
9323
|
),
|
|
9324
|
+
isFullscreen2 && isMobile && (status === "running" || status === "paused") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9325
|
+
FloatingPauseButton,
|
|
9326
|
+
{
|
|
9327
|
+
isPaused,
|
|
9328
|
+
onClick: handlePauseToggle,
|
|
9329
|
+
systemColor
|
|
9330
|
+
}
|
|
9331
|
+
),
|
|
9209
9332
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-2 right-2 z-40 flex flex-col items-end gap-2 pointer-events-auto", children: [
|
|
9210
9333
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9211
9334
|
RecordingIndicator_default,
|