@tastic/hud 0.13.0 → 0.14.1

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 CHANGED
@@ -38,22 +38,22 @@ __export(TriggerGauge_exports, {
38
38
  function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, dashWidth, startDeg = DEFAULT_START_DEG, endDeg = startDeg }) {
39
39
  const totalDurationMs = MOUNT_DURATION_MS + Math.max(0, segments - 1) * MOUNT_STAGGER_MS;
40
40
  const mountProgress = (0, import_react_native_reanimated.useSharedValue)(0);
41
- (0, import_react6.useLayoutEffect)(() => {
41
+ (0, import_react7.useLayoutEffect)(() => {
42
42
  mountProgress.value = (0, import_react_native_reanimated.withTiming)(1, { duration: totalDurationMs, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
43
43
  }, []);
44
44
  const rawSweepDeg = ((endDeg - startDeg) % 360 + 360) % 360;
45
45
  const totalSweepDeg = rawSweepDeg === 0 ? 360 : rawSweepDeg;
46
46
  const step = segments > 0 ? totalSweepDeg / segments : 0;
47
- const centerDeg = (0, import_react6.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
47
+ const centerDeg = (0, import_react7.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
48
48
  const singleSelect = litIndices.length === 1;
49
49
  const angleDeg = (0, import_react_native_reanimated.useSharedValue)(centerDeg(litIndices[0] ?? 0));
50
50
  const litIndicesKey = [...litIndices].sort((a, b) => a - b).join(",");
51
- const [transitionFrom, setTransitionFrom] = (0, import_react6.useState)(litIndices);
51
+ const [transitionFrom, setTransitionFrom] = (0, import_react7.useState)(litIndices);
52
52
  const transitionFromKey = [...transitionFrom].sort((a, b) => a - b).join(",");
53
- const lastKeyRef = (0, import_react6.useRef)(litIndicesKey);
54
- const lastIndicesRef = (0, import_react6.useRef)(litIndices);
53
+ const lastKeyRef = (0, import_react7.useRef)(litIndicesKey);
54
+ const lastIndicesRef = (0, import_react7.useRef)(litIndices);
55
55
  const selectionProgress = (0, import_react_native_reanimated.useSharedValue)(1);
56
- (0, import_react6.useLayoutEffect)(() => {
56
+ (0, import_react7.useLayoutEffect)(() => {
57
57
  if (litIndicesKey !== lastKeyRef.current) {
58
58
  if (singleSelect && lastIndicesRef.current.length === 1) {
59
59
  angleDeg.value = (0, import_react_native_reanimated.withTiming)(centerDeg(litIndices[0]), { duration: SELECTION_TRANSITION_DURATION_MS, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
@@ -82,7 +82,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
82
82
  if (mountProgress.value < 1) {
83
83
  const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
84
84
  const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
85
- local = (0, import_core5.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
85
+ local = (0, import_core6.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
86
86
  }
87
87
  const sweep = dashAngleDeg * local;
88
88
  if (sweep <= 0) continue;
@@ -106,7 +106,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
106
106
  if (!isLitNow) continue;
107
107
  const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
108
108
  const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
109
- local = (0, import_core5.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
109
+ local = (0, import_core6.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
110
110
  } else if (isLitNow === wasLit) {
111
111
  local = 1;
112
112
  } else if (isLitNow) {
@@ -130,21 +130,21 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
130
130
  height: canvasSize,
131
131
  width: canvasSize
132
132
  };
133
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native13.View, { style: [styles11.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
135
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
133
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native14.View, { style: [styles12.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
136
136
  ] }) });
137
137
  }
138
- var import_react_native_skia, import_core5, import_react6, import_react_native13, import_react_native_reanimated, import_jsx_runtime13, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles11;
138
+ var import_react_native_skia, import_core6, import_react7, import_react_native14, import_react_native_reanimated, import_jsx_runtime14, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles12;
139
139
  var init_TriggerGauge = __esm({
140
140
  "src/TriggerGauge.tsx"() {
141
141
  "use strict";
142
142
  import_react_native_skia = require("@shopify/react-native-skia");
143
- import_core5 = require("@tastic/core");
144
- import_react6 = require("react");
145
- import_react_native13 = require("react-native");
143
+ import_core6 = require("@tastic/core");
144
+ import_react7 = require("react");
145
+ import_react_native14 = require("react-native");
146
146
  import_react_native_reanimated = require("react-native-reanimated");
147
- import_jsx_runtime13 = require("react/jsx-runtime");
147
+ import_jsx_runtime14 = require("react/jsx-runtime");
148
148
  UNLIT_THICKNESS = 3;
149
149
  LIT_THICKNESS = 7;
150
150
  DASH_GAP_PX = 9;
@@ -154,7 +154,7 @@ var init_TriggerGauge = __esm({
154
154
  MOUNT_DURATION_MS = 450;
155
155
  MOUNT_STAGGER_MS = 40;
156
156
  SELECTION_TRANSITION_DURATION_MS = 260;
157
- styles11 = import_react_native13.StyleSheet.create({
157
+ styles12 = import_react_native14.StyleSheet.create({
158
158
  container: {
159
159
  alignItems: "center",
160
160
  justifyContent: "center",
@@ -187,6 +187,7 @@ __export(index_exports, {
187
187
  PopoverBody: () => PopoverBody,
188
188
  PressAwayOverlay: () => PressAwayOverlay,
189
189
  ReadyButton: () => ReadyButton,
190
+ RotatedFrame: () => RotatedFrame,
190
191
  SectionedDropdown: () => SectionedDropdown,
191
192
  SharedActionBand: () => SharedActionBand,
192
193
  SkiaGate: () => SkiaGate,
@@ -419,10 +420,10 @@ function ActivityStatSection({ stats }) {
419
420
  var import_auto_paper7 = require("@rific/auto-paper");
420
421
  var import_feedback_press2 = require("@rific/feedback-press");
421
422
  var import_updater = require("@rific/updater");
422
- var import_core2 = require("@tastic/core");
423
- var import_react3 = require("react");
424
- var import_react_native9 = require("react-native");
425
- var import_react_native_paper7 = require("react-native-paper");
423
+ var import_core3 = require("@tastic/core");
424
+ var import_react4 = require("react");
425
+ var import_react_native10 = require("react-native");
426
+ var import_react_native_paper8 = require("react-native-paper");
426
427
 
427
428
  // src/ConfirmDialog.tsx
428
429
  var import_auto_paper6 = require("@rific/auto-paper");
@@ -550,19 +551,49 @@ var styles6 = import_react_native8.StyleSheet.create({
550
551
  }
551
552
  });
552
553
 
553
- // src/useUpdateConfirmBridge.ts
554
+ // src/RotatedFrame.tsx
555
+ var import_core2 = require("@tastic/core");
554
556
  var import_react2 = require("react");
557
+ var import_react_native9 = require("react-native");
558
+ var import_react_native_paper7 = require("react-native-paper");
559
+ var import_react_native_safe_area_context = require("react-native-safe-area-context");
560
+ var import_jsx_runtime8 = require("react/jsx-runtime");
561
+ function RotatedFrame({ children, rotation: rotationOverride, rotatedSafeArea = false, portalHost = false, passThrough = false, maxContentWidth }) {
562
+ const ambientRotation = (0, import_core2.useRotation)();
563
+ const rotation = rotationOverride ?? ambientRotation;
564
+ const window = (0, import_react_native9.useWindowDimensions)();
565
+ const { width, height } = (0, import_core2.rotateDimensions)(window.width, window.height, rotation);
566
+ const rawInsets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
567
+ const insets = (0, import_react2.useMemo)(() => rotatedSafeArea ? (0, import_core2.rotateInsets)(rawInsets, rotation) : rawInsets, [rotatedSafeArea, rawInsets, rotation]);
568
+ const cappedWidth = maxContentWidth !== void 0 && width > height ? maxContentWidth : void 0;
569
+ const column = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
570
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core2.FakeLandscapeView, { rotation, passThrough, style: styles7.root, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Portal.Host, { children: column }) : column }) });
571
+ }
572
+ var styles7 = import_react_native9.StyleSheet.create({
573
+ // A centred column: full width up to `maxWidth`, so a capped frame sits in the middle of a wider window.
574
+ column: {
575
+ alignSelf: "center",
576
+ flex: 1,
577
+ width: "100%"
578
+ },
579
+ root: {
580
+ flex: 1
581
+ }
582
+ });
583
+
584
+ // src/useUpdateConfirmBridge.ts
585
+ var import_react3 = require("react");
555
586
  function useUpdateConfirmBridge() {
556
- const [manifest, setManifest] = (0, import_react2.useState)(null);
557
- const resolveRef = (0, import_react2.useRef)(null);
558
- const onConfirm = (0, import_react2.useCallback)(
587
+ const [manifest, setManifest] = (0, import_react3.useState)(null);
588
+ const resolveRef = (0, import_react3.useRef)(null);
589
+ const onConfirm = (0, import_react3.useCallback)(
559
590
  (next) => new Promise((resolve) => {
560
591
  resolveRef.current = resolve;
561
592
  setManifest(next);
562
593
  }),
563
594
  []
564
595
  );
565
- const respond = (0, import_react2.useCallback)((confirmed) => {
596
+ const respond = (0, import_react3.useCallback)((confirmed) => {
566
597
  setManifest(null);
567
598
  resolveRef.current?.(confirmed);
568
599
  resolveRef.current = null;
@@ -571,20 +602,20 @@ function useUpdateConfirmBridge() {
571
602
  }
572
603
 
573
604
  // src/BaseSettingsDialog.tsx
574
- var import_jsx_runtime8 = require("react/jsx-runtime");
605
+ var import_jsx_runtime9 = require("react/jsx-runtime");
575
606
  function SettingIcon({ source, color, containerColor }) {
576
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Icon, { source, size: 18, color }) });
607
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Icon, { source, size: 18, color }) });
577
608
  }
578
609
  function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
579
610
  const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
580
- const ambientRotation = (0, import_core2.useRotation)();
611
+ const ambientRotation = (0, import_core3.useRotation)();
581
612
  const rotation = rotationOverride ?? ambientRotation;
582
- const isTouchPrimary = (0, import_core2.useIsTouchPrimaryDevice)();
613
+ const isTouchPrimary = (0, import_core3.useIsTouchPrimaryDevice)();
583
614
  const { settings: hapticSettings, set: setHapticSettings } = (0, import_feedback_press2.useHapticSettings)();
584
615
  const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press2.useSoundSettings)();
585
- const sound = (0, import_react3.useContext)(import_feedback_press2.SoundContext);
616
+ const sound = (0, import_react4.useContext)(import_feedback_press2.SoundContext);
586
617
  const { forceShort: forceHapticFeedback } = (0, import_feedback_press2.useVibration)();
587
- const [infoMessage, setInfoMessage] = (0, import_react3.useState)(null);
618
+ const [infoMessage, setInfoMessage] = (0, import_react4.useState)(null);
588
619
  const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
589
620
  const { check, checking, updateReady } = (0, import_updater.useUpdater)({
590
621
  autoCheck: false,
@@ -594,33 +625,36 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
594
625
  onInfo: (title, message) => setInfoMessage({ title, message })
595
626
  });
596
627
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
628
+ const [opened, setOpened] = (0, import_react4.useState)(visible);
629
+ if (visible && !opened) setOpened(true);
597
630
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
598
- const showEdgeGuard = import_react_native9.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
599
- const showHaptics = import_react_native9.Platform.OS !== "web" && !hideHaptics;
631
+ const showEdgeGuard = import_react_native10.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
632
+ const showHaptics = import_react_native10.Platform.OS !== "web" && !hideHaptics;
600
633
  const showSound = !hideSound;
601
634
  const showAppearance = !hideAppearance;
602
- const showUpdateCheck = import_react_native9.Platform.OS !== "web" && !hideUpdateCheck;
603
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: [styles7.dialog, (0, import_core2.toRotationStyle)(rotation)], children: [
605
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
606
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.Dialog.ScrollArea, { style: styles7.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.ScrollView, { contentContainerStyle: styles7.content, showsVerticalScrollIndicator: false, children: [
607
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleGroup, children: [
608
- showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles7.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
609
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
610
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
611
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
612
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
635
+ const showUpdateCheck = import_react_native10.Platform.OS !== "web" && !hideUpdateCheck;
636
+ if (!opened) return null;
637
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
638
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: styles8.dialog, children: [
639
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
640
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.ScrollArea, { style: styles8.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { contentContainerStyle: styles8.content, showsVerticalScrollIndicator: false, children: [
641
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleGroup, children: [
642
+ showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles8.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
643
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
644
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
645
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
646
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
613
647
  ] })
614
648
  ] }) }),
615
- showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles7.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
616
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
617
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
618
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
619
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
649
+ showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles8.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
650
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
651
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
652
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
653
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
620
654
  ] })
621
655
  ] }) }),
622
- (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleRow, children: [
623
- showSound && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
656
+ (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleRow, children: [
657
+ showSound && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
624
658
  import_feedback_press2.TouchableRipple,
625
659
  {
626
660
  soundDisabled: true,
@@ -629,15 +663,15 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
629
663
  setSoundSettings({ enabled });
630
664
  if (enabled) sound.selection?.();
631
665
  },
632
- style: styles7.toggleButtonInRow,
666
+ style: styles8.toggleButtonInRow,
633
667
  accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
634
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
635
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
636
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
668
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
669
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
637
671
  ] })
638
672
  }
639
673
  ),
640
- showHaptics && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
674
+ showHaptics && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
641
675
  import_feedback_press2.TouchableRipple,
642
676
  {
643
677
  hapticDisabled: true,
@@ -646,54 +680,54 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
646
680
  setHapticSettings({ vibrate });
647
681
  if (vibrate) forceHapticFeedback();
648
682
  },
649
- style: styles7.toggleButtonInRow,
683
+ style: styles8.toggleButtonInRow,
650
684
  accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
651
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
652
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
653
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
685
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
686
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
687
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
654
688
  ] })
655
689
  }
656
690
  )
657
691
  ] }),
658
- onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
692
+ onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
659
693
  import_feedback_press2.TouchableRipple,
660
694
  {
661
695
  onPress: () => {
662
696
  onDismiss();
663
697
  onShowHowToPlay();
664
698
  },
665
- style: styles7.toggleButton,
699
+ style: styles8.toggleButton,
666
700
  accessibilityLabel: "How to Play",
667
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
668
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
669
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
670
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
671
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
701
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
702
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
704
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
705
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
672
706
  ] })
673
707
  ] })
674
708
  }
675
709
  )
676
710
  ] }),
