@tastic/hud 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,17 +1,85 @@
1
+ // src/AchievementRow.tsx
2
+ import { useAutoPaperTheme } from "@rific/auto-paper";
3
+ import { StyleSheet, View } from "react-native";
4
+ import { Icon, ProgressBar, Text } from "react-native-paper";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ var LOCKED_BADGE_COLOR = "rgba(128,128,128,0.3)";
7
+ function AchievementRow({ icon, title, description, badgeColor, unlockedLabel, checkColor, progress, deviceMarker }) {
8
+ const { dark } = useAutoPaperTheme();
9
+ const fg = dark ? "#FFFFFF" : "#000000";
10
+ const fgMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)";
11
+ const sectionBg = dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)";
12
+ const unlocked = unlockedLabel !== void 0;
13
+ return /* @__PURE__ */ jsxs(View, { style: [styles.row, { backgroundColor: sectionBg }], children: [
14
+ /* @__PURE__ */ jsx(View, { style: [styles.badge, { backgroundColor: badgeColor }], children: /* @__PURE__ */ jsx(Icon, { source: icon, size: 20, color: unlocked ? "#000000" : fgMuted }) }),
15
+ /* @__PURE__ */ jsxs(View, { style: styles.text, children: [
16
+ /* @__PURE__ */ jsx(Text, { variant: "bodyLarge", style: [styles.boldText, { color: fg }], children: title }),
17
+ /* @__PURE__ */ jsx(Text, { variant: "bodySmall", style: { color: fgMuted }, children: description }),
18
+ deviceMarker && /* @__PURE__ */ jsxs(View, { style: styles.deviceMarker, children: [
19
+ /* @__PURE__ */ jsx(Icon, { source: "earth", size: 11, color: fgMuted }),
20
+ /* @__PURE__ */ jsx(Text, { variant: "labelSmall", style: { color: fgMuted }, children: "Same for every profile" })
21
+ ] }),
22
+ !unlocked && progress !== void 0 && /* @__PURE__ */ jsx(ProgressBar, { progress, color: checkColor ?? badgeColor, style: styles.progressBar })
23
+ ] }),
24
+ unlocked ? /* @__PURE__ */ jsxs(View, { style: styles.status, children: [
25
+ /* @__PURE__ */ jsx(Icon, { source: "check-circle", size: 20, color: checkColor ?? badgeColor }),
26
+ /* @__PURE__ */ jsx(Text, { variant: "labelSmall", style: { color: fgMuted }, children: unlockedLabel })
27
+ ] }) : /* @__PURE__ */ jsx(Icon, { source: "lock-outline", size: 20, color: fgMuted })
28
+ ] });
29
+ }
30
+ var styles = StyleSheet.create({
31
+ badge: {
32
+ alignItems: "center",
33
+ borderRadius: 10,
34
+ height: 36,
35
+ justifyContent: "center",
36
+ width: 36
37
+ },
38
+ boldText: {
39
+ fontWeight: "bold"
40
+ },
41
+ deviceMarker: {
42
+ alignItems: "center",
43
+ flexDirection: "row",
44
+ gap: 4
45
+ },
46
+ progressBar: {
47
+ borderRadius: 4,
48
+ height: 6,
49
+ marginTop: 6
50
+ },
51
+ row: {
52
+ alignItems: "center",
53
+ borderRadius: 12,
54
+ flexDirection: "row",
55
+ gap: 12,
56
+ padding: 12
57
+ },
58
+ status: {
59
+ alignItems: "center",
60
+ gap: 2,
61
+ width: 64
62
+ },
63
+ text: {
64
+ flex: 1,
65
+ gap: 2
66
+ }
67
+ });
68
+
1
69
  // src/BaseSettingsDialog.tsx
