@scriptonita/chess-football-ui 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -149,6 +149,7 @@ var Football = ({ className }) => {
149
149
  var STATIC_I18N_KEYS = [
150
150
  "actionPointsAriaLabel",
151
151
  "actionPointsShort",
152
+ "ballHolder",
152
153
  "endTurn",
153
154
  "endTurnConfirm",
154
155
  "endTurnConfirmDescription",
@@ -293,6 +294,7 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
293
294
  return [];
294
295
  }, [boardState, selectedPieceId]);
295
296
  if (!boardState) return null;
297
+ const ballHolderPiece = boardState.pieces.find((p) => p.id === boardState.ball.holderId) ?? null;
296
298
  const lastMove = boardState.lastMove;
297
299
  const ball = boardState.ball;
298
300
  const ballMoved = !!prevBall && (prevBall.pos.x !== ball.pos.x || prevBall.pos.y !== ball.pos.y);
@@ -529,7 +531,7 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
529
531
  }
530
532
  return squares;
531
533
  };
532
- const board = /* @__PURE__ */ jsxRuntime.jsx(
534
+ const board = /* @__PURE__ */ jsxRuntime.jsxs(
533
535
  "div",
534
536
  {
535
537
  className: cn(
@@ -546,198 +548,220 @@ function GameBoard({ userSide, showCoordinates = false, keyboardNav = true }) {
546
548
  "aria-label": "Game board \u2014 arrow keys to move the cursor, Enter to act",
547
549
  onKeyDown: handleKeyDown
548
550
  } : {},
549
- children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", style: { containerType: "inline-size" }, children: [
550
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px]", children: renderSquares() }),
551
- /* @__PURE__ */ jsxRuntime.jsxs(
552
- "svg",
553
- {
554
- viewBox: "0 0 9 12",
555
- preserveAspectRatio: "none",
556
- className: "absolute inset-0 w-full h-full pointer-events-none",
557
- "aria-hidden": "true",
558
- children: [
559
- /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "0", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
560
- /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "10", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
561
- /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "0", y1: "6", x2: "9", y2: "6", stroke: "white", strokeOpacity: "0.35", strokeWidth: "0.05" }),
562
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "1.5", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
563
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "0.12", fill: "white", fillOpacity: "0.5" }),
564
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "1.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
565
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "10.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
566
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 3.086,2 A 1.5,1.5 0 0 0 5.914,2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
567
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 3.086,10 A 1.5,1.5 0 0 1 5.914,10", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
568
- hoveredPassAt && passCarrier && /* @__PURE__ */ jsxRuntime.jsx(
569
- "line",
570
- {
571
- "data-testid": "pass-trajectory-line",
572
- x1: passCarrier.pos.x + 0.5,
573
- y1: ROWS - 1 - passCarrier.pos.y + 0.5,
574
- x2: hoveredPassAt.x + 0.5,
575
- y2: ROWS - 1 - hoveredPassAt.y + 0.5,
576
- stroke: trajectoryIntercepted ? "var(--danger)" : "var(--pass-highlight)",
577
- strokeWidth: "0.08",
578
- strokeDasharray: "0.15 0.1",
579
- strokeLinecap: "round"
580
- }
581
- )
582
- ]
583
- }
584
- ),
585
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", children: [
586
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "sync", children: boardState.pieces.map((piece) => {
587
- const isPickupCarrier = pickupCarrierId === piece.id;
588
- const pieceTransition = isPickupCarrier ? { duration: PICKUP_DURATION, ease: "linear" } : { type: "spring", stiffness: 200, damping: 25, mass: 1 };
589
- return /* @__PURE__ */ jsxRuntime.jsx(
590
- framerMotion.motion.div,
551
+ children: [
552
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "hidden md:flex items-center justify-between gap-2 px-2.5 py-1", children: [
553
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1.5 min-h-[1.75rem]", "aria-live": "polite", children: ballHolderPiece && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
554
+ /* @__PURE__ */ jsxRuntime.jsxs(
555
+ "div",
591
556
  {
592
- layout: true,
593
- initial: false,
594
- animate: {
595
- left: `${piece.pos.x / COLS * 100}%`,
596
- top: `${(ROWS - 1 - piece.pos.y) / ROWS * 100}%`
597
- },
598
- transition: pieceTransition,
599
- style: {
600
- position: "absolute",
601
- width: `${100 / COLS}%`,
602
- height: `${100 / ROWS}%`
603
- },
604
- className: "flex items-center justify-center pointer-events-auto",
605
- children: /* @__PURE__ */ jsxRuntime.jsx(
606
- GamePiece,
557
+ style: ballHolderPiece.side === "white" ? WHITE_PIECE_STYLE : BLACK_PIECE_STYLE,
558
+ className: "relative w-7 h-7 flex items-center justify-center rounded-full shrink-0",
559
+ children: [
560
+ /* @__PURE__ */ jsxRuntime.jsx(PieceIcon, { type: ballHolderPiece.type, side: ballHolderPiece.side }),
561
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -bottom-1 -right-1 w-3.5 h-3.5 flex items-center justify-center rounded-full bg-bg-secondary border border-border-subtle", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2.5 h-2.5", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) }) })
562
+ ]
563
+ }
564
+ ),
565
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-inter text-[11px] text-fg-secondary", children: [
566
+ t("ballHolder"),
567
+ ": ",
568
+ t(`pieces.${ballHolderPiece.type}`)
569
+ ] })
570
+ ] }) }),
571
+ keyboardNav && /* @__PURE__ */ jsxRuntime.jsxs(
572
+ "div",
573
+ {
574
+ ref: shortcutsRef,
575
+ className: "relative",
576
+ onKeyDown: (e) => e.stopPropagation(),
577
+ children: [
578
+ /* @__PURE__ */ jsxRuntime.jsx(
579
+ "button",
607
580
  {
608
- piece,
609
- isSelected: selectedPieceId === piece.id,
610
- hasBall: boardState.ball.holderId === piece.id,
611
- onClick: (e) => handlePieceClick(piece.id, piece.pos.x, piece.pos.y, e)
581
+ type: "button",
582
+ onClick: (e) => {
583
+ e.stopPropagation();
584
+ setShortcutsOpen((o) => !o);
585
+ },
586
+ "aria-label": t("shortcuts.buttonLabel"),
587
+ "aria-expanded": shortcutsOpen,
588
+ className: "w-8 h-8 flex items-center justify-center rounded-full bg-bg-secondary/80 border border-border-subtle text-fg-muted hover:text-fg-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-green",
589
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircle, { size: 16, strokeWidth: 2, "aria-hidden": "true" })
590
+ }
591
+ ),
592
+ shortcutsOpen && /* @__PURE__ */ jsxRuntime.jsxs(
593
+ "div",
594
+ {
595
+ className: "absolute top-full right-0 mt-1 z-50 w-max max-w-[220px] bg-bg-secondary border border-border-subtle rounded-md shadow-xl p-2.5 pointer-events-auto",
596
+ onClick: (e) => e.stopPropagation(),
597
+ children: [
598
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-inter text-[11px] font-semibold text-fg-primary mb-1.5", children: t("shortcuts.title") }),
599
+ /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "font-mono text-[10px] text-fg-secondary leading-relaxed", children: [
600
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
601
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "\u2191\u2193\u2190\u2192" }),
602
+ " ",
603
+ t("shortcuts.arrows")
604
+ ] }),
605
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
606
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Enter" }),
607
+ " ",
608
+ t("shortcuts.select")
609
+ ] }),
610
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
611
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "M" }),
612
+ " ",
613
+ t("shortcuts.move")
614
+ ] }),
615
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
616
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "P" }),
617
+ " ",
618
+ t("shortcuts.pass")
619
+ ] }),
620
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
621
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Esc" }),
622
+ " ",
623
+ t("shortcuts.cancel")
624
+ ] })
625
+ ] })
626
+ ]
612
627
  }