677
- showAppearance && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.section, children: [
678
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "labelMedium", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
679
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.AutoAppearancePicker, { showLabels: false })
711
+ showAppearance && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
712
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "labelMedium", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
713
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.AutoAppearancePicker, { showLabels: false })
680
714
  ] }),
681
715
  children,
682
- showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.section, children: [
683
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_paper7.Text, { variant: "labelSmall", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: [
716
+ showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_paper8.Text, { variant: "labelSmall", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: [
684
718
  "VERSION ",
685
719
  version,
686
720
  updateReady ? " \xB7 UPDATE READY" : ""
687
721
  ] }),
688
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
722
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
689
723
  ] })
690
724
  ] }) })
691
725
  ] }),
692
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
693
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation, onConfirm: () => setInfoMessage(null) })
694
- ] });
726
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation: 0, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
728
+ ] }) });
695
729
  }
696
- var styles7 = import_react_native9.StyleSheet.create({
730
+ var styles8 = import_react_native10.StyleSheet.create({
697
731
  content: {
698
732
  gap: 24,
699
733
  paddingVertical: 20
@@ -763,29 +797,29 @@ var styles7 = import_react_native9.StyleSheet.create({
763
797
  // src/BaseStatsScreen.tsx
764
798
  var import_auto_paper8 = require("@rific/auto-paper");
765
799
  var import_feedback_press3 = require("@rific/feedback-press");
766
- var import_core3 = require("@tastic/core");
767
- var import_react4 = require("react");
768
- var import_react_native10 = require("react-native");
769
- var import_react_native_paper8 = require("react-native-paper");
770
- var import_jsx_runtime9 = require("react/jsx-runtime");
800
+ var import_core4 = require("@tastic/core");
801
+ var import_react5 = require("react");
802
+ var import_react_native11 = require("react-native");
803
+ var import_react_native_paper9 = require("react-native-paper");
804
+ var import_jsx_runtime10 = require("react/jsx-runtime");
771
805
  function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", titleVariant = "headlineSmall", onBack, insets, onReset, resetLabel = "Reset All Stats", resetConfirmTitle = "Reset Everything?", resetConfirmBody = "This permanently erases all stats and achievements. This cannot be undone.", fg: fgOverride, bg: bgOverride, children }) {
772
806
  const { dark, colors } = (0, import_auto_paper8.useAutoPaperTheme)();
773
- const ambientRotation = (0, import_core3.useRotation)();
807
+ const ambientRotation = (0, import_core4.useRotation)();
774
808
  const rotation = rotationOverride ?? ambientRotation;
775
- const [confirmResetVisible, setConfirmResetVisible] = (0, import_react4.useState)(false);
809
+ const [confirmResetVisible, setConfirmResetVisible] = (0, import_react5.useState)(false);
776
810
  const showReset = !!onReset;
777
811
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
778
812
  const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
779
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.container, { backgroundColor: bg }], children: [
780
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
781
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
782
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: titleVariant, style: [styles8.title, { color: fg }], children: title })
813
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.container, { backgroundColor: bg }], children: [
814
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
815
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
816
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper9.Text, { variant: titleVariant, style: [styles9.title, { color: fg }], children: title })
783
817
  ] }),
784
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { style: styles8.scrollView, contentContainerStyle: [styles8.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
818
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.ScrollView, { style: styles9.scrollView, contentContainerStyle: [styles9.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
785
819
  children,
786
- showReset && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles8.resetButton, children: resetLabel })
820
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles9.resetButton, children: resetLabel })
787
821
  ] }),