2
- import { AutoAppearancePicker, Dialog, useAutoPaperTheme } from "@rific/auto-paper";
70
+ import { AutoAppearancePicker, Dialog, useAutoPaperTheme as useAutoPaperTheme2 } from "@rific/auto-paper";
3
71
  import { Button, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from "@rific/feedback-press";
4
72
  import { useUpdater } from "@rific/updater";
5
73
  import { useIsTouchPrimaryDevice } from "@tastic/core";
6
74
  import { useContext, useState } from "react";
7
- import { Platform, ScrollView, StyleSheet, View } from "react-native";
8
- import { Icon, Portal, Text } from "react-native-paper";
9
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
75
+ import { Platform, ScrollView, StyleSheet as StyleSheet2, View as View2 } from "react-native";
76
+ import { Icon as Icon2, Portal, Text as Text2 } from "react-native-paper";
77
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
10
78
  function SettingIcon({ source, color, containerColor }) {
11
- return /* @__PURE__ */ jsx(View, { style: [styles.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx(Icon, { source, size: 18, color }) });
79
+ return /* @__PURE__ */ jsx2(View2, { style: [styles2.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx2(Icon2, { source, size: 18, color }) });
12
80
  }
13
81
  function BaseSettingsDialog({ visible, onDismiss, rotation = 0, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
14
- const { dark, colors } = useAutoPaperTheme();
82
+ const { dark, colors } = useAutoPaperTheme2();
15
83
  const isTouchPrimary = useIsTouchPrimaryDevice();
16
84
  const { settings: hapticSettings, set: setHapticSettings } = useHapticSettings();
17
85
  const { settings: soundSettings, set: setSoundSettings } = useSoundSettings();
@@ -33,27 +101,27 @@ function BaseSettingsDialog({ visible, onDismiss, rotation = 0, version, lockOri
33
101
  const fg = dark ? "#FFFFFF" : "#000000";
34
102
  const cardBg = dark ? "#111111" : "#F2F2F2";
35
103
  const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
36
- return /* @__PURE__ */ jsxs(Fragment, { children: [
37
- /* @__PURE__ */ jsxs(Dialog, { visible, onDismiss, style: [styles.dialog, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
38
- /* @__PURE__ */ jsx(Dialog.Title, { children: "Settings" }),
39
- /* @__PURE__ */ jsx(Dialog.ScrollArea, { style: styles.scrollArea, children: /* @__PURE__ */ jsxs(ScrollView, { contentContainerStyle: styles.content, showsVerticalScrollIndicator: false, children: [
40
- /* @__PURE__ */ jsxs(View, { style: styles.toggleGroup, children: [
41
- showLockOrientation && /* @__PURE__ */ jsx(TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ jsxs(View, { style: styles.toggleContent, children: [
42
- /* @__PURE__ */ jsx(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
43
- /* @__PURE__ */ jsxs(View, { style: styles.flexShrink, children: [
44
- /* @__PURE__ */ jsx(Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
45
- /* @__PURE__ */ jsx(Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
104
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
105
+ /* @__PURE__ */ jsxs2(Dialog, { visible, onDismiss, style: [styles2.dialog, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
106
+ /* @__PURE__ */ jsx2(Dialog.Title, { children: "Settings" }),
107
+ /* @__PURE__ */ jsx2(Dialog.ScrollArea, { style: styles2.scrollArea, children: /* @__PURE__ */ jsxs2(ScrollView, { contentContainerStyle: styles2.content, showsVerticalScrollIndicator: false, children: [
108
+ /* @__PURE__ */ jsxs2(View2, { style: styles2.toggleGroup, children: [
109
+ showLockOrientation && /* @__PURE__ */ jsx2(TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles2.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ jsxs2(View2, { style: styles2.toggleContent, children: [
110
+ /* @__PURE__ */ jsx2(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
111
+ /* @__PURE__ */ jsxs2(View2, { style: styles2.flexShrink, children: [
112
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
113
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
46
114
  ] })
47
115
  ] }) }),
48
- showEdgeGuard && /* @__PURE__ */ jsx(TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ jsxs(View, { style: styles.toggleContent, children: [
49
- /* @__PURE__ */ jsx(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
50
- /* @__PURE__ */ jsxs(View, { style: styles.flexShrink, children: [
51
- /* @__PURE__ */ jsx(Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
52
- /* @__PURE__ */ jsx(Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
116
+ showEdgeGuard && /* @__PURE__ */ jsx2(TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles2.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ jsxs2(View2, { style: styles2.toggleContent, children: [
117
+ /* @__PURE__ */ jsx2(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
118
+ /* @__PURE__ */ jsxs2(View2, { style: styles2.flexShrink, children: [
119
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
120
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
53
121
  ] })
54
122
  ] }) }),
55
- (showSound || showHaptics) && /* @__PURE__ */ jsxs(View, { style: styles.toggleRow, children: [
56
- showSound && /* @__PURE__ */ jsx(
123
+ (showSound || showHaptics) && /* @__PURE__ */ jsxs2(View2, { style: styles2.toggleRow, children: [
124
+ showSound && /* @__PURE__ */ jsx2(
57
125
  TouchableRipple,
58
126
  {
59
127
  soundDisabled: true,
@@ -62,15 +130,15 @@ function BaseSettingsDialog({ visible, onDismiss, rotation = 0, version, lockOri
62
130
  setSoundSettings({ enabled });
63
131
  if (enabled) sound.selection?.();
64
132
  },
65
- style: styles.toggleButtonInRow,
133
+ style: styles2.toggleButtonInRow,
66
134
  accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
67
- children: /* @__PURE__ */ jsxs(View, { style: styles.toggleContent, children: [
68
- /* @__PURE__ */ jsx(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
69
- /* @__PURE__ */ jsx(Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
135
+ children: /* @__PURE__ */ jsxs2(View2, { style: styles2.toggleContent, children: [
136
+ /* @__PURE__ */ jsx2(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
137
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
70
138
  ] })
71
139
  }
72
140
  ),
73
- showHaptics && /* @__PURE__ */ jsx(
141
+ showHaptics && /* @__PURE__ */ jsx2(
74
142
  TouchableRipple,
75
143
  {
76
144
  hapticDisabled: true,
@@ -79,40 +147,40 @@ function BaseSettingsDialog({ visible, onDismiss, rotation = 0, version, lockOri
79
147
  setHapticSettings({ vibrate });
80
148
  if (vibrate) forceHapticFeedback();
81
149
  },
82
- style: styles.toggleButtonInRow,
150
+ style: styles2.toggleButtonInRow,
83
151
  accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
84
- children: /* @__PURE__ */ jsxs(View, { style: styles.toggleContent, children: [
85
- /* @__PURE__ */ jsx(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
86
- /* @__PURE__ */ jsx(Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
152
+ children: /* @__PURE__ */ jsxs2(View2, { style: styles2.toggleContent, children: [
153
+ /* @__PURE__ */ jsx2(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
154
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
87
155
  ] })
88
156
  }
89
157
  )
90
158
  ] })
91
159
  ] }),
92
- showAppearance && /* @__PURE__ */ jsxs(View, { style: styles.section, children: [
93
- /* @__PURE__ */ jsx(Text, { variant: "labelMedium", style: [styles.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
94
- /* @__PURE__ */ jsx(AutoAppearancePicker, { showLabels: false })
160
+ showAppearance && /* @__PURE__ */ jsxs2(View2, { style: styles2.section, children: [
161
+ /* @__PURE__ */ jsx2(Text2, { variant: "labelMedium", style: [styles2.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
162
+ /* @__PURE__ */ jsx2(AutoAppearancePicker, { showLabels: false })
95
163
  ] }),
96
164
  children,
97
- showUpdateCheck && /* @__PURE__ */ jsxs(View, { style: styles.section, children: [
98
- /* @__PURE__ */ jsxs(Text, { variant: "labelSmall", style: [styles.sectionLabel, { color: colors.onSurfaceVariant }], children: [
165
+ showUpdateCheck && /* @__PURE__ */ jsxs2(View2, { style: styles2.section, children: [
166
+ /* @__PURE__ */ jsxs2(Text2, { variant: "labelSmall", style: [styles2.sectionLabel, { color: colors.onSurfaceVariant }], children: [
99
167
  "VERSION ",
100
168
  version,
101
169
  updateReady ? " \xB7 UPDATE READY" : ""
102
170
  ] }),
103
- /* @__PURE__ */ jsx(Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
171
+ /* @__PURE__ */ jsx2(Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
104
172
  ] })
105
173
  ] }) })
106
174
  ] }),
107
- infoMessage && /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(View, { style: styles.overlay, children: /* @__PURE__ */ jsxs(View, { style: [styles.overlayCard, { backgroundColor: cardBg, borderColor: cardBorder }, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
108
- /* @__PURE__ */ jsx(Icon, { source: "information-outline", size: 64, color: colors.secondary }),
109
- /* @__PURE__ */ jsx(Text, { variant: "headlineLarge", style: [styles.overlayTitle, { color: colors.secondary }], children: infoMessage.title }),
110
- /* @__PURE__ */ jsx(Text, { variant: "bodyLarge", style: [styles.overlayBody, { color: fg }], children: infoMessage.message }),
111
- /* @__PURE__ */ jsx(Button, { mode: "contained", onPress: () => setInfoMessage(null), style: styles.overlayButton, buttonColor: colors.primary, textColor: colors.onPrimary, children: "OK" })
175
+ infoMessage && /* @__PURE__ */ jsx2(Portal, { children: /* @__PURE__ */ jsx2(View2, { style: styles2.overlay, children: /* @__PURE__ */ jsxs2(View2, { style: [styles2.overlayCard, { backgroundColor: cardBg, borderColor: cardBorder }, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
176
+ /* @__PURE__ */ jsx2(Icon2, { source: "information-outline", size: 64, color: colors.secondary }),
177
+ /* @__PURE__ */ jsx2(Text2, { variant: "headlineLarge", style: [styles2.overlayTitle, { color: colors.secondary }], children: infoMessage.title }),
178
+ /* @__PURE__ */ jsx2(Text2, { variant: "bodyLarge", style: [styles2.overlayBody, { color: fg }], children: infoMessage.message }),
179
+ /* @__PURE__ */ jsx2(Button, { mode: "contained", onPress: () => setInfoMessage(null), style: styles2.overlayButton, buttonColor: colors.primary, textColor: colors.onPrimary, children: "OK" })
112
180
  ] }) }) })
113
181
  ] });
114
182
  }
115
- var styles = StyleSheet.create({
183
+ var styles2 = StyleSheet2.create({
116
184
  content: {
117
185
  gap: 24,
118
186
  paddingVertical: 20
@@ -200,17 +268,117 @@ var styles = StyleSheet.create({
200
268
  }
201
269
  });
202
270
 
271
+ // src/BaseStatsScreen.tsx
272
+ import { useAutoPaperTheme as useAutoPaperTheme3 } from "@rific/auto-paper";
273
+ import { Button as Button2, IconButton } from "@rific/feedback-press";
274
+ import { useState as useState2 } from "react";
275
+ import { ScrollView as ScrollView2, StyleSheet as StyleSheet3, View as View3 } from "react-native";
276
+ import { Icon as Icon3, Portal as Portal2, Text as Text3 } from "react-native-paper";
277
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
278
+ function BaseStatsScreen({ rotation = 0, title = "Achievements", onBack, insets, onReset, resetLabel = "Reset All Stats", resetConfirmTitle = "Reset Everything?", resetConfirmBody = "This permanently erases all stats and achievements. This cannot be undone.", children }) {
279
+ const { dark, colors } = useAutoPaperTheme3();
280
+ const [confirmResetVisible, setConfirmResetVisible] = useState2(false);
281
+ const showReset = !!onReset;
282
+ const fg = dark ? "#FFFFFF" : "#000000";
283
+ const bg = dark ? "#000000" : "#FFFFFF";
284
+ const cardBg = dark ? "#111111" : "#F2F2F2";
285
+ const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
286
+ return /* @__PURE__ */ jsxs3(View3, { style: [styles3.container, { backgroundColor: bg }], children: [
287
+ /* @__PURE__ */ jsxs3(View3, { style: [styles3.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
288
+ /* @__PURE__ */ jsx3(IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
289
+ /* @__PURE__ */ jsx3(Text3, { variant: "displaySmall", style: [styles3.title, { color: fg }], children: title })
290
+ ] }),
291
+ /* @__PURE__ */ jsxs3(ScrollView2, { style: styles3.scrollView, contentContainerStyle: [styles3.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
292
+ children,
293
+ showReset && /* @__PURE__ */ jsx3(Button2, { mode: "outlined", onPress: () => setConfirmResetVisible(true), textColor: colors.secondary, style: styles3.resetButton, children: resetLabel })
294
+ ] }),
295
+ confirmResetVisible && /* @__PURE__ */ jsx3(Portal2, { children: /* @__PURE__ */ jsx3(View3, { style: [styles3.overlay, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: /* @__PURE__ */ jsxs3(View3, { style: [styles3.overlayCard, { backgroundColor: cardBg, borderColor: cardBorder }], children: [
296
+ /* @__PURE__ */ jsx3(Icon3, { source: "alert-outline", size: 64, color: colors.secondary }),
297
+ /* @__PURE__ */ jsx3(Text3, { variant: "headlineLarge", style: [styles3.overlayTitle, { color: colors.secondary }], children: resetConfirmTitle }),
298
+ /* @__PURE__ */ jsx3(Text3, { variant: "bodyLarge", style: [styles3.overlayBody, { color: fg }], children: resetConfirmBody }),
299
+ /* @__PURE__ */ jsx3(Button2, { mode: "contained", onPress: () => setConfirmResetVisible(false), style: styles3.overlayButton, children: "Cancel" }),
300
+ /* @__PURE__ */ jsx3(
301
+ Button2,
302
+ {
303
+ mode: "contained",
304
+ onPress: () => {
305
+ onReset?.();
306
+ setConfirmResetVisible(false);
307
+ },
308
+ style: styles3.overlayButton,
309
+ buttonColor: colors.secondary,
310
+ textColor: colors.onSecondary,
311
+ children: "Reset"
312
+ }
313
+ )
314
+ ] }) }) })
315
+ ] });
316
+ }
317
+ var styles3 = StyleSheet3.create({
318
+ container: {
319
+ flex: 1
320
+ },
321
+ content: {
322
+ gap: 12,
323
+ paddingHorizontal: 20
324
+ },
325
+ header: {
326
+ alignItems: "center",
327
+ flexDirection: "row",
328
+ gap: 4,
329
+ paddingBottom: 8
330
+ },
331
+ // Same overlay shape BaseSettingsDialog's own info overlay uses (backdrop + centered card),
332
+ // rotated in place the same way rather than via Portal-root transform for the same reason — see
333
+ // that component's own identical styles for the full rationale.
334
+ overlay: {
335
+ alignItems: "center",
336
+ backgroundColor: "rgba(0,0,0,0.72)",
337
+ bottom: 0,
338
+ justifyContent: "center",
339
+ left: 0,
340
+ position: "absolute",
341
+ right: 0,
342
+ top: 0
343
+ },
344
+ overlayBody: { textAlign: "center" },
345
+ overlayButton: { width: 160 },
346
+ overlayCard: {
347
+ alignItems: "center",
348
+ borderRadius: 20,
349
+ borderWidth: 1,
350
+ gap: 16,
351
+ maxWidth: 360,
352
+ padding: 32
353
+ },
354
+ overlayTitle: { fontWeight: "bold", marginBottom: -8 },
355
+ resetButton: {
356
+ marginTop: 16
357
+ },
358
+ // Bounds the ScrollView to the space `container`'s flex:1 actually gives it — without this, a
359
+ // ScrollView with only a contentContainerStyle isn't reliably height-constrained on native (it
360
+ // can render at its full unclipped content height instead of the screen's), which leaves the
361
+ // header's back button touch target unreliable underneath it.
362
+ scrollView: {
363
+ flex: 1
364
+ },
365
+ title: {
366
+ flexShrink: 1,
367
+ fontWeight: "bold"
368
+ }
369
+ });
370
+
203
371
  // src/CornerActionButtons.tsx
204
- import { IconButton } from "@rific/feedback-press";
205
- import { StyleSheet as StyleSheet2 } from "react-native";
206
- import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
372
+ import { IconButton as IconButton2 } from "@rific/feedback-press";
373
+ import { StyleSheet as StyleSheet4 } from "react-native";
374
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
207
375
  function CornerActionButtons({ onBack, onSettings, fg, insets }) {
208
- return /* @__PURE__ */ jsxs2(Fragment2, { children: [
209
- /* @__PURE__ */ jsx2(IconButton, { icon: "arrow-left", iconColor: fg, size: 24, style: [styles2.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: "Back" }),
210
- /* @__PURE__ */ jsx2(IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles2.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
376
+ return /* @__PURE__ */ jsxs4(Fragment2, { children: [
377
+ /* @__PURE__ */ jsx4(IconButton2, { icon: "arrow-left", iconColor: fg, size: 24, style: [styles4.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: "Back" }),
378
+ /* @__PURE__ */ jsx4(IconButton2, { icon: "cog", iconColor: fg, size: 24, style: [styles4.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
211
379
  ] });
212
380
  }
213
- var styles2 = StyleSheet2.create({
381
+ var styles4 = StyleSheet4.create({
214
382
  back: {
215
383
  position: "absolute"
216
384
  },
@@ -227,34 +395,34 @@ var MONO_FONT = Platform2.select({ ios: "Menlo", android: "monospace", default:
227
395
  import { defaultColors, getContrastColor } from "@rific/auto-paper";
228
396
  import { TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
229
397
  import { clamp } from "@tastic/core";
230
- import { ScrollView as ScrollView2, StyleSheet as StyleSheet4, useWindowDimensions as useWindowDimensions2, View as View4 } from "react-native";
231
- import { Icon as Icon2, Text as Text2 } from "react-native-paper";
398
+ import { ScrollView as ScrollView3, StyleSheet as StyleSheet6, useWindowDimensions as useWindowDimensions2, View as View6 } from "react-native";
399
+ import { Icon as Icon4, Text as Text4 } from "react-native-paper";
232
400
 
233
401
  // src/PopoverBody.tsx
234
- import { StyleSheet as StyleSheet3, View as View2 } from "react-native";
235
- import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
402
+ import { StyleSheet as StyleSheet5, View as View4 } from "react-native";
403
+ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
236
404
  var CARET_SIZE = 7;
237
405
  var CARET_RING_OFFSET = 2;
238
406
  var CARET_DIP = 1;
239
407
  function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
240
408
  if (!visible) return null;
241
409
  const above = verticalAlign === "above";
242
- const alignStyle = align === "left" ? styles3.contentLeft : align === "right" ? styles3.contentRight : styles3.contentCenter;
243
- const verticalStyle = above ? styles3.contentAbove : styles3.contentBelow;
410
+ const alignStyle = align === "left" ? styles5.contentLeft : align === "right" ? styles5.contentRight : styles5.contentCenter;
411
+ const verticalStyle = above ? styles5.contentAbove : styles5.contentBelow;
244
412
  const ringSize = CARET_SIZE + caretBorderWidth;
245
413
  const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
246
414
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
247
415
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
248
416
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
249
- return /* @__PURE__ */ jsxs3(View2, { style: [styles3.content, alignStyle, verticalStyle], children: [
417
+ return /* @__PURE__ */ jsxs5(View4, { style: [styles5.content, alignStyle, verticalStyle], children: [
250
418
  children,
251
- caretColor && /* @__PURE__ */ jsxs3(Fragment3, { children: [
252
- /* @__PURE__ */ jsx3(View2, { style: [styles3.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
253
- /* @__PURE__ */ jsx3(View2, { style: [styles3.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
419
+ caretColor && /* @__PURE__ */ jsxs5(Fragment3, { children: [
420
+ /* @__PURE__ */ jsx5(View4, { style: [styles5.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
421
+ /* @__PURE__ */ jsx5(View4, { style: [styles5.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
254
422
  ] })
255
423
  ] });
256
424
  }
257
- var styles3 = StyleSheet3.create({
425
+ var styles5 = StyleSheet5.create({
258
426
  caret: {
259
427
  borderLeftColor: "transparent",
260
428
  borderRightColor: "transparent",
@@ -297,17 +465,17 @@ var styles3 = StyleSheet3.create({
297
465
  });
298
466
 
299
467
  // src/useAutoAlign.ts
300
- import { useCallback, useEffect, useRef, useState as useState2 } from "react";
468
+ import { useCallback, useEffect, useRef, useState as useState3 } from "react";
301
469
  import { useWindowDimensions } from "react-native";
302
470
  var EDGE_MARGIN = 12;
303
471
  function useAutoAlign(open, contentWidth, contentHeight) {
304
472
  const triggerRef = useRef(null);
305
473
  const { width: windowWidth, height: windowHeight } = useWindowDimensions();
306
- const [align, setAlign] = useState2("center");
307
- const [verticalAlign, setVerticalAlign] = useState2("below");
308
- const [maxHeight, setMaxHeight] = useState2(contentHeight);
309
- const [measured, setMeasured] = useState2(false);
310
- const [prevOpen, setPrevOpen] = useState2(open);
474
+ const [align, setAlign] = useState3("center");
475
+ const [verticalAlign, setVerticalAlign] = useState3("below");
476
+ const [maxHeight, setMaxHeight] = useState3(contentHeight);
477
+ const [measured, setMeasured] = useState3(false);
478
+ const [prevOpen, setPrevOpen] = useState3(open);
311
479
  if (open !== prevOpen) {
312
480
  setPrevOpen(open);
313
481
  if (open) setMeasured(false);
@@ -335,7 +503,7 @@ function useAutoAlign(open, contentWidth, contentHeight) {
335
503
  }
336
504
 
337
505
  // src/InlineColorPicker.tsx
338
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
506
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
339
507
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
340
508
  var DEFAULT_SIZE = 48;
341
509
  var SWATCH_SIZE = 28;
@@ -361,13 +529,13 @@ function InlineColorPicker({ id, host, value, onChange, swatches = defaultColors
361
529
  const align = alignOverride ?? autoAlign;
362
530
  const contrastColor = getContrastColor(value);
363
531
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
364
- return /* @__PURE__ */ jsxs4(View4, { style: [styles4.anchor, open && styles4.anchorOpen], children: [
365
- /* @__PURE__ */ jsx4(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles4.trigger, { backgroundColor: value, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx4(View4, { ref: triggerRef, collapsable: false, style: styles4.triggerMeasure, children: tag ? /* @__PURE__ */ jsx4(Text2, { style: [styles4.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx4(Icon2, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
366
- /* @__PURE__ */ jsx4(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: value, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx4(ScrollView2, { style: [styles4.swatches, { backgroundColor: menuBg, borderColor: value, width: swatchesWidth, maxHeight }], contentContainerStyle: styles4.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
532
+ return /* @__PURE__ */ jsxs6(View6, { style: [styles6.anchor, open && styles6.anchorOpen], children: [
533
+ /* @__PURE__ */ jsx6(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles6.trigger, { backgroundColor: value, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx6(View6, { ref: triggerRef, collapsable: false, style: styles6.triggerMeasure, children: tag ? /* @__PURE__ */ jsx6(Text4, { style: [styles6.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx6(Icon4, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
534
+ /* @__PURE__ */ jsx6(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: value, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx6(ScrollView3, { style: [styles6.swatches, { backgroundColor: menuBg, borderColor: value, width: swatchesWidth, maxHeight }], contentContainerStyle: styles6.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
367
535
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
368
536
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
369
537
  const swappable = taken && allowSwapTaken;
370
- return /* @__PURE__ */ jsx4(
538
+ return /* @__PURE__ */ jsx6(
371
539
  TouchableRipple2,
372
540
  {
373
541
  disabled: taken && !swappable,
@@ -376,15 +544,15 @@ function InlineColorPicker({ id, host, value, onChange, swatches = defaultColors
376
544
  if (autoDismiss) host.close();
377
545
  },
378
546
  borderless: true,
379
- style: [styles4.swatch, { backgroundColor: swatch.value }, selected && styles4.swatchSelected, taken && !swappable && styles4.swatchTaken],
380
- children: selected ? /* @__PURE__ */ jsx4(Icon2, { source: "check", size: 16, color: getContrastColor(swatch.value) }) : swappable ? /* @__PURE__ */ jsx4(Icon2, { source: "swap-horizontal", size: 16, color: getContrastColor(swatch.value) }) : taken ? /* @__PURE__ */ jsx4(Icon2, { source: "close", size: 16, color: getContrastColor(swatch.value) }) : /* @__PURE__ */ jsx4(View4, {})
547
+ style: [styles6.swatch, { backgroundColor: swatch.value }, selected && styles6.swatchSelected, taken && !swappable && styles6.swatchTaken],
548
+ children: selected ? /* @__PURE__ */ jsx6(Icon4, { source: "check", size: 16, color: getContrastColor(swatch.value) }) : swappable ? /* @__PURE__ */ jsx6(Icon4, { source: "swap-horizontal", size: 16, color: getContrastColor(swatch.value) }) : taken ? /* @__PURE__ */ jsx6(Icon4, { source: "close", size: 16, color: getContrastColor(swatch.value) }) : /* @__PURE__ */ jsx6(View6, {})
381
549
  },
382
550
  swatch.value
383
551
  );
384
552
  }) }) })
385
553
  ] });
386
554
  }
387
- var styles4 = StyleSheet4.create({
555
+ var styles6 = StyleSheet6.create({
388
556
  anchor: {
389
557
  position: "relative"
390
558
  },
@@ -458,9 +626,9 @@ var styles4 = StyleSheet4.create({
458
626
  // src/LabeledDropdown.tsx
459
627
  import { getContrastColor as getContrastColor2 } from "@rific/auto-paper";
460
628
  import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
461
- import { ScrollView as ScrollView3, StyleSheet as StyleSheet5, View as View5 } from "react-native";
462
- import { Icon as Icon3, Text as Text3 } from "react-native-paper";
463
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
629
+ import { ScrollView as ScrollView4, StyleSheet as StyleSheet7, View as View7 } from "react-native";
630
+ import { Icon as Icon5, Text as Text5 } from "react-native-paper";
631
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
464
632
  var TRIGGER_HEIGHT = 28;
465
633
  var POPOVER_WIDTH = 180;
466
634
  var ROW_HEIGHT = 36;
@@ -483,22 +651,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
483
651
  onChange(option.value);
484
652
  host.close();
485
653
  };
486
- return /* @__PURE__ */ jsxs5(View5, { style: [styles5.anchor, open && styles5.anchorOpen], children: [
487
- /* @__PURE__ */ jsx5(TouchableRipple3, { onPress: () => host.toggle(id), style: styles5.trigger, children: /* @__PURE__ */ jsxs5(View5, { ref: triggerRef, collapsable: false, style: styles5.triggerInner, children: [
488
- /* @__PURE__ */ jsx5(Text3, { style: [styles5.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
489
- /* @__PURE__ */ jsx5(Icon3, { source: "menu-down", size: 16, color })
654
+ return /* @__PURE__ */ jsxs7(View7, { style: [styles7.anchor, open && styles7.anchorOpen], children: [
655
+ /* @__PURE__ */ jsx7(TouchableRipple3, { onPress: () => host.toggle(id), style: styles7.trigger, children: /* @__PURE__ */ jsxs7(View7, { ref: triggerRef, collapsable: false, style: styles7.triggerInner, children: [
656
+ /* @__PURE__ */ jsx7(Text5, { style: [styles7.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
657
+ /* @__PURE__ */ jsx7(Icon5, { source: "menu-down", size: 16, color })
490
658
  ] }) }),
491
- /* @__PURE__ */ jsx5(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx5(ScrollView3, { style: [styles5.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles5.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
659
+ /* @__PURE__ */ jsx7(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx7(ScrollView4, { style: [styles7.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles7.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
492
660
  const isSelected = option.value === value;
493
661
  const onColor = getContrastColor2(color);
494
- return /* @__PURE__ */ jsx5(TouchableRipple3, { onPress: () => handleSelect(option), style: [styles5.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs5(View5, { style: styles5.rowInner, children: [
495
- option.icon && /* @__PURE__ */ jsx5(Icon3, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
496
- /* @__PURE__ */ jsx5(Text3, { style: [styles5.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
662
+ return /* @__PURE__ */ jsx7(TouchableRipple3, { onPress: () => handleSelect(option), style: [styles7.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs7(View7, { style: styles7.rowInner, children: [
663
+ option.icon && /* @__PURE__ */ jsx7(Icon5, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
664
+ /* @__PURE__ */ jsx7(Text5, { style: [styles7.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
497
665
  ] }) }, option.value);
498
666
  }) }) })
499
667
  ] });
500
668
  }
501
- var styles5 = StyleSheet5.create({
669
+ var styles7 = StyleSheet7.create({
502
670
  anchor: {
503
671
  position: "relative"
504
672
  },
@@ -556,25 +724,25 @@ function loadSkiaWeb() {
556
724
  }
557
725
 
558
726
  // src/PressAwayOverlay.tsx
559
- import { Pressable, StyleSheet as StyleSheet6 } from "react-native";
560
- import { jsx as jsx6 } from "react/jsx-runtime";
727
+ import { Pressable, StyleSheet as StyleSheet8 } from "react-native";
728
+ import { jsx as jsx8 } from "react/jsx-runtime";
561
729
  function PressAwayOverlay({ active, onPress, style }) {
562
730
  if (!active) return null;
563
- return /* @__PURE__ */ jsx6(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet6.absoluteFill, style] });
731
+ return /* @__PURE__ */ jsx8(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet8.absoluteFill, style] });
564
732
  }
565
733
 
566
734
  // src/ReadyButton.tsx
567
735
  import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
568
- import { StyleSheet as StyleSheet7 } from "react-native";
569
- import { Text as Text4 } from "react-native-paper";
570
- import { jsx as jsx7 } from "react/jsx-runtime";
736
+ import { StyleSheet as StyleSheet9 } from "react-native";
737
+ import { Text as Text6 } from "react-native-paper";
738
+ import { jsx as jsx9 } from "react/jsx-runtime";
571
739
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
572
- const readyButtonStyle = [styles6.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
740
+ const readyButtonStyle = [styles8.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
573
741
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
574
742
  const labelColorStyle = { color: ready ? "#000000" : color };
575
- return /* @__PURE__ */ jsx7(TouchableRipple4, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx7(Text4, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
743
+ return /* @__PURE__ */ jsx9(TouchableRipple4, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx9(Text6, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
576
744
  }
577
- var styles6 = StyleSheet7.create({
745
+ var styles8 = StyleSheet9.create({
578
746
  readyButton: {
579
747
  alignItems: "center",
580
748
  borderRadius: 12,
@@ -588,20 +756,20 @@ var styles6 = StyleSheet7.create({
588
756
 
589
757
  // src/SectionedDropdown.tsx
590
758
  import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
591
- import { IconButton as IconButton2, TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
592
- import { ScrollView as ScrollView4, StyleSheet as StyleSheet8, View as View6 } from "react-native";
593
- import { Icon as Icon4, Text as Text5 } from "react-native-paper";
759
+ import { IconButton as IconButton3, TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
760
+ import { ScrollView as ScrollView5, StyleSheet as StyleSheet10, View as View8 } from "react-native";
761
+ import { Icon as Icon6, Text as Text7 } from "react-native-paper";
594
762
 
595
763
  // src/TriggerGaugeHost.tsx
596
764
  import { lazy, Suspense } from "react";
597
- import { jsx as jsx8 } from "react/jsx-runtime";
765
+ import { jsx as jsx10 } from "react/jsx-runtime";
598
766
  var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-2OJOOF6I.mjs").then((m) => ({ default: m.TriggerGauge }))));
599
767
  function TriggerGaugeHost(props) {
600
- return /* @__PURE__ */ jsx8(Suspense, { fallback: null, children: /* @__PURE__ */ jsx8(LazyTriggerGauge, { ...props }) });
768
+ return /* @__PURE__ */ jsx10(Suspense, { fallback: null, children: /* @__PURE__ */ jsx10(LazyTriggerGauge, { ...props }) });
601
769
  }
602
770
 
603
771
  // src/SectionedDropdown.tsx
604
- import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
772
+ import { Fragment as Fragment4, jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
605
773
  var MENU_BORDER_WIDTH = 1;
606
774
  var TRIGGER_SIZE = 44;
607
775
  var MENU_MIN_WIDTH = 200;
@@ -647,17 +815,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
647
815
  }
648
816
  gaugeOffset += section.options.length;
649
817
  }
650
- const anchorStyle = [styles7.anchor, open && styles7.anchorOpen];
818
+ const anchorStyle = [styles9.anchor, open && styles9.anchorOpen];
651
819
  const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
652
820
  const dividerStyle = { backgroundColor: menuBorderColor };
653
- return /* @__PURE__ */ jsxs6(View6, { style: anchorStyle, children: [
654
- /* @__PURE__ */ jsxs6(View6, { ref: triggerRef, collapsable: false, style: styles7.triggerBox, children: [
655
- /* @__PURE__ */ jsx9(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
656
- /* @__PURE__ */ jsx9(IconButton2, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
821
+ return /* @__PURE__ */ jsxs8(View8, { style: anchorStyle, children: [
822
+ /* @__PURE__ */ jsxs8(View8, { ref: triggerRef, collapsable: false, style: styles9.triggerBox, children: [
823
+ /* @__PURE__ */ jsx11(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
824
+ /* @__PURE__ */ jsx11(IconButton3, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
657
825
  ] }),
658
- /* @__PURE__ */ jsx9(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx9(ScrollView4, { style: [styles7.menu, menuStyle], contentContainerStyle: styles7.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs6(View6, { children: [
659
- sectionIndex > 0 && /* @__PURE__ */ jsx9(View6, { style: [styles7.divider, dividerStyle] }),
660
- section.kind === "single" ? /* @__PURE__ */ jsx9(
826
+ /* @__PURE__ */ jsx11(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx11(ScrollView5, { style: [styles9.menu, menuStyle], contentContainerStyle: styles9.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs8(View8, { children: [
827
+ sectionIndex > 0 && /* @__PURE__ */ jsx11(View8, { style: [styles9.divider, dividerStyle] }),
828
+ section.kind === "single" ? /* @__PURE__ */ jsx11(
661
829
  SingleSection,
662
830
  {
663
831
  section,
@@ -670,7 +838,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
670
838
  if (autoDismiss) host.close();
671
839
  }
672
840
  }
673
- ) : /* @__PURE__ */ jsx9(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
841
+ ) : /* @__PURE__ */ jsx11(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
674
842
  ] }, section.id)) }) })
675
843
  ] });
676
844
  }
@@ -682,17 +850,17 @@ function SingleSection({
682
850
  labelFontFamily,
683
851
  onSelect
684
852
  }) {
685
- return /* @__PURE__ */ jsx9(Fragment4, { children: section.options.map((option) => {
853
+ return /* @__PURE__ */ jsx11(Fragment4, { children: section.options.map((option) => {
686
854
  const selected = option.value === section.value;
687
855
  const rowColor = selected ? onAccentColor : mutedColor;
688
- const itemStyle = [styles7.item, selected && { backgroundColor: accentColor }];
856
+ const itemStyle = [styles9.item, selected && { backgroundColor: accentColor }];
689
857
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
690
858
  const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
691
- return /* @__PURE__ */ jsx9(TouchableRipple5, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs6(View6, { style: styles7.itemRow, children: [
692
- option.icon && /* @__PURE__ */ jsx9(Icon4, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
693
- /* @__PURE__ */ jsxs6(View6, { style: styles7.itemLabelColumn, children: [
694
- /* @__PURE__ */ jsx9(Text5, { variant: "labelLarge", style: labelStyle, children: option.label }),
695
- option.description && /* @__PURE__ */ jsx9(Text5, { variant: "labelSmall", style: descriptionStyle, children: option.description })
859
+ return /* @__PURE__ */ jsx11(TouchableRipple5, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs8(View8, { style: styles9.itemRow, children: [
860
+ option.icon && /* @__PURE__ */ jsx11(Icon6, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
861
+ /* @__PURE__ */ jsxs8(View8, { style: styles9.itemLabelColumn, children: [
862
+ /* @__PURE__ */ jsx11(Text7, { variant: "labelLarge", style: labelStyle, children: option.label }),
863
+ option.description && /* @__PURE__ */ jsx11(Text7, { variant: "labelSmall", style: descriptionStyle, children: option.description })
696
864
  ] })
697
865
  ] }) }, option.value);
698
866
  }) });
@@ -706,23 +874,23 @@ function MultiSection({
706
874
  allClearLabels
707
875
  }) {
708
876
  const allSelected = section.value.length === section.options.length;
709
- return /* @__PURE__ */ jsxs6(Fragment4, { children: [
877
+ return /* @__PURE__ */ jsxs8(Fragment4, { children: [
710
878
  section.options.map((option, i) => {
711
879
  const selected = section.value.includes(option.value);
712
880
  const rowColor = selected ? onAccentColor : mutedColor;
713
881
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
714
882
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
715
- const itemStyle = [styles7.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
883
+ const itemStyle = [styles9.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
716
884
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
717
- return /* @__PURE__ */ jsx9(TouchableRipple5, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs6(View6, { style: styles7.itemRow, children: [
718
- option.icon && /* @__PURE__ */ jsx9(Icon4, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
719
- /* @__PURE__ */ jsx9(Text5, { variant: "labelLarge", style: [styles7.itemLabelFlex, labelStyle], children: option.label })
885
+ return /* @__PURE__ */ jsx11(TouchableRipple5, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs8(View8, { style: styles9.itemRow, children: [
886
+ option.icon && /* @__PURE__ */ jsx11(Icon6, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
887
+ /* @__PURE__ */ jsx11(Text7, { variant: "labelLarge", style: [styles9.itemLabelFlex, labelStyle], children: option.label })
720
888
  ] }) }, option.value);
721
889
  }),
722
- section.allClear && /* @__PURE__ */ jsx9(TouchableRipple5, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles7.item, children: /* @__PURE__ */ jsx9(Text5, { variant: "labelLarge", style: [styles7.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
890
+ section.allClear && /* @__PURE__ */ jsx11(TouchableRipple5, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles9.item, children: /* @__PURE__ */ jsx11(Text7, { variant: "labelLarge", style: [styles9.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
723
891
  ] });
724
892
  }
725
- var styles7 = StyleSheet8.create({
893
+ var styles9 = StyleSheet10.create({
726
894
  allClearLabel: {
727
895
  fontWeight: "bold",
728
896
  textAlign: "center"
@@ -739,7 +907,7 @@ var styles7 = StyleSheet8.create({
739
907
  zIndex: 100
740
908
  },
741
909
  divider: {
742
- height: StyleSheet8.hairlineWidth,
910
+ height: StyleSheet10.hairlineWidth,
743
911
  marginVertical: 4
744
912
  },
745
913
  item: {
@@ -787,21 +955,21 @@ var styles7 = StyleSheet8.create({
787
955
  });
788
956
 
789
957
  // src/SharedActionBand.tsx
790
- import { IconButton as IconButton3 } from "@rific/feedback-press";
791
- import { StyleSheet as StyleSheet9, View as View7 } from "react-native";
792
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
958
+ import { IconButton as IconButton4 } from "@rific/feedback-press";
959
+ import { StyleSheet as StyleSheet11, View as View9 } from "react-native";
960
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
793
961
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
794
- return /* @__PURE__ */ jsxs7(View7, { style: [styles8.column, popoverOpen && styles8.columnOpen], children: [
795
- /* @__PURE__ */ jsxs7(View7, { style: styles8.actionsRow, children: [
796
- /* @__PURE__ */ jsx10(IconButton3, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
797
- onRandomize && /* @__PURE__ */ jsx10(IconButton3, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
798
- onReset && /* @__PURE__ */ jsx10(IconButton3, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
799
- /* @__PURE__ */ jsx10(IconButton3, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
962
+ return /* @__PURE__ */ jsxs9(View9, { style: [styles10.column, popoverOpen && styles10.columnOpen], children: [
963
+ /* @__PURE__ */ jsxs9(View9, { style: styles10.actionsRow, children: [
964
+ /* @__PURE__ */ jsx12(IconButton4, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
965
+ onRandomize && /* @__PURE__ */ jsx12(IconButton4, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
966
+ onReset && /* @__PURE__ */ jsx12(IconButton4, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
967
+ /* @__PURE__ */ jsx12(IconButton4, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
800
968
  ] }),
801
969
  children
802
970
  ] });
803
971
  }
804
- var styles8 = StyleSheet9.create({
972
+ var styles10 = StyleSheet11.create({
805
973
  actionsRow: {
806
974
  alignItems: "center",
807
975
  flexDirection: "row",
@@ -816,10 +984,60 @@ var styles8 = StyleSheet9.create({
816
984
  }
817
985
  });
818
986
 
987
+ // src/StatRow.tsx
988
+ import { useAutoPaperTheme as useAutoPaperTheme4 } from "@rific/auto-paper";
989
+ import { StyleSheet as StyleSheet12, View as View10 } from "react-native";
990
+ import { Text as Text8 } from "react-native-paper";
991
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
992
+ function StatRow({ label, value }) {
993
+ const { dark } = useAutoPaperTheme4();
994
+ const fg = dark ? "#FFFFFF" : "#000000";
995
+ const fgMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)";
996
+ return /* @__PURE__ */ jsxs10(View10, { style: styles11.row, children: [
997
+ /* @__PURE__ */ jsx13(Text8, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
998
+ /* @__PURE__ */ jsx13(Text8, { variant: "bodyMedium", style: [styles11.value, { color: fg }], children: value })
999
+ ] });
1000
+ }
1001
+ var styles11 = StyleSheet12.create({
1002
+ row: {
1003
+ alignItems: "center",
1004
+ flexDirection: "row",
1005
+ justifyContent: "space-between"
1006
+ },
1007
+ value: {
1008
+ fontWeight: "bold"
1009
+ }
1010
+ });
1011
+
1012
+ // src/StatSection.tsx
1013
+ import { useAutoPaperTheme as useAutoPaperTheme5 } from "@rific/auto-paper";
1014
+ import { StyleSheet as StyleSheet13, View as View11 } from "react-native";
1015
+ import { Text as Text9 } from "react-native-paper";
1016
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1017
+ function StatSection({ label, children }) {
1018
+ const { dark } = useAutoPaperTheme5();
1019
+ const fgMuted = dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)";
1020
+ const sectionBg = dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)";
1021
+ return /* @__PURE__ */ jsxs11(View11, { style: [styles12.section, { backgroundColor: sectionBg }], children: [
1022
+ /* @__PURE__ */ jsx14(Text9, { variant: "labelMedium", style: [styles12.label, { color: fgMuted }], children: label }),
1023
+ children
1024
+ ] });
1025
+ }
1026
+ var styles12 = StyleSheet13.create({
1027
+ label: {
1028
+ letterSpacing: 2
1029
+ },
1030
+ section: {
1031
+ borderRadius: 12,
1032
+ gap: 8,
1033
+ padding: 16
1034
+ }
1035
+ });
1036
+
819
1037
  // src/usePopoverHost.ts
820
- import { useCallback as useCallback2, useState as useState3 } from "react";
1038
+ import { useCallback as useCallback2, useState as useState4 } from "react";
821
1039
  function usePopoverHost() {
822
- const [openId, setOpenId] = useState3(null);
1040
+ const [openId, setOpenId] = useState4(null);
823
1041
  const toggle = useCallback2((id) => {
824
1042
  setOpenId((prev) => prev === id ? null : id);
825
1043
  }, []);
@@ -827,10 +1045,13 @@ function usePopoverHost() {
827
1045
  return { openId, toggle, close };
828
1046
  }
829
1047
  export {
1048
+ AchievementRow,
830
1049
  BaseSettingsDialog,
1050
+ BaseStatsScreen,
831
1051
  CornerActionButtons,
832
1052
  InlineColorPicker,
833
1053
  LABELED_DROPDOWN_POPOVER_WIDTH,
1054
+ LOCKED_BADGE_COLOR,
834
1055
  LabeledDropdown,
835
1056
  MONO_FONT,
836
1057
  PopoverBody,
@@ -838,6 +1059,8 @@ export {
838
1059
  ReadyButton,
839
1060
  SectionedDropdown,
840
1061
  SharedActionBand,
1062
+ StatRow,
1063
+ StatSection,
841
1064
  TriggerGaugeHost,
842
1065
  getLabeledDropdownContentHeight,
843
1066
  loadSkiaWeb,