613
628
  )
614
- },
615
- piece.id
616
- );
617
- }) }),
618
- (() => {
619
- const targetX = ball.pos.x / COLS * 100;
620
- const targetY = (ROWS - 1 - ball.pos.y) / ROWS * 100;
621
- let animate;
622
- let transition;
623
- if (isPickupOnMove && prevBall) {
624
- const prevX = prevBall.pos.x / COLS * 100;
625
- const prevY = (ROWS - 1 - prevBall.pos.y) / ROWS * 100;
626
- const pulseStart = Math.max(0.05, pickupProportion - 0.06);
627
- animate = {
628
- left: [`${prevX}%`, `${prevX}%`, `${prevX}%`, `${targetX}%`],
629
- top: [`${prevY}%`, `${prevY}%`, `${prevY}%`, `${targetY}%`],
630
- scale: [1, 1, 1.35, 1]
631
- };
632
- transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
633
- } else {
634
- animate = { left: `${targetX}%`, top: `${targetY}%`, scale: 1 };
635
- transition = { type: "spring", stiffness: 300, damping: 30, mass: 0.5 };
629
+ ]
630
+ }
631
+ )
632
+ ] }),
633
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", style: { containerType: "inline-size" }, children: [
634
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-9 gap-[1px]", children: renderSquares() }),
635
+ /* @__PURE__ */ jsxRuntime.jsxs(
636
+ "svg",
637
+ {
638
+ viewBox: "0 0 9 12",
639
+ preserveAspectRatio: "none",
640
+ className: "absolute inset-0 w-full h-full pointer-events-none",
641
+ "aria-hidden": "true",
642
+ children: [
643
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "0", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
644
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "2", y: "10", width: "5", height: "2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
645
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "0", y1: "6", x2: "9", y2: "6", stroke: "white", strokeOpacity: "0.35", strokeWidth: "0.05" }),
646
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "1.5", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
647
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "6", r: "0.12", fill: "white", fillOpacity: "0.5" }),
648
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "1.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
649
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "4.5", cy: "10.5", r: "0.1", fill: "white", fillOpacity: "0.5" }),
650
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 3.086,2 A 1.5,1.5 0 0 0 5.914,2", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
651
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M 3.086,10 A 1.5,1.5 0 0 1 5.914,10", fill: "none", stroke: "white", strokeOpacity: "0.3", strokeWidth: "0.05" }),
652
+ hoveredPassAt && passCarrier && /* @__PURE__ */ jsxRuntime.jsx(
653
+ "line",
654
+ {
655
+ "data-testid": "pass-trajectory-line",
656
+ x1: passCarrier.pos.x + 0.5,
657
+ y1: ROWS - 1 - passCarrier.pos.y + 0.5,
658
+ x2: hoveredPassAt.x + 0.5,
659
+ y2: ROWS - 1 - hoveredPassAt.y + 0.5,
660
+ stroke: trajectoryIntercepted ? "var(--danger)" : "var(--pass-highlight)",
661
+ strokeWidth: "0.08",
662
+ strokeDasharray: "0.15 0.1",
663
+ strokeLinecap: "round"
664
+ }
665
+ )
666
+ ]
636
667
  }