788
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
822
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
789
823
  ConfirmDialog,
790
824
  {
791
825
  visible: confirmResetVisible,
@@ -805,7 +839,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
805
839
  )
806
840
  ] });
807
841
  }
808
- var styles8 = import_react_native10.StyleSheet.create({
842
+ var styles9 = import_react_native11.StyleSheet.create({
809
843
  container: {
810
844
  flex: 1
811
845
  },
@@ -836,19 +870,19 @@ var styles8 = import_react_native10.StyleSheet.create({
836
870
  });
837
871
 
838
872
  // src/ContentGutter.tsx
839
- var import_core4 = require("@tastic/core");
840
- var import_react_native11 = require("react-native");
841
- var import_jsx_runtime10 = require("react/jsx-runtime");
873
+ var import_core5 = require("@tastic/core");
874
+ var import_react_native12 = require("react-native");
875
+ var import_jsx_runtime11 = require("react/jsx-runtime");
842
876
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
843
- const { width: windowWidth } = (0, import_core4.useRotatedWindowDimensions)();
844
- const { contentWidth, gutterWidth } = (0, import_core4.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
845
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.row, style], children: [
846
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.gutter, { width: gutterWidth }], children: leftGutter }),
847
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: { width: contentWidth }, children }),
848
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.gutter, { width: gutterWidth }], children: rightGutter })
877
+ const { width: windowWidth } = (0, import_core5.useRotatedWindowDimensions)();
878
+ const { contentWidth, gutterWidth } = (0, import_core5.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
879
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.row, style], children: [
880
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: leftGutter }),
881
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: { width: contentWidth }, children }),
882
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: rightGutter })
849
883
  ] });
850
884
  }
