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.mjs
CHANGED
|
@@ -2387,26 +2387,49 @@ function getLayoutForSystem(system) {
|
|
|
2387
2387
|
if (s.includes("ATARI")) return TWO_BUTTON_LAYOUT;
|
|
2388
2388
|
return TWO_BUTTON_LAYOUT;
|
|
2389
2389
|
}
|
|
2390
|
-
|
|
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;
|
|
2391
2410
|
var DRAG_MOVE_THRESHOLD = 10;
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
buttonType,
|
|
2395
|
-
isSystemButton,
|
|
2396
|
-
buttonSize,
|
|
2411
|
+
function useDrag({
|
|
2412
|
+
elementSize,
|
|
2397
2413
|
displayX,
|
|
2398
2414
|
displayY,
|
|
2399
2415
|
containerWidth,
|
|
2400
2416
|
containerHeight,
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2417
|
+
onPositionChange,
|
|
2418
|
+
holdDelay = DEFAULT_HOLD_DELAY,
|
|
2419
|
+
centerThreshold = DEFAULT_CENTER_THRESHOLD,
|
|
2420
|
+
onDragStart,
|
|
2421
|
+
onDragEnd
|
|
2405
2422
|
}) {
|
|
2423
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
2406
2424
|
const isDraggingRef = useRef(false);
|
|
2407
|
-
const dragStartRef = useRef({ x: 0, y: 0 });
|
|
2408
2425
|
const dragTimerRef = useRef(null);
|
|
2409
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
|
+
});
|
|
2410
2433
|
const clearDragTimer = useCallback(() => {
|
|
2411
2434
|
if (dragTimerRef.current) {
|
|
2412
2435
|
clearTimeout(dragTimerRef.current);
|
|
@@ -2416,23 +2439,129 @@ function useTouchHandlers({
|
|
|
2416
2439
|
const startDragging = useCallback(
|
|
2417
2440
|
(touchX, touchY) => {
|
|
2418
2441
|
isDraggingRef.current = true;
|
|
2442
|
+
setIsDragging(true);
|
|
2419
2443
|
dragStartRef.current = {
|
|
2420
|
-
|
|
2421
|
-
|
|
2444
|
+
elementX: displayX,
|
|
2445
|
+
elementY: displayY,
|
|
2446
|
+
touchX,
|
|
2447
|
+
touchY
|
|
2422
2448
|
};
|
|
2423
2449
|
if (navigator.vibrate) {
|
|
2424
2450
|
navigator.vibrate([10, 30, 10]);
|
|
2425
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;
|
|
2426
2554
|
if (!isSystemButton) {
|
|
2427
2555
|
onRelease(buttonType);
|
|
2428
2556
|
}
|
|
2429
2557
|
},
|
|
2430
|
-
|
|
2431
|
-
|
|
2558
|
+
onDragEnd: () => {
|
|
2559
|
+
isDraggingRef.current = false;
|
|
2560
|
+
}
|
|
2561
|
+
});
|
|
2432
2562
|
const handleTouchStart = useCallback(
|
|
2433
2563
|
(e) => {
|
|
2434
2564
|
const touch = e.touches[0];
|
|
2435
|
-
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY };
|
|
2436
2565
|
e.preventDefault();
|
|
2437
2566
|
e.stopPropagation();
|
|
2438
2567
|
if (navigator.vibrate) {
|
|
@@ -2447,57 +2576,32 @@ function useTouchHandlers({
|
|
|
2447
2576
|
const target = e.currentTarget;
|
|
2448
2577
|
if (!target) return;
|
|
2449
2578
|
const rect = target.getBoundingClientRect();
|
|
2450
|
-
|
|
2451
|
-
const centerY = rect.top + rect.height / 2;
|
|
2452
|
-
const distance = Math.sqrt(
|
|
2453
|
-
Math.pow(touch.clientX - centerX, 2) + Math.pow(touch.clientY - centerY, 2)
|
|
2454
|
-
);
|
|
2455
|
-
const dragThreshold = buttonSize * DRAG_CENTER_THRESHOLD;
|
|
2456
|
-
if (distance < dragThreshold) {
|
|
2457
|
-
dragTimerRef.current = setTimeout(() => {
|
|
2458
|
-
if (!isDraggingRef.current) {
|
|
2459
|
-
startDragging(touch.clientX, touch.clientY);
|
|
2460
|
-
}
|
|
2461
|
-
}, DRAG_HOLD_DELAY);
|
|
2462
|
-
}
|
|
2579
|
+
drag.checkDragStart(touch.clientX, touch.clientY, rect);
|
|
2463
2580
|
}
|
|
2464
2581
|
},
|
|
2465
|
-
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange,
|
|
2582
|
+
[isSystemButton, buttonType, onPress, onPressDown, onPositionChange, drag]
|
|
2466
2583
|
);
|
|
2467
2584
|
const handleTouchMove = useCallback(
|
|
2468
2585
|
(e) => {
|
|
2469
2586
|
const touch = e.touches[0];
|
|
2470
2587
|
if (onPositionChange && !isDraggingRef.current) {
|
|
2471
|
-
|
|
2472
|
-
Math.pow(touch.clientX - touchStartPosRef.current.x, 2) + Math.pow(touch.clientY - touchStartPosRef.current.y, 2)
|
|
2473
|
-
);
|
|
2474
|
-
if (moveDistance > DRAG_MOVE_THRESHOLD) {
|
|
2475
|
-
clearDragTimer();
|
|
2476
|
-
startDragging(touch.clientX, touch.clientY);
|
|
2477
|
-
}
|
|
2588
|
+
drag.checkMoveThreshold(touch.clientX, touch.clientY);
|
|
2478
2589
|
}
|
|
2479
|
-
if (isDraggingRef.current
|
|
2590
|
+
if (isDraggingRef.current) {
|
|
2480
2591
|
e.preventDefault();
|
|
2481
2592
|
e.stopPropagation();
|
|
2482
|
-
|
|
2483
|
-
const newY = touch.clientY - dragStartRef.current.y;
|
|
2484
|
-
const newXPercent = newX / containerWidth * 100;
|
|
2485
|
-
const newYPercent = newY / containerHeight * 100;
|
|
2486
|
-
const margin = buttonSize / 2 / Math.min(containerWidth, containerHeight) * 100;
|
|
2487
|
-
const constrainedX = Math.max(margin, Math.min(100 - margin, newXPercent));
|
|
2488
|
-
const constrainedY = Math.max(margin, Math.min(100 - margin, newYPercent));
|
|
2489
|
-
onPositionChange(constrainedX, constrainedY);
|
|
2593
|
+
drag.handleDragMove(touch.clientX, touch.clientY);
|
|
2490
2594
|
}
|
|
2491
2595
|
},
|
|
2492
|
-
[onPositionChange,
|
|
2596
|
+
[onPositionChange, drag]
|
|
2493
2597
|
);
|
|
2494
2598
|
const handleTouchEnd = useCallback(
|
|
2495
2599
|
(e) => {
|
|
2496
|
-
clearDragTimer();
|
|
2600
|
+
drag.clearDragTimer();
|
|
2497
2601
|
if (isDraggingRef.current) {
|
|
2498
2602
|
e.preventDefault();
|
|
2499
2603
|
e.stopPropagation();
|
|
2500
|
-
|
|
2604
|
+
drag.handleDragEnd();
|
|
2501
2605
|
return;
|
|
2502
2606
|
}
|
|
2503
2607
|
e.preventDefault();
|
|
@@ -2506,15 +2610,15 @@ function useTouchHandlers({
|
|
|
2506
2610
|
onRelease(buttonType);
|
|
2507
2611
|
}
|
|
2508
2612
|
},
|
|
2509
|
-
[
|
|
2613
|
+
[drag, isSystemButton, buttonType, onRelease]
|
|
2510
2614
|
);
|
|
2511
2615
|
const handleTouchCancel = useCallback(
|
|
2512
2616
|
(e) => {
|
|
2513
|
-
clearDragTimer();
|
|
2617
|
+
drag.clearDragTimer();
|
|
2514
2618
|
if (isDraggingRef.current) {
|
|
2515
2619
|
e.preventDefault();
|
|
2516
2620
|
e.stopPropagation();
|
|
2517
|
-
|
|
2621
|
+
drag.handleDragEnd();
|
|
2518
2622
|
return;
|
|
2519
2623
|
}
|
|
2520
2624
|
e.preventDefault();
|
|
@@ -2523,11 +2627,11 @@ function useTouchHandlers({
|
|
|
2523
2627
|
onRelease(buttonType);
|
|
2524
2628
|
}
|
|
2525
2629
|
},
|
|
2526
|
-
[
|
|
2630
|
+
[drag, isSystemButton, buttonType, onRelease]
|
|
2527
2631
|
);
|
|
2528
2632
|
const cleanup = useCallback(() => {
|
|
2529
|
-
clearDragTimer();
|
|
2530
|
-
}, [
|
|
2633
|
+
drag.clearDragTimer();
|
|
2634
|
+
}, [drag]);
|
|
2531
2635
|
return {
|
|
2532
2636
|
handleTouchStart,
|
|
2533
2637
|
handleTouchMove,
|
|
@@ -3383,7 +3487,6 @@ function dispatchKeyboardEvent(type, code) {
|
|
|
3383
3487
|
canvas.dispatchEvent(event);
|
|
3384
3488
|
return true;
|
|
3385
3489
|
}
|
|
3386
|
-
var DRAG_HOLD_DELAY2 = 350;
|
|
3387
3490
|
var CENTER_TOUCH_RADIUS = 0.25;
|
|
3388
3491
|
var Dpad = React2.memo(function Dpad2({
|
|
3389
3492
|
size = 180,
|
|
@@ -3400,10 +3503,6 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3400
3503
|
const dpadRef = useRef(null);
|
|
3401
3504
|
const activeTouchRef = useRef(null);
|
|
3402
3505
|
const activeDirectionsRef = useRef(/* @__PURE__ */ new Set());
|
|
3403
|
-
const [isDragging, setIsDragging] = useState(false);
|
|
3404
|
-
const dragTimerRef = useRef(null);
|
|
3405
|
-
const dragStartRef = useRef({ x: 0, y: 0, touchX: 0, touchY: 0 });
|
|
3406
|
-
const touchStartPosRef = useRef({ x: 0, y: 0, time: 0 });
|
|
3407
3506
|
const upPathRef = useRef(null);
|
|
3408
3507
|
const downPathRef = useRef(null);
|
|
3409
3508
|
const leftPathRef = useRef(null);
|
|
@@ -3411,6 +3510,13 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3411
3510
|
const centerCircleRef = useRef(null);
|
|
3412
3511
|
const displayX = customPosition ? customPosition.x : x;
|
|
3413
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
|
+
}, []);
|
|
3414
3520
|
const getKeyCode = useCallback((direction) => {
|
|
3415
3521
|
if (!controls) {
|
|
3416
3522
|
const defaults = {
|
|
@@ -3423,6 +3529,19 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3423
3529
|
}
|
|
3424
3530
|
return controls[direction] || "";
|
|
3425
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
|
+
});
|
|
3426
3545
|
const getDirectionsFromTouch = useCallback((touchX, touchY, rect) => {
|
|
3427
3546
|
const centerX = rect.left + rect.width / 2;
|
|
3428
3547
|
const centerY = rect.top + rect.height / 2;
|
|
@@ -3484,51 +3603,20 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3484
3603
|
activeDirectionsRef.current = newDirections;
|
|
3485
3604
|
updateVisuals(newDirections);
|
|
3486
3605
|
}, [getKeyCode, updateVisuals]);
|
|
3487
|
-
const clearDragTimer = useCallback(() => {
|
|
3488
|
-
if (dragTimerRef.current) {
|
|
3489
|
-
clearTimeout(dragTimerRef.current);
|
|
3490
|
-
dragTimerRef.current = null;
|
|
3491
|
-
}
|
|
3492
|
-
}, []);
|
|
3493
|
-
const startDragging = useCallback((touchX, touchY) => {
|
|
3494
|
-
setIsDragging(true);
|
|
3495
|
-
dragStartRef.current = {
|
|
3496
|
-
x: displayX,
|
|
3497
|
-
y: displayY,
|
|
3498
|
-
touchX,
|
|
3499
|
-
touchY
|
|
3500
|
-
};
|
|
3501
|
-
activeDirectionsRef.current.forEach((dir) => {
|
|
3502
|
-
const keyCode = getKeyCode(dir);
|
|
3503
|
-
if (keyCode) dispatchKeyboardEvent("keyup", keyCode);
|
|
3504
|
-
});
|
|
3505
|
-
activeDirectionsRef.current = /* @__PURE__ */ new Set();
|
|
3506
|
-
updateVisuals(/* @__PURE__ */ new Set());
|
|
3507
|
-
if (navigator.vibrate) navigator.vibrate([10, 30, 10]);
|
|
3508
|
-
}, [displayX, displayY, getKeyCode, updateVisuals]);
|
|
3509
3606
|
const handleTouchStart = useCallback((e) => {
|
|
3510
3607
|
e.preventDefault();
|
|
3511
3608
|
if (activeTouchRef.current !== null) return;
|
|
3512
3609
|
const touch = e.changedTouches[0];
|
|
3513
3610
|
activeTouchRef.current = touch.identifier;
|
|
3514
|
-
touchStartPosRef.current = { x: touch.clientX, y: touch.clientY, time: Date.now() };
|
|
3515
3611
|
const rect = dpadRef.current?.getBoundingClientRect();
|
|
3516
3612
|
if (!rect) return;
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
const distFromCenter = Math.sqrt(
|
|
3520
|
-
Math.pow(touch.clientX - centerX, 2) + Math.pow(touch.clientY - centerY, 2)
|
|
3521
|
-
);
|
|
3522
|
-
const centerRadius = size * CENTER_TOUCH_RADIUS;
|
|
3523
|
-
if (distFromCenter < centerRadius && onPositionChange) {
|
|
3524
|
-
dragTimerRef.current = setTimeout(() => {
|
|
3525
|
-
startDragging(touch.clientX, touch.clientY);
|
|
3526
|
-
}, DRAG_HOLD_DELAY2);
|
|
3613
|
+
if (onPositionChange) {
|
|
3614
|
+
drag.checkDragStart(touch.clientX, touch.clientY, rect);
|
|
3527
3615
|
}
|
|
3528
|
-
if (!isDragging) {
|
|
3616
|
+
if (!drag.isDragging) {
|
|
3529
3617
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
3530
3618
|
}
|
|
3531
|
-
}, [getDirectionsFromTouch, updateDirections,
|
|
3619
|
+
}, [getDirectionsFromTouch, updateDirections, onPositionChange, drag]);
|
|
3532
3620
|
const handleTouchMove = useCallback((e) => {
|
|
3533
3621
|
e.preventDefault();
|
|
3534
3622
|
let touch = null;
|
|
@@ -3539,31 +3627,19 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3539
3627
|
}
|
|
3540
3628
|
}
|
|
3541
3629
|
if (!touch) return;
|
|
3542
|
-
if (isDragging
|
|
3543
|
-
|
|
3544
|
-
const deltaY = touch.clientY - dragStartRef.current.touchY;
|
|
3545
|
-
const newXPercent = dragStartRef.current.x + deltaX / containerWidth * 100;
|
|
3546
|
-
const newYPercent = dragStartRef.current.y + deltaY / containerHeight * 100;
|
|
3547
|
-
const margin = size / 2 / Math.min(containerWidth, containerHeight) * 100;
|
|
3548
|
-
const constrainedX = Math.max(margin, Math.min(100 - margin, newXPercent));
|
|
3549
|
-
const constrainedY = Math.max(margin, Math.min(100 - margin, newYPercent));
|
|
3550
|
-
onPositionChange(constrainedX, constrainedY);
|
|
3630
|
+
if (drag.isDragging) {
|
|
3631
|
+
drag.handleDragMove(touch.clientX, touch.clientY);
|
|
3551
3632
|
} else {
|
|
3552
|
-
const moveDistance = Math.sqrt(
|
|
3553
|
-
Math.pow(touch.clientX - touchStartPosRef.current.x, 2) + Math.pow(touch.clientY - touchStartPosRef.current.y, 2)
|
|
3554
|
-
);
|
|
3555
|
-
if (moveDistance > 15) {
|
|
3556
|
-
clearDragTimer();
|
|
3557
|
-
}
|
|
3558
3633
|
const rect = dpadRef.current?.getBoundingClientRect();
|
|
3559
3634
|
if (rect) {
|
|
3635
|
+
drag.clearDragTimer();
|
|
3560
3636
|
updateDirections(getDirectionsFromTouch(touch.clientX, touch.clientY, rect));
|
|
3561
3637
|
}
|
|
3562
3638
|
}
|
|
3563
|
-
}, [
|
|
3639
|
+
}, [drag, getDirectionsFromTouch, updateDirections]);
|
|
3564
3640
|
const handleTouchEnd = useCallback((e) => {
|
|
3565
3641
|
e.preventDefault();
|
|
3566
|
-
clearDragTimer();
|
|
3642
|
+
drag.clearDragTimer();
|
|
3567
3643
|
let touchEnded = false;
|
|
3568
3644
|
for (let i = 0; i < e.changedTouches.length; i++) {
|
|
3569
3645
|
if (e.changedTouches[i].identifier === activeTouchRef.current) {
|
|
@@ -3573,8 +3649,8 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3573
3649
|
}
|
|
3574
3650
|
if (touchEnded) {
|
|
3575
3651
|
activeTouchRef.current = null;
|
|
3576
|
-
if (isDragging) {
|
|
3577
|
-
|
|
3652
|
+
if (drag.isDragging) {
|
|
3653
|
+
drag.handleDragEnd();
|
|
3578
3654
|
} else {
|
|
3579
3655
|
activeDirectionsRef.current.forEach((dir) => {
|
|
3580
3656
|
const keyCode = getKeyCode(dir);
|
|
@@ -3584,7 +3660,7 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3584
3660
|
updateVisuals(/* @__PURE__ */ new Set());
|
|
3585
3661
|
}
|
|
3586
3662
|
}
|
|
3587
|
-
}, [getKeyCode, updateVisuals,
|
|
3663
|
+
}, [getKeyCode, updateVisuals, drag]);
|
|
3588
3664
|
useEffect(() => {
|
|
3589
3665
|
const dpad = dpadRef.current;
|
|
3590
3666
|
if (!dpad) return;
|
|
@@ -3597,9 +3673,9 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3597
3673
|
dpad.removeEventListener("touchmove", handleTouchMove);
|
|
3598
3674
|
dpad.removeEventListener("touchend", handleTouchEnd);
|
|
3599
3675
|
dpad.removeEventListener("touchcancel", handleTouchEnd);
|
|
3600
|
-
clearDragTimer();
|
|
3676
|
+
drag.clearDragTimer();
|
|
3601
3677
|
};
|
|
3602
|
-
}, [handleTouchStart, handleTouchMove, handleTouchEnd,
|
|
3678
|
+
}, [handleTouchStart, handleTouchMove, handleTouchEnd, drag]);
|
|
3603
3679
|
const leftPx = displayX / 100 * containerWidth - size / 2;
|
|
3604
3680
|
const topPx = displayY / 100 * containerHeight - size / 2;
|
|
3605
3681
|
const dUp = "M 35,5 L 65,5 L 65,35 L 50,50 L 35,35 Z";
|
|
@@ -3610,21 +3686,21 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3610
3686
|
"div",
|
|
3611
3687
|
{
|
|
3612
3688
|
ref: dpadRef,
|
|
3613
|
-
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" : ""}`,
|
|
3614
3690
|
style: {
|
|
3615
3691
|
top: 0,
|
|
3616
3692
|
left: 0,
|
|
3617
|
-
transform: `translate3d(${leftPx}px, ${topPx}px, 0)${isDragging ? " scale(1.05)" : ""}`,
|
|
3693
|
+
transform: `translate3d(${leftPx}px, ${topPx}px, 0)${drag.isDragging ? " scale(1.05)" : ""}`,
|
|
3618
3694
|
width: size,
|
|
3619
3695
|
height: size,
|
|
3620
3696
|
opacity: isLandscape ? 0.75 : 0.9,
|
|
3621
3697
|
WebkitTouchCallout: "none",
|
|
3622
3698
|
WebkitUserSelect: "none",
|
|
3623
3699
|
touchAction: "none",
|
|
3624
|
-
transition: isDragging ? "none" : "transform 0.1s ease-out"
|
|
3700
|
+
transition: drag.isDragging ? "none" : "transform 0.1s ease-out"
|
|
3625
3701
|
},
|
|
3626
3702
|
children: [
|
|
3627
|
-
/* @__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"}` }),
|
|
3628
3704
|
/* @__PURE__ */ jsxs("svg", { width: "100%", height: "100%", viewBox: "0 0 100 100", className: "drop-shadow-xl relative z-10", children: [
|
|
3629
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" }),
|
|
3630
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" }),
|
|
@@ -3637,9 +3713,9 @@ var Dpad = React2.memo(function Dpad2({
|
|
|
3637
3713
|
cx: "50",
|
|
3638
3714
|
cy: "50",
|
|
3639
3715
|
r: "12",
|
|
3640
|
-
fill: isDragging ? systemColor : "rgba(0,0,0,0.5)",
|
|
3641
|
-
stroke: isDragging ? "#fff" : "rgba(255,255,255,0.3)",
|
|
3642
|
-
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
|
|
3643
3719
|
}
|
|
3644
3720
|
),
|
|
3645
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" }),
|
|
@@ -4067,6 +4143,45 @@ function FloatingFullscreenButton({ onClick, disabled = false }) {
|
|
|
4067
4143
|
}
|
|
4068
4144
|
);
|
|
4069
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
|
+
}
|
|
4070
4185
|
function LoadingSpinner({ color, size = "lg" }) {
|
|
4071
4186
|
const sizeClass = size === "lg" ? "w-12 h-12" : "w-8 h-8";
|
|
4072
4187
|
return /* @__PURE__ */ jsx(Loader2, { className: `${sizeClass} animate-spin`, style: { color } });
|
|
@@ -9200,6 +9315,14 @@ var GamePlayerInner = memo(function GamePlayerInner2(props) {
|
|
|
9200
9315
|
disabled: status === "loading" || status === "error"
|
|
9201
9316
|
}
|
|
9202
9317
|
),
|
|
9318
|
+
isFullscreen2 && isMobile && (status === "running" || status === "paused") && /* @__PURE__ */ jsx(
|
|
9319
|
+
FloatingPauseButton,
|
|
9320
|
+
{
|
|
9321
|
+
isPaused,
|
|
9322
|
+
onClick: handlePauseToggle,
|
|
9323
|
+
systemColor
|
|
9324
|
+
}
|
|
9325
|
+
),
|
|
9203
9326
|
/* @__PURE__ */ jsxs("div", { className: "absolute top-2 right-2 z-40 flex flex-col items-end gap-2 pointer-events-auto", children: [
|
|
9204
9327
|
/* @__PURE__ */ jsx(
|
|
9205
9328
|
RecordingIndicator_default,
|