637
- return /* @__PURE__ */ jsxRuntime.jsx(
668
+ ),
669
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 pointer-events-none", children: [
670
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { mode: "sync", children: boardState.pieces.map((piece) => {
671
+ const isPickupCarrier = pickupCarrierId === piece.id;
672
+ const pieceTransition = isPickupCarrier ? { duration: PICKUP_DURATION, ease: "linear" } : { type: "spring", stiffness: 200, damping: 25, mass: 1 };
673
+ return /* @__PURE__ */ jsxRuntime.jsx(
674
+ framerMotion.motion.div,
675
+ {
676
+ layout: true,
677
+ initial: false,
678
+ animate: {
679
+ left: `${piece.pos.x / COLS * 100}%`,
680
+ top: `${(ROWS - 1 - piece.pos.y) / ROWS * 100}%`
681
+ },
682
+ transition: pieceTransition,
683
+ style: {
684
+ position: "absolute",
685
+ width: `${100 / COLS}%`,
686
+ height: `${100 / ROWS}%`
687
+ },
688
+ className: "flex items-center justify-center pointer-events-auto",
689
+ children: /* @__PURE__ */ jsxRuntime.jsx(
690
+ GamePiece,
691
+ {
692
+ piece,
693
+ isSelected: selectedPieceId === piece.id,
694
+ hasBall: boardState.ball.holderId === piece.id,
695
+ onClick: (e) => handlePieceClick(piece.id, piece.pos.x, piece.pos.y, e)
696
+ }
697
+ )
698
+ },
699
+ piece.id
700
+ );
701
+ }) }),
702
+ (() => {
703
+ const targetX = ball.pos.x / COLS * 100;
704
+ const targetY = (ROWS - 1 - ball.pos.y) / ROWS * 100;
705
+ let animate;
706
+ let transition;
707
+ if (isPickupOnMove && prevBall) {
708
+ const prevX = prevBall.pos.x / COLS * 100;
709
+ const prevY = (ROWS - 1 - prevBall.pos.y) / ROWS * 100;
710
+ const pulseStart = Math.max(0.05, pickupProportion - 0.06);
711
+ animate = {
712
+ left: [`${prevX}%`, `${prevX}%`, `${prevX}%`, `${targetX}%`],
713
+ top: [`${prevY}%`, `${prevY}%`, `${prevY}%`, `${targetY}%`],
714
+ scale: [1, 1, 1.35, 1]
715
+ };
716
+ transition = { duration: PICKUP_DURATION, times: [0, pulseStart, pickupProportion, 1], ease: "linear" };
717
+ } else {
718
+ animate = { left: `${targetX}%`, top: `${targetY}%`, scale: 1 };
719
+ transition = { type: "spring", stiffness: 300, damping: 30, mass: 0.5 };
720
+ }
721
+ return /* @__PURE__ */ jsxRuntime.jsx(
722
+ framerMotion.motion.div,
723
+ {
724
+ initial: false,
725
+ animate,
726
+ transition,
727
+ style: {
728
+ position: "absolute",
729
+ width: `${100 / COLS}%`,
730
+ height: `${100 / ROWS}%`,
731
+ zIndex: 50
732
+ },
733
+ className: "flex items-center justify-center pointer-events-none",
734
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[60%] h-[60%]", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) })
735
+ },
736
+ "ball"
737
+ );
738
+ })(),
739
+ invalidClickAt && /* @__PURE__ */ jsxRuntime.jsx(
638
740
  framerMotion.motion.div,
639
741
  {
742
+ "data-testid": "invalid-action-shake",
743
+ "aria-hidden": "true",
640
744
  initial: false,
641
- animate,
642
- transition,
745
+ animate: prefersReducedMotion ? { opacity: [0.9, 0] } : { x: [0, -3, 3, -3, 3, 0] },
746
+ transition: { duration: 0.08 },
643
747
  style: {
644
748
  position: "absolute",
749
+ left: `${invalidClickAt.x / COLS * 100}%`,
750
+ top: `${(ROWS - 1 - invalidClickAt.y) / ROWS * 100}%`,
645
751
  width: `${100 / COLS}%`,
646
- height: `${100 / ROWS}%`,
647
- zIndex: 50
752
+ height: `${100 / ROWS}%`
648
753
  },
649
- className: "flex items-center justify-center pointer-events-none",
650
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[60%] h-[60%]", children: /* @__PURE__ */ jsxRuntime.jsx(Football, {}) })
651
- },
652
- "ball"
653
- );
654
- })(),
655
- invalidClickAt && /* @__PURE__ */ jsxRuntime.jsx(
656
- framerMotion.motion.div,
657
- {
658
- "data-testid": "invalid-action-shake",
659
- "aria-hidden": "true",
660
- initial: false,
661
- animate: prefersReducedMotion ? { opacity: [0.9, 0] } : { x: [0, -3, 3, -3, 3, 0] },
662
- transition: { duration: 0.08 },
663
- style: {
664
- position: "absolute",
665
- left: `${invalidClickAt.x / COLS * 100}%`,
666
- top: `${(ROWS - 1 - invalidClickAt.y) / ROWS * 100}%`,
667
- width: `${100 / COLS}%`,
668
- height: `${100 / ROWS}%`
754
+ className: "ring-2 ring-inset ring-danger/70 rounded-sm"
669
755
  },
670
- className: "ring-2 ring-inset ring-danger/70 rounded-sm"
671
- },
672
- invalidClickAt.nonce
673
- )
674
- ] }),
675
- isOffsideRisk && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 z-30 flex items-center gap-1.5 px-3 py-1.5 bg-warning/20 border border-warning/50 rounded-full font-inter text-xs font-semibold text-warning pointer-events-none whitespace-nowrap backdrop-blur-sm", children: [
676
- "\u26A0 ",
677
- t("offsideWarning")
678
- ] }),
679
- keyboardNav && /* @__PURE__ */ jsxRuntime.jsxs(
680
- "div",
681
- {
682
- ref: shortcutsRef,
683
- className: "hidden md:block absolute top-2 right-2 z-40",
684
- onKeyDown: (e) => e.stopPropagation(),
685
- children: [
686
- /* @__PURE__ */ jsxRuntime.jsx(
687
- "button",
688
- {
689
- type: "button",
690
- onClick: (e) => {
691
- e.stopPropagation();
692
- setShortcutsOpen((o) => !o);
693
- },
694
- "aria-label": t("shortcuts.buttonLabel"),
695
- "aria-expanded": shortcutsOpen,
696
- className: "w-11 h-11 flex items-center justify-center rounded-full bg-bg-secondary/80 border border-border-subtle text-fg-muted hover:text-fg-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-green backdrop-blur-sm",
697
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.HelpCircle, { size: 16, strokeWidth: 2, "aria-hidden": "true" })
698
- }
699
- ),
700
- shortcutsOpen && /* @__PURE__ */ jsxRuntime.jsxs(
701
- "div",
702
- {
703
- className: "absolute top-full right-0 mt-1 z-50 w-max max-w-[220px] bg-bg-secondary border border-border-subtle rounded-md shadow-xl p-2.5 pointer-events-auto",
704
- onClick: (e) => e.stopPropagation(),
705
- children: [
706
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-inter text-[11px] font-semibold text-fg-primary mb-1.5", children: t("shortcuts.title") }),
707
- /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "font-mono text-[10px] text-fg-secondary leading-relaxed", children: [
708
- /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
709
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "\u2191\u2193\u2190\u2192" }),
710
- " ",
711
- t("shortcuts.arrows")
712
- ] }),
713
- /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
714
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Enter" }),
715
- " ",
716
- t("shortcuts.select")
717
- ] }),
718
- /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
719
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "M" }),
720
- " ",
721
- t("shortcuts.move")
722
- ] }),
723
- /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
724
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "P" }),
725
- " ",
726
- t("shortcuts.pass")
727
- ] }),
728
- /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
729
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "text-fg-primary", children: "Esc" }),
730
- " ",
731
- t("shortcuts.cancel")
732
- ] })
733
- ] })
734
- ]
735
- }
736
- )
737
- ]
738
- }
739
- )
740
- ] })
756
+ invalidClickAt.nonce
757
+ )
758
+ ] }),
759
+ isOffsideRisk && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 z-30 flex items-center gap-1.5 px-3 py-1.5 bg-warning/20 border border-warning/50 rounded-full font-inter text-xs font-semibold text-warning pointer-events-none whitespace-nowrap backdrop-blur-sm", children: [
760
+ "\u26A0 ",
761
+ t("offsideWarning")
762
+ ] })
763
+ ] })
764
+ ]
741
765
  }
742
766
  );
743
767
  if (!showCoordinates) return board;