851
- var styles9 = import_react_native11.StyleSheet.create({
885
+ var styles10 = import_react_native12.StyleSheet.create({
852
886
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
853
887
  // column instead of clipping cleanly at its own real width.
854
888
  gutter: {
@@ -860,41 +894,41 @@ var styles9 = import_react_native11.StyleSheet.create({
860
894
  });
861
895
 
862
896
  // src/ControlSchemePicker.tsx
863
- var import_core7 = require("@tastic/core");
864
- var import_react_native16 = require("react-native");
897
+ var import_core8 = require("@tastic/core");
898
+ var import_react_native17 = require("react-native");
865
899
 
866
900
  // src/SectionedDropdown.tsx
867
901
  var import_auto_paper9 = require("@rific/auto-paper");
868
902
  var import_feedback_press4 = require("@rific/feedback-press");
869
- var import_core6 = require("@tastic/core");
870
- var import_react_native15 = require("react-native");
871
- var import_react_native_paper9 = require("react-native-paper");
903
+ var import_core7 = require("@tastic/core");
904
+ var import_react_native16 = require("react-native");
905
+ var import_react_native_paper10 = require("react-native-paper");
872
906
 
873
907
  // src/PopoverBody.tsx
874
- var import_react_native12 = require("react-native");
875
- var import_jsx_runtime11 = require("react/jsx-runtime");
908
+ var import_react_native13 = require("react-native");
909
+ var import_jsx_runtime12 = require("react/jsx-runtime");
876
910
  var CARET_SIZE = 7;
877
911
  var CARET_RING_OFFSET = 2;
878
912
  var CARET_DIP = 1;
879
913
  function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
880
914
  if (!visible) return null;
881
915
  const above = verticalAlign === "above";
882
- const alignStyle = align === "left" ? styles10.contentLeft : align === "right" ? styles10.contentRight : styles10.contentCenter;
883
- const verticalStyle = above ? styles10.contentAbove : styles10.contentBelow;
916
+ const alignStyle = align === "left" ? styles11.contentLeft : align === "right" ? styles11.contentRight : styles11.contentCenter;
917
+ const verticalStyle = above ? styles11.contentAbove : styles11.contentBelow;
884
918
  const ringSize = CARET_SIZE + caretBorderWidth;
885
919
  const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
886
920
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
887
921
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
888
922
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
889
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.content, alignStyle, verticalStyle], children: [
923
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: [styles11.content, alignStyle, verticalStyle], children: [
890
924
  children,
891
- caretColor && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
892
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
893
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
925
+ caretColor && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
926
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
927
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles11.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
894
928
  ] })
895
929
  ] });
896
930
  }
897
- var styles10 = import_react_native12.StyleSheet.create({
931
+ var styles11 = import_react_native13.StyleSheet.create({
898
932
  caret: {
899
933
  borderLeftColor: "transparent",
900
934
  borderRightColor: "transparent",
@@ -937,11 +971,11 @@ var styles10 = import_react_native12.StyleSheet.create({
937
971
  });
938
972
 
939
973
  // src/SkiaGate.tsx
940
- var import_react5 = require("react");
941
- var import_jsx_runtime12 = require("react/jsx-runtime");
974
+ var import_react6 = require("react");
975
+ var import_jsx_runtime13 = require("react/jsx-runtime");
942
976
  function SkiaGate({ getComponent, componentProps, fallback = null }) {
943
- const [Component, setComponent] = (0, import_react5.useState)(null);
944
- (0, import_react5.useEffect)(() => {
977
+ const [Component, setComponent] = (0, import_react6.useState)(null);
978
+ (0, import_react6.useEffect)(() => {
945
979
  let cancelled = false;
946
980
  getComponent().then((mod) => {
947
981
  if (!cancelled) setComponent(() => mod.default);
@@ -951,19 +985,19 @@ function SkiaGate({ getComponent, componentProps, fallback = null }) {
951
985
  };
952
986
  }, [getComponent]);
953
987
  if (!Component) return fallback;
954
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Component, { ...componentProps });
988
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Component, { ...componentProps });
955
989
  }
956
990
 
957
991
  // src/TriggerGaugeHost.tsx
958
- var import_jsx_runtime14 = require("react/jsx-runtime");
992
+ var import_jsx_runtime15 = require("react/jsx-runtime");
959
993
  var getTriggerGauge = () => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((mod) => ({ default: mod.TriggerGauge }));
960
994
  function TriggerGaugeHost(props) {
961
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
995
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
962
996
  }
963
997
 
964
998
  // src/useAutoAlign.ts
965
- var import_react7 = require("react");
966
- var import_react_native14 = require("react-native");
999
+ var import_react8 = require("react");
1000
+ var import_react_native15 = require("react-native");
967
1001
  var EDGE_MARGIN = 12;
968
1002
  function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
969
1003
  if (rotation === 0) return { x, y, width, height };
@@ -975,18 +1009,18 @@ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
975
1009
  return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
976
1010
  }
977
1011
  function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
978
- const triggerRef = (0, import_react7.useRef)(null);
979
- const { width: windowWidth, height: windowHeight } = (0, import_react_native14.useWindowDimensions)();
980
- const [align, setAlign] = (0, import_react7.useState)("center");
981
- const [verticalAlign, setVerticalAlign] = (0, import_react7.useState)("below");
982
- const [maxHeight, setMaxHeight] = (0, import_react7.useState)(contentHeight);
983
- const [measured, setMeasured] = (0, import_react7.useState)(false);
984
- const [prevOpen, setPrevOpen] = (0, import_react7.useState)(open);
1012
+ const triggerRef = (0, import_react8.useRef)(null);
1013
+ const { width: windowWidth, height: windowHeight } = (0, import_react_native15.useWindowDimensions)();
1014
+ const [align, setAlign] = (0, import_react8.useState)("center");
1015
+ const [verticalAlign, setVerticalAlign] = (0, import_react8.useState)("below");
1016
+ const [maxHeight, setMaxHeight] = (0, import_react8.useState)(contentHeight);
1017
+ const [measured, setMeasured] = (0, import_react8.useState)(false);
1018
+ const [prevOpen, setPrevOpen] = (0, import_react8.useState)(open);
985
1019
  if (open !== prevOpen) {
986
1020
  setPrevOpen(open);
987
1021
  if (open) setMeasured(false);
988
1022
  }
989
- const measure = (0, import_react7.useCallback)(() => {
1023
+ const measure = (0, import_react8.useCallback)(() => {
990
1024
  triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
991
1025
  const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
992
1026
  const centerX = x + triggerWidth / 2;
@@ -1003,14 +1037,14 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
1003
1037
  setMeasured(true);
1004
1038
  });
1005
1039
  }, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
1006
- (0, import_react7.useEffect)(() => {
1040
+ (0, import_react8.useEffect)(() => {
1007
1041
  if (open) measure();
1008
1042
  }, [open, measure]);
1009
1043
  return { align, maxHeight, measured, triggerRef, verticalAlign };
1010
1044
  }
1011
1045
 
1012
1046
  // src/SectionedDropdown.tsx
1013
- var import_jsx_runtime15 = require("react/jsx-runtime");
1047
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1014
1048
  var MENU_BORDER_WIDTH = 1;
1015
1049
  var TRIGGER_SIZE = 44;
1016
1050
  var MENU_MIN_WIDTH = 200;
@@ -1022,7 +1056,7 @@ var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
1022
1056
  var MENU_DIVIDER_HEIGHT = 9;
1023
1057
  var MENU_VERTICAL_PADDING = 12;
1024
1058
  function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
1025
- const ambientRotation = (0, import_core6.useRotation)();
1059
+ const ambientRotation = (0, import_core7.useRotation)();
1026
1060
  const rotation = rotationOverride ?? ambientRotation;
1027
1061
  const menuBg = dark ? "#000000" : "#FFFFFF";
1028
1062
  const menuBorderColor = (0, import_auto_paper9.getBlendedColor)(mutedColor, menuBg, 0.5);
@@ -1060,17 +1094,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1060
1094
  }
1061
1095
  gaugeOffset += section.options.length;
1062
1096
  }
1063
- const anchorStyle = [styles12.anchor, open && styles12.anchorOpen];
1097
+ const anchorStyle = [styles13.anchor, open && styles13.anchorOpen];
1064
1098
  const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
1065
1099
  const dividerStyle = { backgroundColor: menuBorderColor };
1066
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: anchorStyle, children: [
1067
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { ref: triggerRef, collapsable: false, style: styles12.triggerBox, children: [
1068
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1069
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1100
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: anchorStyle, children: [
1101
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { ref: triggerRef, collapsable: false, style: styles13.triggerBox, children: [
1102
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1103
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1070
1104
  ] }),
1071
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.ScrollView, { style: [styles12.menu, menuStyle], contentContainerStyle: styles12.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { children: [
1072
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.View, { style: [styles12.divider, dividerStyle] }),
1073
- section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1105
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native16.ScrollView, { style: [styles13.menu, menuStyle], contentContainerStyle: styles13.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { children: [
1106
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native16.View, { style: [styles13.divider, dividerStyle] }),
1107
+ section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1074
1108
  SingleSection,
1075
1109
  {
1076
1110
  section,
@@ -1083,7 +1117,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1083
1117
  if (autoDismiss) host.close();
1084
1118
  }
1085
1119
  }
1086
- ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1120
+ ) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1087
1121
  ] }, section.id)) }) })
1088
1122
  ] });
1089
1123
  }
@@ -1095,18 +1129,18 @@ function SingleSection({
1095
1129
  labelFontFamily,
1096
1130
  onSelect
1097
1131
  }) {
1098
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: section.options.map((option) => {
1132
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children: section.options.map((option) => {
1099
1133
  const selected = option.value === section.value;
1100
1134
  const taken = !selected && option.value === section.takenValue;
1101
1135
  const rowColor = selected ? onAccentColor : mutedColor;
1102
- const itemStyle = [styles12.item, selected && { backgroundColor: accentColor }, taken && styles12.itemTaken];
1136
+ const itemStyle = [styles13.item, selected && { backgroundColor: accentColor }, taken && styles13.itemTaken];
1103
1137
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1104
1138
  const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
1105
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: styles12.itemRow, children: [
1106
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1107
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: styles12.itemLabelColumn, children: [
1108
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1109
- option.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1139
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: styles13.itemRow, children: [
1140
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1141
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: styles13.itemLabelColumn, children: [
1142
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1143
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1110
1144
  ] })
1111
1145
  ] }) }, option.value);
1112
1146
  }) });
@@ -1120,23 +1154,23 @@ function MultiSection({
1120
1154
  allClearLabels
1121
1155
  }) {
1122
1156
  const allSelected = section.value.length === section.options.length;
1123
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1157
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1124
1158
  section.options.map((option, i) => {
1125
1159
  const selected = section.value.includes(option.value);
1126
1160
  const rowColor = selected ? onAccentColor : mutedColor;
1127
1161
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
1128
1162
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
1129
- const itemStyle = [styles12.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1163
+ const itemStyle = [styles13.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1130
1164
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1131
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: styles12.itemRow, children: [
1132
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1133
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: [styles12.itemLabelFlex, labelStyle], children: option.label })
1165
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native16.View, { style: styles13.itemRow, children: [
1166
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1167
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: [styles13.itemLabelFlex, labelStyle], children: option.label })
1134
1168
  ] }) }, option.value);
1135
1169
  }),
1136
- section.allClear && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles12.item, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: [styles12.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1170
+ section.allClear && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles13.item, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper10.Text, { variant: "labelLarge", style: [styles13.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1137
1171
  ] });
1138
1172
  }
1139
- var styles12 = import_react_native15.StyleSheet.create({
1173
+ var styles13 = import_react_native16.StyleSheet.create({
1140
1174
  allClearLabel: {
1141
1175
  fontWeight: "bold",
1142
1176
  textAlign: "center"
@@ -1153,7 +1187,7 @@ var styles12 = import_react_native15.StyleSheet.create({
1153
1187
  zIndex: 100
1154
1188
  },
1155
1189
  divider: {
1156
- height: import_react_native15.StyleSheet.hairlineWidth,
1190
+ height: import_react_native16.StyleSheet.hairlineWidth,
1157
1191
  marginVertical: 4
1158
1192
  },
1159
1193
  item: {
@@ -1206,24 +1240,24 @@ var styles12 = import_react_native15.StyleSheet.create({
1206
1240
  });
1207
1241
 
1208
1242
  // src/ControlSchemePicker.tsx
1209
- var import_jsx_runtime16 = require("react/jsx-runtime");
1243
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1210
1244
  function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily }) {
1211
- const isTouchPrimary = (0, import_core7.useIsTouchPrimaryDevice)();
1212
- if (import_react_native16.Platform.OS !== "web" || isTouchPrimary) return null;
1213
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
1245
+ const isTouchPrimary = (0, import_core8.useIsTouchPrimaryDevice)();
1246
+ if (import_react_native17.Platform.OS !== "web" || isTouchPrimary) return null;
1247
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
1214
1248
  }
1215
1249
 
1216
1250
  // src/CornerActionButtons.tsx
1217
1251
  var import_feedback_press5 = require("@rific/feedback-press");
1218
- var import_react_native17 = require("react-native");
1219
- var import_jsx_runtime17 = require("react/jsx-runtime");
1252
+ var import_react_native18 = require("react-native");
1253
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1220
1254
  function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
1221
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1222
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles13.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
1223
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles13.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
1255
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1256
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles14.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles14.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
1224
1258
  ] });
1225
1259
  }
1226
- var styles13 = import_react_native17.StyleSheet.create({
1260
+ var styles14 = import_react_native18.StyleSheet.create({
1227
1261
  back: {
1228
1262
  position: "absolute"
1229
1263
  },
@@ -1233,22 +1267,22 @@ var styles13 = import_react_native17.StyleSheet.create({
1233
1267
  });
1234
1268
 
1235
1269
  // src/CornerStatusBadges.tsx
1236
- var import_react_native18 = require("react-native");
1237
- var import_react_native_paper10 = require("react-native-paper");
1238
- var import_jsx_runtime18 = require("react/jsx-runtime");
1270
+ var import_react_native19 = require("react-native");
1271
+ var import_react_native_paper11 = require("react-native-paper");
1272
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1239
1273
  var BADGE_SIZE = 30;
1240
1274
  function StatusBadge({ icon }) {
1241
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { style: styles14.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { style: styles15.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1242
1276
  }
1243
1277
  function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
1244
1278
  const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
1245
1279
  const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
1246
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1247
- p1 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { pointerEvents: "none", style: p1OnRightSide ? styles14.bottomRight : styles14.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusBadge, { icon: p1.icon }) }),
1248
- p2 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { pointerEvents: "none", style: p2OnLeftSide ? styles14.topLeft : styles14.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusBadge, { icon: p2.icon }) })
1280
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
1281
+ p1 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { pointerEvents: "none", style: p1OnRightSide ? styles15.bottomRight : styles15.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusBadge, { icon: p1.icon }) }),
1282
+ p2 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { pointerEvents: "none", style: p2OnLeftSide ? styles15.topLeft : styles15.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StatusBadge, { icon: p2.icon }) })
1249
1283
  ] });
1250
1284
  }
1251
- var styles14 = import_react_native18.StyleSheet.create({
1285
+ var styles15 = import_react_native19.StyleSheet.create({
1252
1286
  badge: {
1253
1287
  alignItems: "center",
1254
1288
  backgroundColor: "rgba(0,0,0,0.28)",
@@ -1269,10 +1303,10 @@ var styles14 = import_react_native18.StyleSheet.create({
1269
1303
  // src/InlineColorPicker.tsx
1270
1304
  var import_auto_paper10 = require("@rific/auto-paper");
1271
1305
  var import_feedback_press6 = require("@rific/feedback-press");
1272
- var import_core8 = require("@tastic/core");
1273
- var import_react_native19 = require("react-native");
1274
- var import_react_native_paper11 = require("react-native-paper");
1275
- var import_jsx_runtime19 = require("react/jsx-runtime");
1306
+ var import_core9 = require("@tastic/core");
1307
+ var import_react_native20 = require("react-native");
1308
+ var import_react_native_paper12 = require("react-native-paper");
1309
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1276
1310
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
1277
1311
  var DEFAULT_SIZE = 48;
1278
1312
  var SWATCH_SIZE = 28;
@@ -1286,7 +1320,7 @@ function widthForColumns(columns) {
1286
1320
  return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
1287
1321
  }
1288
1322
  function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
1289
- const autoColumns = (0, import_core8.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
1323
+ const autoColumns = (0, import_core9.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
1290
1324
  const resolvedColumns = columns ?? autoColumns;
1291
1325
  const width = widthForColumns(resolvedColumns);
1292
1326
  const rows = Math.ceil(swatchCount / resolvedColumns);
@@ -1294,10 +1328,10 @@ function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
1294
1328
  return { width, height };
1295
1329
  }
1296
1330
  function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper10.defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1297
- const ambientRotation = (0, import_core8.useRotation)();
1331
+ const ambientRotation = (0, import_core9.useRotation)();
1298
1332
  const rotation = rotationOverride ?? ambientRotation;
1299
1333
  const menuBg = dark ? "#000000" : "#FFFFFF";
1300
- const { width: windowWidth } = (0, import_react_native19.useWindowDimensions)();
1334
+ const { width: windowWidth } = (0, import_react_native20.useWindowDimensions)();
1301
1335
  const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
1302
1336
  const open = host.openId === id;
1303
1337
  const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
@@ -1308,14 +1342,14 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1308
1342
  const displayValue = displayFor(value);
1309
1343
  const contrastColor = (0, import_auto_paper10.getContrastColor)(displayValue);
1310
1344
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
1311
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native19.View, { style: [styles15.anchor, open && styles15.anchorOpen], children: [
1312
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles15.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { ref: triggerRef, collapsable: false, style: styles15.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Text, { style: [styles15.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1313
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.ScrollView, { style: [styles15.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles15.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1345
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { style: [styles16.anchor, open && styles16.anchorOpen], children: [
1346
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles16.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, { ref: triggerRef, collapsable: false, style: styles16.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { style: [styles16.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1347
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.ScrollView, { style: [styles16.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles16.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1314
1348
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
1315
1349
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
1316
1350
  const swappable = taken && allowSwapTaken;
1317
1351
  const swatchDisplay = displayFor(swatch.value);
1318
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1352
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
1319
1353
  import_feedback_press6.TouchableRipple,
1320
1354
  {
1321
1355
  disabled: taken && !swappable,
@@ -1324,15 +1358,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1324
1358
  if (autoDismiss) host.close();
1325
1359
  },
1326
1360
  borderless: true,
1327
- style: [styles15.swatch, { backgroundColor: swatchDisplay }, selected && styles15.swatchSelected, taken && !swappable && styles15.swatchTaken],
1328
- children: selected ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "check", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "close", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, {})
1361
+ style: [styles16.swatch, { backgroundColor: swatchDisplay }, selected && styles16.swatchSelected, taken && !swappable && styles16.swatchTaken],
1362
+ children: selected ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "check", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "close", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.View, {})
1329
1363
  },
1330
1364
  swatch.value
1331
1365
  );
1332
1366
  }) }) })
1333
1367
  ] });
1334
1368
  }
1335
- var styles15 = import_react_native19.StyleSheet.create({
1369
+ var styles16 = import_react_native20.StyleSheet.create({
1336
1370
  anchor: {
1337
1371
  position: "relative"
1338
1372
  },
@@ -1406,9 +1440,9 @@ var styles15 = import_react_native19.StyleSheet.create({
1406
1440
  // src/LabeledDropdown.tsx
1407
1441
  var import_auto_paper11 = require("@rific/auto-paper");
1408
1442
  var import_feedback_press7 = require("@rific/feedback-press");
1409
- var import_react_native20 = require("react-native");
1410
- var import_react_native_paper12 = require("react-native-paper");
1411
- var import_jsx_runtime20 = require("react/jsx-runtime");
1443
+ var import_react_native21 = require("react-native");
1444
+ var import_react_native_paper13 = require("react-native-paper");
1445
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1412
1446
  var TRIGGER_HEIGHT = 28;
1413
1447
  var POPOVER_WIDTH = 180;
1414
1448
  var ROW_HEIGHT = 36;
@@ -1431,22 +1465,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
1431
1465
  onChange(option.value);
1432
1466
  host.close();
1433
1467
  };
1434
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { style: [styles16.anchor, open && styles16.anchorOpen], children: [
1435
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles16.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { ref: triggerRef, collapsable: false, style: styles16.triggerInner, children: [
1436
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { style: [styles16.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1437
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "menu-down", size: 16, color })
1468
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: [styles17.anchor, open && styles17.anchorOpen], children: [
1469
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles17.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { ref: triggerRef, collapsable: false, style: styles17.triggerInner, children: [
1470
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { style: [styles17.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1471
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Icon, { source: "menu-down", size: 16, color })
1438
1472
  ] }) }),
1439
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.ScrollView, { style: [styles16.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles16.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1473
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native21.ScrollView, { style: [styles17.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles17.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1440
1474
  const isSelected = option.value === value;
1441
1475
  const onColor = (0, import_auto_paper11.getContrastColor)(color);
1442
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles16.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { style: styles16.rowInner, children: [
1443
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1444
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { style: [styles16.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1476
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles17.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: styles17.rowInner, children: [
1477
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1478
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { style: [styles17.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1445
1479
  ] }) }, option.value);
1446
1480
  }) }) })
1447
1481
  ] });
1448
1482
  }
1449
- var styles16 = import_react_native20.StyleSheet.create({
1483
+ var styles17 = import_react_native21.StyleSheet.create({
1450
1484
  anchor: {
1451
1485
  position: "relative"
1452
1486
  },
@@ -1505,21 +1539,21 @@ function loadSkiaWeb() {
1505
1539
 
1506
1540
  // src/PlayerSetupPanel.tsx
1507
1541
  var import_profile2 = require("@tastic/profile");
1508
- var import_react_native22 = require("react-native");
1509
- var import_react_native_paper14 = require("react-native-paper");
1542
+ var import_react_native23 = require("react-native");
1543
+ var import_react_native_paper15 = require("react-native-paper");
1510
1544
 
1511
1545
  // src/ReadyButton.tsx
1512
1546
  var import_feedback_press8 = require("@rific/feedback-press");
1513
- var import_react_native21 = require("react-native");
1514
- var import_react_native_paper13 = require("react-native-paper");
1515
- var import_jsx_runtime21 = require("react/jsx-runtime");
1547
+ var import_react_native22 = require("react-native");
1548
+ var import_react_native_paper14 = require("react-native-paper");
1549
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1516
1550
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
1517
- const readyButtonStyle = [styles17.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1551
+ const readyButtonStyle = [styles18.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1518
1552
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
1519
1553
  const labelColorStyle = { color: ready ? "#000000" : color };
1520
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1554
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper14.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1521
1555
  }
1522
- var styles17 = import_react_native21.StyleSheet.create({
1556
+ var styles18 = import_react_native22.StyleSheet.create({
1523
1557
  readyButton: {
1524
1558
  alignItems: "center",
1525
1559
  borderRadius: 12,
@@ -1532,18 +1566,18 @@ var styles17 = import_react_native21.StyleSheet.create({
1532
1566
  });
1533
1567
 
1534
1568
  // src/usePopoverHost.ts
1535
- var import_react8 = require("react");
1569
+ var import_react9 = require("react");
1536
1570
  function usePopoverHost() {
1537
- const [openId, setOpenId] = (0, import_react8.useState)(null);
1538
- const toggle = (0, import_react8.useCallback)((id) => {
1571
+ const [openId, setOpenId] = (0, import_react9.useState)(null);
1572
+ const toggle = (0, import_react9.useCallback)((id) => {
1539
1573
  setOpenId((prev) => prev === id ? null : id);
1540
1574
  }, []);
1541
- const close = (0, import_react8.useCallback)(() => setOpenId(null), []);
1575
+ const close = (0, import_react9.useCallback)(() => setOpenId(null), []);
1542
1576
  return { openId, toggle, close };
1543
1577
  }
1544
1578
 
1545
1579
  // src/PlayerSetupPanel.tsx
1546
- var import_jsx_runtime22 = require("react/jsx-runtime");
1580
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1547
1581
  function getColorPopoverId(idPrefix) {
1548
1582
  return `${idPrefix}-color`;
1549
1583
  }
@@ -1558,16 +1592,16 @@ function PlayerSetupPanel({ idPrefix, host, label, labelFontFamily, color, onCol
1558
1592
  const showProfilePicker = isHuman && profiles !== void 0 && !!onProfileSelect;
1559
1593
  const showCpuDifficulty = !isHuman && cpuDifficulty !== void 0 && cpuDifficultyOptions !== void 0 && !!onCpuDifficultyChange;
1560
1594
  const selectedProfile = profiles?.find((p) => p.id === selectedProfileId) ?? null;
1561
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { style: [styles18.panel, ownPopoverOpen && styles18.panelOpen], children: [
1562
- showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_profile2.ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper14.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1563
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { style: [styles18.pickerRow, pickerRowPopoverOpen && styles18.pickerRowOpen], children: [
1564
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
1595
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native23.View, { style: [styles19.panel, ownPopoverOpen && styles19.panelOpen], children: [
1596
+ showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_profile2.ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native_paper15.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1597
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native23.View, { style: [styles19.pickerRow, pickerRowPopoverOpen && styles19.pickerRowOpen], children: [
1598
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
1565
1599
  secondPicker
1566
1600
  ] }),
1567
- isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1601
+ isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1568
1602
  ] });
1569
1603
  }
1570
- var styles18 = import_react_native22.StyleSheet.create({
1604
+ var styles19 = import_react_native23.StyleSheet.create({
1571
1605
  panel: {
1572
1606
  alignItems: "center",
1573
1607
  gap: 12
@@ -1599,29 +1633,29 @@ var styles18 = import_react_native22.StyleSheet.create({
1599
1633
  });
1600
1634
 
1601
1635
  // src/PressAwayOverlay.tsx
1602
- var import_react_native23 = require("react-native");
1603
- var import_jsx_runtime23 = require("react/jsx-runtime");
1636
+ var import_react_native24 = require("react-native");
1637
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1604
1638
  function PressAwayOverlay({ active, onPress, style }) {
1605
1639
  if (!active) return null;
1606
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native23.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native23.StyleSheet.absoluteFill, style] });
1640
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native24.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native24.StyleSheet.absoluteFill, style] });
1607
1641
  }
1608
1642
 
1609
1643
  // src/SharedActionBand.tsx
1610
1644
  var import_feedback_press9 = require("@rific/feedback-press");
1611
- var import_react_native24 = require("react-native");
1612
- var import_jsx_runtime24 = require("react/jsx-runtime");
1645
+ var import_react_native25 = require("react-native");
1646
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1613
1647
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
1614
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native24.View, { style: [styles19.column, popoverOpen && styles19.columnOpen], children: [
1615
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native24.View, { style: styles19.actionsRow, children: [
1616
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1617
- onRandomize && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1618
- onReset && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1619
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1648
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native25.View, { style: [styles20.column, popoverOpen && styles20.columnOpen], children: [
1649
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_react_native25.View, { style: styles20.actionsRow, children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1651
+ onRandomize && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1652
+ onReset && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1653
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1620
1654
  ] }),
1621
1655
  children
1622
1656
  ] });
1623
1657
  }
1624
- var styles19 = import_react_native24.StyleSheet.create({
1658
+ var styles20 = import_react_native25.StyleSheet.create({
1625
1659
  actionsRow: {
1626
1660
  alignItems: "center",
1627
1661
  flexDirection: "row",
@@ -1637,10 +1671,10 @@ var styles19 = import_react_native24.StyleSheet.create({
1637
1671
  });
1638
1672
 
1639
1673
  // src/StaggeredWord.tsx
1640
- var import_react9 = require("react");
1641
- var import_react_native25 = require("react-native");
1674
+ var import_react10 = require("react");
1675
+ var import_react_native26 = require("react-native");
1642
1676
  var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
1643
- var import_jsx_runtime25 = require("react/jsx-runtime");
1677
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1644
1678
  var STAGGER_MS = 45;
1645
1679
  var LETTER_DURATION_MS = 320;
1646
1680
  function getStaggeredWordDuration(letterCount) {
@@ -1648,7 +1682,7 @@ function getStaggeredWordDuration(letterCount) {
1648
1682
  }
1649
1683
  function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }) {
1650
1684
  const progress = (0, import_react_native_reanimated2.useSharedValue)(reducedMotion ? 1 : 0);
1651
- (0, import_react9.useEffect)(() => {
1685
+ (0, import_react10.useEffect)(() => {
1652
1686
  if (reducedMotion) return;
1653
1687
  progress.value = (0, import_react_native_reanimated2.withDelay)(index * STAGGER_MS, (0, import_react_native_reanimated2.withTiming)(1, { duration: LETTER_DURATION_MS, easing: import_react_native_reanimated2.Easing.out(import_react_native_reanimated2.Easing.back(1.5)) }));
1654
1688
  }, [reducedMotion]);
@@ -1656,12 +1690,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
1656
1690
  opacity: progress.value,
1657
1691
  transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
1658
1692
  }));
1659
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native_reanimated2.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
1693
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native_reanimated2.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
1660
1694
  }
1661
1695
  function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
1662
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.View, { style: [styles20.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
1696
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_native26.View, { style: [styles21.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
1663
1697
  }
1664
- var styles20 = import_react_native25.StyleSheet.create({
1698
+ var styles21 = import_react_native26.StyleSheet.create({
1665
1699
  row: {
1666
1700
  flexDirection: "row"
1667
1701
  }
@@ -1669,53 +1703,53 @@ var styles20 = import_react_native25.StyleSheet.create({
1669
1703
 
1670
1704
  // src/UpdateDialog.tsx
1671
1705
  var import_updater2 = require("@rific/updater");
1672
- var import_jsx_runtime26 = require("react/jsx-runtime");
1706
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1673
1707
  function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
1674
1708
  const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
1675
1709
  (0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
1676
1710
  const date = manifest ? new Date(manifest.createdAt) : null;
1677
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
1711
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
1678
1712
  }
1679
1713
 
1680
1714
  // src/useQuitConfirmation.ts
1681
- var import_react10 = require("react");
1715
+ var import_react11 = require("react");
1682
1716
  function useQuitConfirmation(hasProgress, onConfirmedBack) {
1683
- const [confirmVisible, setConfirmVisible] = (0, import_react10.useState)(false);
1684
- const hasProgressRef = (0, import_react10.useRef)(hasProgress);
1685
- (0, import_react10.useEffect)(() => {
1717
+ const [confirmVisible, setConfirmVisible] = (0, import_react11.useState)(false);
1718
+ const hasProgressRef = (0, import_react11.useRef)(hasProgress);
1719
+ (0, import_react11.useEffect)(() => {
1686
1720
  hasProgressRef.current = hasProgress;
1687
1721
  });
1688
- const onConfirmedBackRef = (0, import_react10.useRef)(onConfirmedBack);
1689
- (0, import_react10.useEffect)(() => {
1722
+ const onConfirmedBackRef = (0, import_react11.useRef)(onConfirmedBack);
1723
+ (0, import_react11.useEffect)(() => {
1690
1724
  onConfirmedBackRef.current = onConfirmedBack;
1691
1725
  });
1692
- const requestBack = (0, import_react10.useCallback)(() => {
1726
+ const requestBack = (0, import_react11.useCallback)(() => {
1693
1727
  if (hasProgressRef.current()) setConfirmVisible(true);
1694
1728
  else onConfirmedBackRef.current();
1695
1729
  }, []);
1696
- const cancelBack = (0, import_react10.useCallback)(() => setConfirmVisible(false), []);
1730
+ const cancelBack = (0, import_react11.useCallback)(() => setConfirmVisible(false), []);
1697
1731
  return { confirmVisible, requestBack, cancelBack };
1698
1732
  }
1699
1733
 
1700
1734
  // src/useZoneClampedAlign.ts
1701
1735
  var import_split_screen = require("@tastic/split-screen");
1702
- var import_react11 = require("react");
1703
- var import_react_native26 = require("react-native");
1704
- var import_react_native_safe_area_context = require("react-native-safe-area-context");
1736
+ var import_react12 = require("react");
1737
+ var import_react_native27 = require("react-native");
1738
+ var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
1705
1739
  var EDGE_MARGIN2 = 12;
1706
1740
  function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1707
1741
  const auto = useAutoAlign(open, contentWidth, contentHeight, rotation);
1708
1742
  const zone = (0, import_split_screen.useZoneBounds)();
1709
- const { height: windowHeight } = (0, import_react_native26.useWindowDimensions)();
1710
- const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
1743
+ const { height: windowHeight } = (0, import_react_native27.useWindowDimensions)();
1744
+ const insets = (0, import_react_native_safe_area_context2.useSafeAreaInsets)();
1711
1745
  const shouldMeasure = open && auto.measured && zone !== null;
1712
- const [ownBounds, setOwnBounds] = (0, import_react11.useState)(null);
1713
- const [prevShouldMeasure, setPrevShouldMeasure] = (0, import_react11.useState)(shouldMeasure);
1746
+ const [ownBounds, setOwnBounds] = (0, import_react12.useState)(null);
1747
+ const [prevShouldMeasure, setPrevShouldMeasure] = (0, import_react12.useState)(shouldMeasure);
1714
1748
  if (shouldMeasure !== prevShouldMeasure) {
1715
1749
  setPrevShouldMeasure(shouldMeasure);
1716
1750
  setOwnBounds(null);
1717
1751
  }
1718
- (0, import_react11.useEffect)(() => {
1752
+ (0, import_react12.useEffect)(() => {
1719
1753
  if (!shouldMeasure) return;
1720
1754
  auto.triggerRef.current?.measureInWindow((_x, y, _width, height) => {
1721
1755
  const belowShared = zone.zoneSide === "belowShared";
@@ -1757,6 +1791,7 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1757
1791
  PopoverBody,
1758
1792
  PressAwayOverlay,
1759
1793
  ReadyButton,
1794
+ RotatedFrame,
1760
1795
  SectionedDropdown,
1761
1796
  SharedActionBand,
1762
1797
  SkiaGate,