@tastic/hud 0.8.5 → 0.12.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/README.md +301 -20
- package/dist/index.d.mts +107 -15
- package/dist/index.d.ts +107 -15
- package/dist/index.js +528 -306
- package/dist/index.mjs +455 -253
- package/package.json +16 -8
- package/src/AchievementCatalogSection.tsx +60 -0
- package/src/ActivityStatSection.tsx +29 -0
- package/src/ControlSchemePicker.tsx +11 -2
- package/src/InlineColorPicker.tsx +38 -11
- package/src/LabeledDropdown.tsx +5 -17
- package/src/PlayerSetupPanel.tsx +196 -0
- package/src/SectionedDropdown.tsx +18 -7
- package/src/StaggeredWord.tsx +114 -0
- package/src/index.ts +8 -2
- package/src/useAutoAlign.ts +17 -1
- package/src/useQuitConfirmation.ts +61 -0
- package/src/useZoneClampedAlign.ts +135 -0
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,12 @@ import {
|
|
|
2
2
|
SkiaGate
|
|
3
3
|
} from "./chunk-XEOFR236.mjs";
|
|
4
4
|
|
|
5
|
+
// src/AchievementCatalogSection.tsx
|
|
6
|
+
import { useAutoPaperTheme as useAutoPaperTheme2 } from "@rific/auto-paper";
|
|
7
|
+
import { Fragment } from "react";
|
|
8
|
+
import { StyleSheet as StyleSheet2 } from "react-native";
|
|
9
|
+
import { Text as Text2 } from "react-native-paper";
|
|
10
|
+
|
|
5
11
|
// src/AchievementRow.tsx
|
|
6
12
|
import { useAutoPaperTheme } from "@rific/auto-paper";
|
|
7
13
|
import { StyleSheet, View } from "react-native";
|
|
@@ -70,24 +76,110 @@ var styles = StyleSheet.create({
|
|
|
70
76
|
}
|
|
71
77
|
});
|
|
72
78
|
|
|
79
|
+
// src/fonts.ts
|
|
80
|
+
import { Platform } from "react-native";
|
|
81
|
+
var MONO_FONT = Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
82
|
+
|
|
83
|
+
// src/AchievementCatalogSection.tsx
|
|
84
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
85
|
+
function AchievementCatalogSection({ rows, label = "ALL ACHIEVEMENTS", fg, fgMuted: fgMutedOverride }) {
|
|
86
|
+
const { dark } = useAutoPaperTheme2();
|
|
87
|
+
const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
|
|
88
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
89
|
+
/* @__PURE__ */ jsx2(Text2, { variant: "labelMedium", style: [styles2.label, { color: fgMuted, fontFamily: MONO_FONT }], children: label }),
|
|
90
|
+
rows.map((row) => /* @__PURE__ */ jsx2(AchievementRow, { icon: row.icon, title: row.title, description: row.description, badgeColor: row.unlockedAt !== void 0 ? row.tierColor : LOCKED_BADGE_COLOR, checkColor: row.tierColor, unlockedLabel: row.unlockedLabel, progress: row.progress, deviceMarker: row.deviceMarker, fg, fgMuted: fgMutedOverride }, row.id))
|
|
91
|
+
] });
|
|
92
|
+
}
|
|
93
|
+
var styles2 = StyleSheet2.create({
|
|
94
|
+
label: {
|
|
95
|
+
letterSpacing: 2,
|
|
96
|
+
marginTop: 8
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// src/StatRow.tsx
|
|
101
|
+
import { useAutoPaperTheme as useAutoPaperTheme3 } from "@rific/auto-paper";
|
|
102
|
+
import { StyleSheet as StyleSheet3, View as View2 } from "react-native";
|
|
103
|
+
import { Text as Text3 } from "react-native-paper";
|
|
104
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
105
|
+
function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
|
|
106
|
+
const { dark } = useAutoPaperTheme3();
|
|
107
|
+
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
108
|
+
const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
|
|
109
|
+
return /* @__PURE__ */ jsxs3(View2, { style: styles3.row, children: [
|
|
110
|
+
/* @__PURE__ */ jsx3(Text3, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
|
|
111
|
+
/* @__PURE__ */ jsx3(Text3, { variant: "bodyMedium", style: [styles3.value, { color: fg }], children: value })
|
|
112
|
+
] });
|
|
113
|
+
}
|
|
114
|
+
var styles3 = StyleSheet3.create({
|
|
115
|
+
row: {
|
|
116
|
+
alignItems: "center",
|
|
117
|
+
flexDirection: "row",
|
|
118
|
+
justifyContent: "space-between"
|
|
119
|
+
},
|
|
120
|
+
value: {
|
|
121
|
+
fontWeight: "bold"
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// src/StatSection.tsx
|
|
126
|
+
import { useAutoPaperTheme as useAutoPaperTheme4 } from "@rific/auto-paper";
|
|
127
|
+
import { StyleSheet as StyleSheet4, View as View3 } from "react-native";
|
|
128
|
+
import { Text as Text4 } from "react-native-paper";
|
|
129
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
130
|
+
function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
|
|
131
|
+
const { dark } = useAutoPaperTheme4();
|
|
132
|
+
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
133
|
+
const sectionBg = sectionBgOverride ?? (dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)");
|
|
134
|
+
return /* @__PURE__ */ jsxs4(View3, { style: [styles4.section, { backgroundColor: sectionBg }], children: [
|
|
135
|
+
/* @__PURE__ */ jsx4(Text4, { variant: "labelMedium", style: [styles4.label, { color: fg }], children: label }),
|
|
136
|
+
children
|
|
137
|
+
] });
|
|
138
|
+
}
|
|
139
|
+
var styles4 = StyleSheet4.create({
|
|
140
|
+
// Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
|
|
141
|
+
// same visual weight as StatRow's own row labels below it (both used the identical muted color;
|
|
142
|
+
// letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
|
|
143
|
+
// at a glance). Matches AchievementRow's own title styling (bold + fg) below it in the same list.
|
|
144
|
+
label: {
|
|
145
|
+
fontWeight: "bold",
|
|
146
|
+
letterSpacing: 2
|
|
147
|
+
},
|
|
148
|
+
section: {
|
|
149
|
+
borderRadius: 12,
|
|
150
|
+
gap: 8,
|
|
151
|
+
padding: 16
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// src/ActivityStatSection.tsx
|
|
156
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
157
|
+
function ActivityStatSection({ stats }) {
|
|
158
|
+
return /* @__PURE__ */ jsxs5(StatSection, { label: "ACTIVITY", children: [
|
|
159
|
+
/* @__PURE__ */ jsx5(StatRow, { label: "Days Played", value: String(stats.distinctDaysPlayed) }),
|
|
160
|
+
/* @__PURE__ */ jsx5(StatRow, { label: "Day Streak", value: String(stats.currentDayStreak) }),
|
|
161
|
+
/* @__PURE__ */ jsx5(StatRow, { label: "Best Day Streak", value: String(stats.bestDayStreak) })
|
|
162
|
+
] });
|
|
163
|
+
}
|
|
164
|
+
|
|
73
165
|
// src/BaseSettingsDialog.tsx
|
|
74
|
-
import { AutoAppearancePicker, Dialog, useAutoPaperTheme as
|
|
166
|
+
import { AutoAppearancePicker, Dialog, useAutoPaperTheme as useAutoPaperTheme6 } from "@rific/auto-paper";
|
|
75
167
|
import { Button as Button2, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from "@rific/feedback-press";
|
|
76
168
|
import { useUpdater } from "@rific/updater";
|
|
77
169
|
import { toRotationStyle as toRotationStyle2, useIsTouchPrimaryDevice, useRotation } from "@tastic/core";
|
|
78
170
|
import { useContext, useState as useState2 } from "react";
|
|
79
|
-
import { Platform, ScrollView, StyleSheet as
|
|
80
|
-
import { Icon as Icon3, Text as
|
|
171
|
+
import { Platform as Platform2, ScrollView, StyleSheet as StyleSheet7, View as View5 } from "react-native";
|
|
172
|
+
import { Icon as Icon3, Text as Text6 } from "react-native-paper";
|
|
81
173
|
|
|
82
174
|
// src/ConfirmDialog.tsx
|
|
83
|
-
import { useAutoPaperTheme as
|
|
175
|
+
import { useAutoPaperTheme as useAutoPaperTheme5 } from "@rific/auto-paper";
|
|
84
176
|
import { Button } from "@rific/feedback-press";
|
|
85
177
|
import { toRotationStyle } from "@tastic/core";
|
|
86
|
-
import { StyleSheet as
|
|
87
|
-
import { Icon as Icon2, Portal, Text as
|
|
178
|
+
import { StyleSheet as StyleSheet6, View as View4 } from "react-native";
|
|
179
|
+
import { Icon as Icon2, Portal, Text as Text5 } from "react-native-paper";
|
|
88
180
|
|
|
89
181
|
// src/overlayCard.ts
|
|
90
|
-
import { StyleSheet as
|
|
182
|
+
import { StyleSheet as StyleSheet5 } from "react-native";
|
|
91
183
|
function getOverlayCardColors(dark) {
|
|
92
184
|
return {
|
|
93
185
|
fg: dark ? "#FFFFFF" : "#000000",
|
|
@@ -96,7 +188,7 @@ function getOverlayCardColors(dark) {
|
|
|
96
188
|
cardBorder: dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"
|
|
97
189
|
};
|
|
98
190
|
}
|
|
99
|
-
var overlayStyles =
|
|
191
|
+
var overlayStyles = StyleSheet5.create({
|
|
100
192
|
card: {
|
|
101
193
|
alignItems: "center",
|
|
102
194
|
borderRadius: 20,
|
|
@@ -118,25 +210,25 @@ var overlayStyles = StyleSheet2.create({
|
|
|
118
210
|
});
|
|
119
211
|
|
|
120
212
|
// src/ConfirmDialog.tsx
|
|
121
|
-
import { jsx as
|
|
213
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
122
214
|
function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
|
|
123
|
-
const { dark, colors } =
|
|
215
|
+
const { dark, colors } = useAutoPaperTheme5();
|
|
124
216
|
if (!visible) return null;
|
|
125
217
|
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
|
|
126
218
|
const accent = destructive ? colors.danger : colors.primary;
|
|
127
219
|
const onAccent = destructive ? colors.onDanger : colors.onPrimary;
|
|
128
220
|
const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
|
|
129
|
-
return /* @__PURE__ */
|
|
130
|
-
/* @__PURE__ */
|
|
131
|
-
/* @__PURE__ */
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
-
showCancel && /* @__PURE__ */
|
|
135
|
-
/* @__PURE__ */
|
|
221
|
+
return /* @__PURE__ */ jsx6(Portal, { children: /* @__PURE__ */ jsx6(View4, { style: [overlayStyles.overlay, styles5.overlay], children: /* @__PURE__ */ jsxs6(View4, { style: [overlayStyles.card, styles5.card, { backgroundColor: cardBg, borderColor: cardBorder }, toRotationStyle(rotation)], children: [
|
|
222
|
+
/* @__PURE__ */ jsx6(Icon2, { source: icon, size: 64, color: accent }),
|
|
223
|
+
/* @__PURE__ */ jsx6(Text5, { variant: "headlineLarge", style: [styles5.title, { color: accent }], children: title }),
|
|
224
|
+
/* @__PURE__ */ jsx6(Text5, { variant: "bodyLarge", style: [styles5.body, { color: fg }], children: message }),
|
|
225
|
+
/* @__PURE__ */ jsxs6(View4, { style: styles5.actions, children: [
|
|
226
|
+
showCancel && /* @__PURE__ */ jsx6(Button, { mode: "outlined", onPress: onCancel, style: styles5.actionButton, children: cancelLabel }),
|
|
227
|
+
/* @__PURE__ */ jsx6(Button, { mode: "contained", onPress: onConfirm, style: showCancel ? styles5.actionButton : styles5.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
|
|
136
228
|
] })
|
|
137
229
|
] }) }) });
|
|
138
230
|
}
|
|
139
|
-
var
|
|
231
|
+
var styles5 = StyleSheet6.create({
|
|
140
232
|
// minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
|
|
141
233
|
// still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
|
|
142
234
|
// on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
|
|
@@ -224,12 +316,12 @@ function useUpdateConfirmBridge() {
|
|
|
224
316
|
}
|
|
225
317
|
|
|
226
318
|
// src/BaseSettingsDialog.tsx
|
|
227
|
-
import { Fragment, jsx as
|
|
319
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
228
320
|
function SettingIcon({ source, color, containerColor }) {
|
|
229
|
-
return /* @__PURE__ */
|
|
321
|
+
return /* @__PURE__ */ jsx7(View5, { style: [styles6.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx7(Icon3, { source, size: 18, color }) });
|
|
230
322
|
}
|
|
231
323
|
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
|
|
232
|
-
const { colors } =
|
|
324
|
+
const { colors } = useAutoPaperTheme6();
|
|
233
325
|
const ambientRotation = useRotation();
|
|
234
326
|
const rotation = rotationOverride ?? ambientRotation;
|
|
235
327
|
const isTouchPrimary = useIsTouchPrimaryDevice();
|
|
@@ -248,32 +340,32 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
248
340
|
});
|
|
249
341
|
const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
|
|
250
342
|
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
251
|
-
const showEdgeGuard =
|
|
252
|
-
const showHaptics =
|
|
343
|
+
const showEdgeGuard = Platform2.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
344
|
+
const showHaptics = Platform2.OS !== "web" && !hideHaptics;
|
|
253
345
|
const showSound = !hideSound;
|
|
254
346
|
const showAppearance = !hideAppearance;
|
|
255
|
-
const showUpdateCheck =
|
|
256
|
-
return /* @__PURE__ */
|
|
257
|
-
/* @__PURE__ */
|
|
258
|
-
/* @__PURE__ */
|
|
259
|
-
/* @__PURE__ */
|
|
260
|
-
/* @__PURE__ */
|
|
261
|
-
showLockOrientation && /* @__PURE__ */
|
|
262
|
-
/* @__PURE__ */
|
|
263
|
-
/* @__PURE__ */
|
|
264
|
-
/* @__PURE__ */
|
|
265
|
-
/* @__PURE__ */
|
|
347
|
+
const showUpdateCheck = Platform2.OS !== "web" && !hideUpdateCheck;
|
|
348
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
349
|
+
/* @__PURE__ */ jsxs7(Dialog, { visible, onDismiss, style: [styles6.dialog, toRotationStyle2(rotation)], children: [
|
|
350
|
+
/* @__PURE__ */ jsx7(Dialog.Title, { children: "Settings" }),
|
|
351
|
+
/* @__PURE__ */ jsx7(Dialog.ScrollArea, { style: styles6.scrollArea, children: /* @__PURE__ */ jsxs7(ScrollView, { contentContainerStyle: styles6.content, showsVerticalScrollIndicator: false, children: [
|
|
352
|
+
/* @__PURE__ */ jsxs7(View5, { style: styles6.toggleGroup, children: [
|
|
353
|
+
showLockOrientation && /* @__PURE__ */ jsx7(TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles6.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ jsxs7(View5, { style: styles6.toggleContent, children: [
|
|
354
|
+
/* @__PURE__ */ jsx7(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
|
|
355
|
+
/* @__PURE__ */ jsxs7(View5, { style: styles6.flexShrink, children: [
|
|
356
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
|
|
357
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
|
|
266
358
|
] })
|
|
267
359
|
] }) }),
|
|
268
|
-
showEdgeGuard && /* @__PURE__ */
|
|
269
|
-
/* @__PURE__ */
|
|
270
|
-
/* @__PURE__ */
|
|
271
|
-
/* @__PURE__ */
|
|
272
|
-
/* @__PURE__ */
|
|
360
|
+
showEdgeGuard && /* @__PURE__ */ jsx7(TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles6.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ jsxs7(View5, { style: styles6.toggleContent, children: [
|
|
361
|
+
/* @__PURE__ */ jsx7(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
|
|
362
|
+
/* @__PURE__ */ jsxs7(View5, { style: styles6.flexShrink, children: [
|
|
363
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
|
|
364
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
|
|
273
365
|
] })
|
|
274
366
|
] }) }),
|
|
275
|
-
(showSound || showHaptics) && /* @__PURE__ */
|
|
276
|
-
showSound && /* @__PURE__ */
|
|
367
|
+
(showSound || showHaptics) && /* @__PURE__ */ jsxs7(View5, { style: styles6.toggleRow, children: [
|
|
368
|
+
showSound && /* @__PURE__ */ jsx7(
|
|
277
369
|
TouchableRipple,
|
|
278
370
|
{
|
|
279
371
|
soundDisabled: true,
|
|
@@ -282,15 +374,15 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
282
374
|
setSoundSettings({ enabled });
|
|
283
375
|
if (enabled) sound.selection?.();
|
|
284
376
|
},
|
|
285
|
-
style:
|
|
377
|
+
style: styles6.toggleButtonInRow,
|
|
286
378
|
accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
|
|
287
|
-
children: /* @__PURE__ */
|
|
288
|
-
/* @__PURE__ */
|
|
289
|
-
/* @__PURE__ */
|
|
379
|
+
children: /* @__PURE__ */ jsxs7(View5, { style: styles6.toggleContent, children: [
|
|
380
|
+
/* @__PURE__ */ jsx7(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
381
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
|
|
290
382
|
] })
|
|
291
383
|
}
|
|
292
384
|
),
|
|
293
|
-
showHaptics && /* @__PURE__ */
|
|
385
|
+
showHaptics && /* @__PURE__ */ jsx7(
|
|
294
386
|
TouchableRipple,
|
|
295
387
|
{
|
|
296
388
|
hapticDisabled: true,
|
|
@@ -299,36 +391,36 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
299
391
|
setHapticSettings({ vibrate });
|
|
300
392
|
if (vibrate) forceHapticFeedback();
|
|
301
393
|
},
|
|
302
|
-
style:
|
|
394
|
+
style: styles6.toggleButtonInRow,
|
|
303
395
|
accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
|
|
304
|
-
children: /* @__PURE__ */
|
|
305
|
-
/* @__PURE__ */
|
|
306
|
-
/* @__PURE__ */
|
|
396
|
+
children: /* @__PURE__ */ jsxs7(View5, { style: styles6.toggleContent, children: [
|
|
397
|
+
/* @__PURE__ */ jsx7(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
398
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
|
|
307
399
|
] })
|
|
308
400
|
}
|
|
309
401
|
)
|
|
310
402
|
] })
|
|
311
403
|
] }),
|
|
312
|
-
showAppearance && /* @__PURE__ */
|
|
313
|
-
/* @__PURE__ */
|
|
314
|
-
/* @__PURE__ */
|
|
404
|
+
showAppearance && /* @__PURE__ */ jsxs7(View5, { style: styles6.section, children: [
|
|
405
|
+
/* @__PURE__ */ jsx7(Text6, { variant: "labelMedium", style: [styles6.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
|
|
406
|
+
/* @__PURE__ */ jsx7(AutoAppearancePicker, { showLabels: false })
|
|
315
407
|
] }),
|
|
316
408
|
children,
|
|
317
|
-
showUpdateCheck && /* @__PURE__ */
|
|
318
|
-
/* @__PURE__ */
|
|
409
|
+
showUpdateCheck && /* @__PURE__ */ jsxs7(View5, { style: styles6.section, children: [
|
|
410
|
+
/* @__PURE__ */ jsxs7(Text6, { variant: "labelSmall", style: [styles6.sectionLabel, { color: colors.onSurfaceVariant }], children: [
|
|
319
411
|
"VERSION ",
|
|
320
412
|
version,
|
|
321
413
|
updateReady ? " \xB7 UPDATE READY" : ""
|
|
322
414
|
] }),
|
|
323
|
-
/* @__PURE__ */
|
|
415
|
+
/* @__PURE__ */ jsx7(Button2, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
|
|
324
416
|
] })
|
|
325
417
|
] }) })
|
|
326
418
|
] }),
|
|
327
|
-
/* @__PURE__ */
|
|
328
|
-
/* @__PURE__ */
|
|
419
|
+
/* @__PURE__ */ jsx7(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) }),
|
|
420
|
+
/* @__PURE__ */ jsx7(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation, onConfirm: () => setInfoMessage(null) })
|
|
329
421
|
] });
|
|
330
422
|
}
|
|
331
|
-
var
|
|
423
|
+
var styles6 = StyleSheet7.create({
|
|
332
424
|
content: {
|
|
333
425
|
gap: 24,
|
|
334
426
|
paddingVertical: 20
|
|
@@ -396,31 +488,31 @@ var styles3 = StyleSheet4.create({
|
|
|
396
488
|
});
|
|
397
489
|
|
|
398
490
|
// src/BaseStatsScreen.tsx
|
|
399
|
-
import { useAutoPaperTheme as
|
|
491
|
+
import { useAutoPaperTheme as useAutoPaperTheme7 } from "@rific/auto-paper";
|
|
400
492
|
import { Button as Button3, IconButton } from "@rific/feedback-press";
|
|
401
493
|
import { useRotation as useRotation2 } from "@tastic/core";
|
|
402
494
|
import { useState as useState3 } from "react";
|
|
403
|
-
import { ScrollView as ScrollView2, StyleSheet as
|
|
404
|
-
import { Text as
|
|
405
|
-
import { jsx as
|
|
495
|
+
import { ScrollView as ScrollView2, StyleSheet as StyleSheet8, View as View6 } from "react-native";
|
|
496
|
+
import { Text as Text7 } from "react-native-paper";
|
|
497
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
406
498
|
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 }) {
|
|
407
|
-
const { dark, colors } =
|
|
499
|
+
const { dark, colors } = useAutoPaperTheme7();
|
|
408
500
|
const ambientRotation = useRotation2();
|
|
409
501
|
const rotation = rotationOverride ?? ambientRotation;
|
|
410
502
|
const [confirmResetVisible, setConfirmResetVisible] = useState3(false);
|
|
411
503
|
const showReset = !!onReset;
|
|
412
504
|
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
413
505
|
const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
|
|
414
|
-
return /* @__PURE__ */
|
|
415
|
-
/* @__PURE__ */
|
|
416
|
-
/* @__PURE__ */
|
|
417
|
-
/* @__PURE__ */
|
|
506
|
+
return /* @__PURE__ */ jsxs8(View6, { style: [styles7.container, { backgroundColor: bg }], children: [
|
|
507
|
+
/* @__PURE__ */ jsxs8(View6, { style: [styles7.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
|
|
508
|
+
/* @__PURE__ */ jsx8(IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
|
|
509
|
+
/* @__PURE__ */ jsx8(Text7, { variant: titleVariant, style: [styles7.title, { color: fg }], children: title })
|
|
418
510
|
] }),
|
|
419
|
-
/* @__PURE__ */
|
|
511
|
+
/* @__PURE__ */ jsxs8(ScrollView2, { style: styles7.scrollView, contentContainerStyle: [styles7.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
|
|
420
512
|
children,
|
|
421
|
-
showReset && /* @__PURE__ */
|
|
513
|
+
showReset && /* @__PURE__ */ jsx8(Button3, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles7.resetButton, children: resetLabel })
|
|
422
514
|
] }),
|
|
423
|
-
/* @__PURE__ */
|
|
515
|
+
/* @__PURE__ */ jsx8(
|
|
424
516
|
ConfirmDialog,
|
|
425
517
|
{
|
|
426
518
|
visible: confirmResetVisible,
|
|
@@ -440,7 +532,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
|
|
|
440
532
|
)
|
|
441
533
|
] });
|
|
442
534
|
}
|
|
443
|
-
var
|
|
535
|
+
var styles7 = StyleSheet8.create({
|
|
444
536
|
container: {
|
|
445
537
|
flex: 1
|
|
446
538
|
},
|
|
@@ -472,18 +564,18 @@ var styles4 = StyleSheet5.create({
|
|
|
472
564
|
|
|
473
565
|
// src/ContentGutter.tsx
|
|
474
566
|
import { computeContentBounds } from "@tastic/core";
|
|
475
|
-
import { StyleSheet as
|
|
476
|
-
import { jsx as
|
|
567
|
+
import { StyleSheet as StyleSheet9, useWindowDimensions, View as View7 } from "react-native";
|
|
568
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
477
569
|
function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
|
|
478
570
|
const { width: windowWidth } = useWindowDimensions();
|
|
479
571
|
const { contentWidth, gutterWidth } = computeContentBounds(windowWidth, maxContentWidth ?? Infinity);
|
|
480
|
-
return /* @__PURE__ */
|
|
481
|
-
/* @__PURE__ */
|
|
482
|
-
/* @__PURE__ */
|
|
483
|
-
/* @__PURE__ */
|
|
572
|
+
return /* @__PURE__ */ jsxs9(View7, { style: [styles8.row, style], children: [
|
|
573
|
+
/* @__PURE__ */ jsx9(View7, { style: [styles8.gutter, { width: gutterWidth }], children: leftGutter }),
|
|
574
|
+
/* @__PURE__ */ jsx9(View7, { style: { width: contentWidth }, children }),
|
|
575
|
+
/* @__PURE__ */ jsx9(View7, { style: [styles8.gutter, { width: gutterWidth }], children: rightGutter })
|
|
484
576
|
] });
|
|
485
577
|
}
|
|
486
|
-
var
|
|
578
|
+
var styles8 = StyleSheet9.create({
|
|
487
579
|
// overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
|
|
488
580
|
// column instead of clipping cleanly at its own real width.
|
|
489
581
|
gutter: {
|
|
@@ -502,38 +594,34 @@ import { Platform as Platform3 } from "react-native";
|
|
|
502
594
|
import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
|
|
503
595
|
import { IconButton as IconButton2, TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
|
|
504
596
|
import { useRotation as useRotation3 } from "@tastic/core";
|
|
505
|
-
import { ScrollView as ScrollView3, StyleSheet as
|
|
506
|
-
import { Icon as Icon4, Text as
|
|
507
|
-
|
|
508
|
-
// src/fonts.ts
|
|
509
|
-
import { Platform as Platform2 } from "react-native";
|
|
510
|
-
var MONO_FONT = Platform2.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
597
|
+
import { ScrollView as ScrollView3, StyleSheet as StyleSheet11, View as View10 } from "react-native";
|
|
598
|
+
import { Icon as Icon4, Text as Text8 } from "react-native-paper";
|
|
511
599
|
|
|
512
600
|
// src/PopoverBody.tsx
|
|
513
|
-
import { StyleSheet as
|
|
514
|
-
import { Fragment as
|
|
601
|
+
import { StyleSheet as StyleSheet10, View as View8 } from "react-native";
|
|
602
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
515
603
|
var CARET_SIZE = 7;
|
|
516
604
|
var CARET_RING_OFFSET = 2;
|
|
517
605
|
var CARET_DIP = 1;
|
|
518
606
|
function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
|
|
519
607
|
if (!visible) return null;
|
|
520
608
|
const above = verticalAlign === "above";
|
|
521
|
-
const alignStyle = align === "left" ?
|
|
522
|
-
const verticalStyle = above ?
|
|
609
|
+
const alignStyle = align === "left" ? styles9.contentLeft : align === "right" ? styles9.contentRight : styles9.contentCenter;
|
|
610
|
+
const verticalStyle = above ? styles9.contentAbove : styles9.contentBelow;
|
|
523
611
|
const ringSize = CARET_SIZE + caretBorderWidth;
|
|
524
612
|
const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
|
|
525
613
|
const caretFill = above ? "borderTopColor" : "borderBottomColor";
|
|
526
614
|
const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
|
|
527
615
|
const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
|
|
528
|
-
return /* @__PURE__ */
|
|
616
|
+
return /* @__PURE__ */ jsxs10(View8, { style: [styles9.content, alignStyle, verticalStyle], children: [
|
|
529
617
|
children,
|
|
530
|
-
caretColor && /* @__PURE__ */
|
|
531
|
-
/* @__PURE__ */
|
|
532
|
-
/* @__PURE__ */
|
|
618
|
+
caretColor && /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
619
|
+
/* @__PURE__ */ jsx10(View8, { style: [styles9.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
|
|
620
|
+
/* @__PURE__ */ jsx10(View8, { style: [styles9.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
|
|
533
621
|
] })
|
|
534
622
|
] });
|
|
535
623
|
}
|
|
536
|
-
var
|
|
624
|
+
var styles9 = StyleSheet10.create({
|
|
537
625
|
caret: {
|
|
538
626
|
borderLeftColor: "transparent",
|
|
539
627
|
borderRightColor: "transparent",
|
|
@@ -576,10 +664,10 @@ var styles6 = StyleSheet7.create({
|
|
|
576
664
|
});
|
|
577
665
|
|
|
578
666
|
// src/TriggerGaugeHost.tsx
|
|
579
|
-
import { jsx as
|
|
667
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
580
668
|
var getTriggerGauge = () => import("./TriggerGauge-2OJOOF6I.mjs").then((mod) => ({ default: mod.TriggerGauge }));
|
|
581
669
|
function TriggerGaugeHost(props) {
|
|
582
|
-
return /* @__PURE__ */
|
|
670
|
+
return /* @__PURE__ */ jsx11(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
|
|
583
671
|
}
|
|
584
672
|
|
|
585
673
|
// src/useAutoAlign.ts
|
|
@@ -631,7 +719,7 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
|
|
|
631
719
|
}
|
|
632
720
|
|
|
633
721
|
// src/SectionedDropdown.tsx
|
|
634
|
-
import { Fragment as
|
|
722
|
+
import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
635
723
|
var MENU_BORDER_WIDTH = 1;
|
|
636
724
|
var TRIGGER_SIZE = 44;
|
|
637
725
|
var MENU_MIN_WIDTH = 200;
|
|
@@ -642,7 +730,7 @@ var MENU_ITEM_HEIGHT = 40;
|
|
|
642
730
|
var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
|
|
643
731
|
var MENU_DIVIDER_HEIGHT = 9;
|
|
644
732
|
var MENU_VERTICAL_PADDING = 12;
|
|
645
|
-
function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, rotation: rotationOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
|
|
733
|
+
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" } }) {
|
|
646
734
|
const ambientRotation = useRotation3();
|
|
647
735
|
const rotation = rotationOverride ?? ambientRotation;
|
|
648
736
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
@@ -656,8 +744,10 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
|
|
|
656
744
|
const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
|
|
657
745
|
return sum + rows + footer + divider;
|
|
658
746
|
}, 0);
|
|
659
|
-
const
|
|
660
|
-
const
|
|
747
|
+
const auto = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight, rotation);
|
|
748
|
+
const placement = alignOverride ?? auto;
|
|
749
|
+
const { maxHeight, measured, triggerRef, verticalAlign } = placement;
|
|
750
|
+
const align = forcedAlign ?? placement.align;
|
|
661
751
|
const onlySection = sections.length === 1 ? sections[0] : null;
|
|
662
752
|
const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
|
|
663
753
|
const triggerIcon = selectedOption?.icon ?? icon;
|
|
@@ -679,17 +769,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
|
|
|
679
769
|
}
|
|
680
770
|
gaugeOffset += section.options.length;
|
|
681
771
|
}
|
|
682
|
-
const anchorStyle = [
|
|
772
|
+
const anchorStyle = [styles10.anchor, open && styles10.anchorOpen];
|
|
683
773
|
const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
|
|
684
774
|
const dividerStyle = { backgroundColor: menuBorderColor };
|
|
685
|
-
return /* @__PURE__ */
|
|
686
|
-
/* @__PURE__ */
|
|
687
|
-
/* @__PURE__ */
|
|
688
|
-
/* @__PURE__ */
|
|
775
|
+
return /* @__PURE__ */ jsxs11(View10, { style: anchorStyle, children: [
|
|
776
|
+
/* @__PURE__ */ jsxs11(View10, { ref: triggerRef, collapsable: false, style: styles10.triggerBox, children: [
|
|
777
|
+
/* @__PURE__ */ jsx12(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
|
|
778
|
+
/* @__PURE__ */ jsx12(IconButton2, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
|
|
689
779
|
] }),
|
|
690
|
-
/* @__PURE__ */
|
|
691
|
-
sectionIndex > 0 && /* @__PURE__ */
|
|
692
|
-
section.kind === "single" ? /* @__PURE__ */
|
|
780
|
+
/* @__PURE__ */ jsx12(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx12(ScrollView3, { style: [styles10.menu, menuStyle], contentContainerStyle: styles10.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs11(View10, { children: [
|
|
781
|
+
sectionIndex > 0 && /* @__PURE__ */ jsx12(View10, { style: [styles10.divider, dividerStyle] }),
|
|
782
|
+
section.kind === "single" ? /* @__PURE__ */ jsx12(
|
|
693
783
|
SingleSection,
|
|
694
784
|
{
|
|
695
785
|
section,
|
|
@@ -702,7 +792,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
|
|
|
702
792
|
if (autoDismiss) host.close();
|
|
703
793
|
}
|
|
704
794
|
}
|
|
705
|
-
) : /* @__PURE__ */
|
|
795
|
+
) : /* @__PURE__ */ jsx12(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
|
|
706
796
|
] }, section.id)) }) })
|
|
707
797
|
] });
|
|
708
798
|
}
|
|
@@ -714,18 +804,18 @@ function SingleSection({
|
|
|
714
804
|
labelFontFamily,
|
|
715
805
|
onSelect
|
|
716
806
|
}) {
|
|
717
|
-
return /* @__PURE__ */
|
|
807
|
+
return /* @__PURE__ */ jsx12(Fragment4, { children: section.options.map((option) => {
|
|
718
808
|
const selected = option.value === section.value;
|
|
719
809
|
const taken = !selected && option.value === section.takenValue;
|
|
720
810
|
const rowColor = selected ? onAccentColor : mutedColor;
|
|
721
|
-
const itemStyle = [
|
|
811
|
+
const itemStyle = [styles10.item, selected && { backgroundColor: accentColor }, taken && styles10.itemTaken];
|
|
722
812
|
const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
|
|
723
813
|
const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
|
|
724
|
-
return /* @__PURE__ */
|
|
725
|
-
option.icon && /* @__PURE__ */
|
|
726
|
-
/* @__PURE__ */
|
|
727
|
-
/* @__PURE__ */
|
|
728
|
-
option.description && /* @__PURE__ */
|
|
814
|
+
return /* @__PURE__ */ jsx12(TouchableRipple2, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs11(View10, { style: styles10.itemRow, children: [
|
|
815
|
+
option.icon && /* @__PURE__ */ jsx12(Icon4, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
|
|
816
|
+
/* @__PURE__ */ jsxs11(View10, { style: styles10.itemLabelColumn, children: [
|
|
817
|
+
/* @__PURE__ */ jsx12(Text8, { variant: "labelLarge", style: labelStyle, children: option.label }),
|
|
818
|
+
option.description && /* @__PURE__ */ jsx12(Text8, { variant: "labelSmall", style: descriptionStyle, children: option.description })
|
|
729
819
|
] })
|
|
730
820
|
] }) }, option.value);
|
|
731
821
|
}) });
|
|
@@ -739,23 +829,23 @@ function MultiSection({
|
|
|
739
829
|
allClearLabels
|
|
740
830
|
}) {
|
|
741
831
|
const allSelected = section.value.length === section.options.length;
|
|
742
|
-
return /* @__PURE__ */
|
|
832
|
+
return /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
743
833
|
section.options.map((option, i) => {
|
|
744
834
|
const selected = section.value.includes(option.value);
|
|
745
835
|
const rowColor = selected ? onAccentColor : mutedColor;
|
|
746
836
|
const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
|
|
747
837
|
const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
|
|
748
|
-
const itemStyle = [
|
|
838
|
+
const itemStyle = [styles10.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
|
|
749
839
|
const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
|
|
750
|
-
return /* @__PURE__ */
|
|
751
|
-
option.icon && /* @__PURE__ */
|
|
752
|
-
/* @__PURE__ */
|
|
840
|
+
return /* @__PURE__ */ jsx12(TouchableRipple2, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs11(View10, { style: styles10.itemRow, children: [
|
|
841
|
+
option.icon && /* @__PURE__ */ jsx12(Icon4, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
|
|
842
|
+
/* @__PURE__ */ jsx12(Text8, { variant: "labelLarge", style: [styles10.itemLabelFlex, labelStyle], children: option.label })
|
|
753
843
|
] }) }, option.value);
|
|
754
844
|
}),
|
|
755
|
-
section.allClear && /* @__PURE__ */
|
|
845
|
+
section.allClear && /* @__PURE__ */ jsx12(TouchableRipple2, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles10.item, children: /* @__PURE__ */ jsx12(Text8, { variant: "labelLarge", style: [styles10.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
|
|
756
846
|
] });
|
|
757
847
|
}
|
|
758
|
-
var
|
|
848
|
+
var styles10 = StyleSheet11.create({
|
|
759
849
|
allClearLabel: {
|
|
760
850
|
fontWeight: "bold",
|
|
761
851
|
textAlign: "center"
|
|
@@ -772,7 +862,7 @@ var styles7 = StyleSheet8.create({
|
|
|
772
862
|
zIndex: 100
|
|
773
863
|
},
|
|
774
864
|
divider: {
|
|
775
|
-
height:
|
|
865
|
+
height: StyleSheet11.hairlineWidth,
|
|
776
866
|
marginVertical: 4
|
|
777
867
|
},
|
|
778
868
|
item: {
|
|
@@ -825,24 +915,24 @@ var styles7 = StyleSheet8.create({
|
|
|
825
915
|
});
|
|
826
916
|
|
|
827
917
|
// src/ControlSchemePicker.tsx
|
|
828
|
-
import { jsx as
|
|
829
|
-
function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, labelFontFamily }) {
|
|
918
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
919
|
+
function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily }) {
|
|
830
920
|
const isTouchPrimary = useIsTouchPrimaryDevice2();
|
|
831
921
|
if (Platform3.OS !== "web" || isTouchPrimary) return null;
|
|
832
|
-
return /* @__PURE__ */
|
|
922
|
+
return /* @__PURE__ */ jsx13(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 });
|
|
833
923
|
}
|
|
834
924
|
|
|
835
925
|
// src/CornerActionButtons.tsx
|
|
836
926
|
import { IconButton as IconButton3 } from "@rific/feedback-press";
|
|
837
|
-
import { StyleSheet as
|
|
838
|
-
import { Fragment as
|
|
927
|
+
import { StyleSheet as StyleSheet12 } from "react-native";
|
|
928
|
+
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
839
929
|
function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
|
|
840
|
-
return /* @__PURE__ */
|
|
841
|
-
/* @__PURE__ */
|
|
842
|
-
/* @__PURE__ */
|
|
930
|
+
return /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
931
|
+
/* @__PURE__ */ jsx14(IconButton3, { icon: backIcon, iconColor: fg, size: 24, style: [styles11.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
|
|
932
|
+
/* @__PURE__ */ jsx14(IconButton3, { icon: "cog", iconColor: fg, size: 24, style: [styles11.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
|
|
843
933
|
] });
|
|
844
934
|
}
|
|
845
|
-
var
|
|
935
|
+
var styles11 = StyleSheet12.create({
|
|
846
936
|
back: {
|
|
847
937
|
position: "absolute"
|
|
848
938
|
},
|
|
@@ -852,22 +942,22 @@ var styles8 = StyleSheet9.create({
|
|
|
852
942
|
});
|
|
853
943
|
|
|
854
944
|
// src/CornerStatusBadges.tsx
|
|
855
|
-
import { StyleSheet as
|
|
945
|
+
import { StyleSheet as StyleSheet13, View as View11 } from "react-native";
|
|
856
946
|
import { Icon as Icon5 } from "react-native-paper";
|
|
857
|
-
import { Fragment as
|
|
947
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
858
948
|
var BADGE_SIZE = 30;
|
|
859
949
|
function StatusBadge({ icon }) {
|
|
860
|
-
return /* @__PURE__ */
|
|
950
|
+
return /* @__PURE__ */ jsx15(View11, { style: styles12.badge, children: icon && /* @__PURE__ */ jsx15(Icon5, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
|
|
861
951
|
}
|
|
862
952
|
function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
|
|
863
953
|
const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
|
|
864
954
|
const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
|
|
865
|
-
return /* @__PURE__ */
|
|
866
|
-
p1 && /* @__PURE__ */
|
|
867
|
-
p2 && /* @__PURE__ */
|
|
955
|
+
return /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
956
|
+
p1 && /* @__PURE__ */ jsx15(View11, { pointerEvents: "none", style: p1OnRightSide ? styles12.bottomRight : styles12.bottomLeft, children: /* @__PURE__ */ jsx15(StatusBadge, { icon: p1.icon }) }),
|
|
957
|
+
p2 && /* @__PURE__ */ jsx15(View11, { pointerEvents: "none", style: p2OnLeftSide ? styles12.topLeft : styles12.topRight, children: /* @__PURE__ */ jsx15(StatusBadge, { icon: p2.icon }) })
|
|
868
958
|
] });
|
|
869
959
|
}
|
|
870
|
-
var
|
|
960
|
+
var styles12 = StyleSheet13.create({
|
|
871
961
|
badge: {
|
|
872
962
|
alignItems: "center",
|
|
873
963
|
backgroundColor: "rgba(0,0,0,0.28)",
|
|
@@ -889,9 +979,9 @@ var styles9 = StyleSheet10.create({
|
|
|
889
979
|
import { defaultColors, getContrastColor } from "@rific/auto-paper";
|
|
890
980
|
import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
|
|
891
981
|
import { clamp, useRotation as useRotation4 } from "@tastic/core";
|
|
892
|
-
import { ScrollView as ScrollView4, StyleSheet as
|
|
893
|
-
import { Icon as Icon6, Text as
|
|
894
|
-
import { jsx as
|
|
982
|
+
import { ScrollView as ScrollView4, StyleSheet as StyleSheet14, useWindowDimensions as useWindowDimensions3, View as View12 } from "react-native";
|
|
983
|
+
import { Icon as Icon6, Text as Text9 } from "react-native-paper";
|
|
984
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
895
985
|
var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
|
|
896
986
|
var DEFAULT_SIZE = 48;
|
|
897
987
|
var SWATCH_SIZE = 28;
|
|
@@ -904,31 +994,37 @@ var SCREEN_MARGIN = 40;
|
|
|
904
994
|
function widthForColumns(columns) {
|
|
905
995
|
return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
|
|
906
996
|
}
|
|
907
|
-
function
|
|
997
|
+
function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
|
|
998
|
+
const autoColumns = clamp(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
|
|
999
|
+
const resolvedColumns = columns ?? autoColumns;
|
|
1000
|
+
const width = widthForColumns(resolvedColumns);
|
|
1001
|
+
const rows = Math.ceil(swatchCount / resolvedColumns);
|
|
1002
|
+
const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
|
|
1003
|
+
return { width, height };
|
|
1004
|
+
}
|
|
1005
|
+
function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
|
|
908
1006
|
const ambientRotation = useRotation4();
|
|
909
1007
|
const rotation = rotationOverride ?? ambientRotation;
|
|
910
1008
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
911
1009
|
const { width: windowWidth } = useWindowDimensions3();
|
|
912
|
-
const
|
|
913
|
-
const resolvedColumns = columns ?? autoColumns;
|
|
914
|
-
const swatchesWidth = widthForColumns(resolvedColumns);
|
|
915
|
-
const swatchRows = Math.ceil(swatches.length / resolvedColumns);
|
|
916
|
-
const swatchesHeight = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * swatchRows + SWATCHES_GAP * (swatchRows - 1);
|
|
1010
|
+
const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
|
|
917
1011
|
const open = host.openId === id;
|
|
918
|
-
const
|
|
919
|
-
const
|
|
1012
|
+
const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
|
|
1013
|
+
const placement = alignOverride ?? auto;
|
|
1014
|
+
const { maxHeight, measured, triggerRef, verticalAlign } = placement;
|
|
1015
|
+
const align = forcedAlign ?? placement.align;
|
|
920
1016
|
const displayFor = previewValue ?? ((hex) => hex);
|
|
921
1017
|
const displayValue = displayFor(value);
|
|
922
1018
|
const contrastColor = getContrastColor(displayValue);
|
|
923
1019
|
const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
|
|
924
|
-
return /* @__PURE__ */
|
|
925
|
-
/* @__PURE__ */
|
|
926
|
-
/* @__PURE__ */
|
|
1020
|
+
return /* @__PURE__ */ jsxs14(View12, { style: [styles13.anchor, open && styles13.anchorOpen], children: [
|
|
1021
|
+
/* @__PURE__ */ jsx16(TouchableRipple3, { onPress: () => host.toggle(id), borderless: true, style: [styles13.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx16(View12, { ref: triggerRef, collapsable: false, style: styles13.triggerMeasure, children: tag ? /* @__PURE__ */ jsx16(Text9, { style: [styles13.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx16(Icon6, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
|
|
1022
|
+
/* @__PURE__ */ jsx16(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx16(ScrollView4, { style: [styles13.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles13.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
|
|
927
1023
|
const selected = swatch.value.toLowerCase() === value.toLowerCase();
|
|
928
1024
|
const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
|
|
929
1025
|
const swappable = taken && allowSwapTaken;
|
|
930
1026
|
const swatchDisplay = displayFor(swatch.value);
|
|
931
|
-
return /* @__PURE__ */
|
|
1027
|
+
return /* @__PURE__ */ jsx16(
|
|
932
1028
|
TouchableRipple3,
|
|
933
1029
|
{
|
|
934
1030
|
disabled: taken && !swappable,
|
|
@@ -937,15 +1033,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
|
|
|
937
1033
|
if (autoDismiss) host.close();
|
|
938
1034
|
},
|
|
939
1035
|
borderless: true,
|
|
940
|
-
style: [
|
|
941
|
-
children: selected ? /* @__PURE__ */
|
|
1036
|
+
style: [styles13.swatch, { backgroundColor: swatchDisplay }, selected && styles13.swatchSelected, taken && !swappable && styles13.swatchTaken],
|
|
1037
|
+
children: selected ? /* @__PURE__ */ jsx16(Icon6, { source: "check", size: 16, color: getContrastColor(swatchDisplay) }) : swappable ? /* @__PURE__ */ jsx16(Icon6, { source: "swap-horizontal", size: 16, color: getContrastColor(swatchDisplay) }) : taken ? /* @__PURE__ */ jsx16(Icon6, { source: "close", size: 16, color: getContrastColor(swatchDisplay) }) : /* @__PURE__ */ jsx16(View12, {})
|
|
942
1038
|
},
|
|
943
1039
|
swatch.value
|
|
944
1040
|
);
|
|
945
1041
|
}) }) })
|
|
946
1042
|
] });
|
|
947
1043
|
}
|
|
948
|
-
var
|
|
1044
|
+
var styles13 = StyleSheet14.create({
|
|
949
1045
|
anchor: {
|
|
950
1046
|
position: "relative"
|
|
951
1047
|
},
|
|
@@ -1019,9 +1115,9 @@ var styles10 = StyleSheet11.create({
|
|
|
1019
1115
|
// src/LabeledDropdown.tsx
|
|
1020
1116
|
import { getContrastColor as getContrastColor2 } from "@rific/auto-paper";
|
|
1021
1117
|
import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
|
|
1022
|
-
import { ScrollView as ScrollView5, StyleSheet as
|
|
1023
|
-
import { Icon as Icon7, Text as
|
|
1024
|
-
import { jsx as
|
|
1118
|
+
import { ScrollView as ScrollView5, StyleSheet as StyleSheet15, View as View13 } from "react-native";
|
|
1119
|
+
import { Icon as Icon7, Text as Text10 } from "react-native-paper";
|
|
1120
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1025
1121
|
var TRIGGER_HEIGHT = 28;
|
|
1026
1122
|
var POPOVER_WIDTH = 180;
|
|
1027
1123
|
var ROW_HEIGHT = 36;
|
|
@@ -1044,22 +1140,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
|
|
|
1044
1140
|
onChange(option.value);
|
|
1045
1141
|
host.close();
|
|
1046
1142
|
};
|
|
1047
|
-
return /* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1049
|
-
/* @__PURE__ */
|
|
1050
|
-
/* @__PURE__ */
|
|
1143
|
+
return /* @__PURE__ */ jsxs15(View13, { style: [styles14.anchor, open && styles14.anchorOpen], children: [
|
|
1144
|
+
/* @__PURE__ */ jsx17(TouchableRipple4, { onPress: () => host.toggle(id), style: styles14.trigger, children: /* @__PURE__ */ jsxs15(View13, { ref: triggerRef, collapsable: false, style: styles14.triggerInner, children: [
|
|
1145
|
+
/* @__PURE__ */ jsx17(Text10, { style: [styles14.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
|
|
1146
|
+
/* @__PURE__ */ jsx17(Icon7, { source: "menu-down", size: 16, color })
|
|
1051
1147
|
] }) }),
|
|
1052
|
-
/* @__PURE__ */
|
|
1148
|
+
/* @__PURE__ */ jsx17(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx17(ScrollView5, { style: [styles14.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles14.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
|
|
1053
1149
|
const isSelected = option.value === value;
|
|
1054
1150
|
const onColor = getContrastColor2(color);
|
|
1055
|
-
return /* @__PURE__ */
|
|
1056
|
-
option.icon && /* @__PURE__ */
|
|
1057
|
-
/* @__PURE__ */
|
|
1151
|
+
return /* @__PURE__ */ jsx17(TouchableRipple4, { onPress: () => handleSelect(option), style: [styles14.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs15(View13, { style: styles14.rowInner, children: [
|
|
1152
|
+
option.icon && /* @__PURE__ */ jsx17(Icon7, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
|
|
1153
|
+
/* @__PURE__ */ jsx17(Text10, { style: [styles14.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
|
|
1058
1154
|
] }) }, option.value);
|
|
1059
1155
|
}) }) })
|
|
1060
1156
|
] });
|
|
1061
1157
|
}
|
|
1062
|
-
var
|
|
1158
|
+
var styles14 = StyleSheet15.create({
|
|
1063
1159
|
anchor: {
|
|
1064
1160
|
position: "relative"
|
|
1065
1161
|
},
|
|
@@ -1116,26 +1212,23 @@ function loadSkiaWeb() {
|
|
|
1116
1212
|
return Promise.resolve();
|
|
1117
1213
|
}
|
|
1118
1214
|
|
|
1119
|
-
// src/
|
|
1120
|
-
import {
|
|
1121
|
-
import {
|
|
1122
|
-
|
|
1123
|
-
if (!active) return null;
|
|
1124
|
-
return /* @__PURE__ */ jsx14(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet13.absoluteFill, style] });
|
|
1125
|
-
}
|
|
1215
|
+
// src/PlayerSetupPanel.tsx
|
|
1216
|
+
import { ProfilePicker } from "@tastic/profile";
|
|
1217
|
+
import { StyleSheet as StyleSheet17, View as View14 } from "react-native";
|
|
1218
|
+
import { Text as Text12 } from "react-native-paper";
|
|
1126
1219
|
|
|
1127
1220
|
// src/ReadyButton.tsx
|
|
1128
1221
|
import { TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
|
|
1129
|
-
import { StyleSheet as
|
|
1130
|
-
import { Text as
|
|
1131
|
-
import { jsx as
|
|
1222
|
+
import { StyleSheet as StyleSheet16 } from "react-native";
|
|
1223
|
+
import { Text as Text11 } from "react-native-paper";
|
|
1224
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1132
1225
|
function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
|
|
1133
|
-
const readyButtonStyle = [
|
|
1226
|
+
const readyButtonStyle = [styles15.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
|
|
1134
1227
|
const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
|
|
1135
1228
|
const labelColorStyle = { color: ready ? "#000000" : color };
|
|
1136
|
-
return /* @__PURE__ */
|
|
1229
|
+
return /* @__PURE__ */ jsx18(TouchableRipple5, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx18(Text11, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
|
|
1137
1230
|
}
|
|
1138
|
-
var
|
|
1231
|
+
var styles15 = StyleSheet16.create({
|
|
1139
1232
|
readyButton: {
|
|
1140
1233
|
alignItems: "center",
|
|
1141
1234
|
borderRadius: 12,
|
|
@@ -1147,22 +1240,97 @@ var styles12 = StyleSheet14.create({
|
|
|
1147
1240
|
}
|
|
1148
1241
|
});
|
|
1149
1242
|
|
|
1243
|
+
// src/usePopoverHost.ts
|
|
1244
|
+
import { useCallback as useCallback3, useState as useState5 } from "react";
|
|
1245
|
+
function usePopoverHost() {
|
|
1246
|
+
const [openId, setOpenId] = useState5(null);
|
|
1247
|
+
const toggle = useCallback3((id) => {
|
|
1248
|
+
setOpenId((prev) => prev === id ? null : id);
|
|
1249
|
+
}, []);
|
|
1250
|
+
const close = useCallback3(() => setOpenId(null), []);
|
|
1251
|
+
return { openId, toggle, close };
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// src/PlayerSetupPanel.tsx
|
|
1255
|
+
import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1256
|
+
function getColorPopoverId(idPrefix) {
|
|
1257
|
+
return `${idPrefix}-color`;
|
|
1258
|
+
}
|
|
1259
|
+
function getCpuDifficultyPopoverId(idPrefix) {
|
|
1260
|
+
return `${idPrefix}-difficulty`;
|
|
1261
|
+
}
|
|
1262
|
+
function PlayerSetupPanel({ idPrefix, host, label, labelFontFamily, color, onColorChange, swatches, takenColor, allowSwapTaken, colorAlignOverride, colorRotation, isHuman, secondPicker, secondPickerId, ready, onToggleReady, dark, showReadyButton = true, profiles, selectedProfileId, takenProfileId, guestLabel, onProfileSelect, onManageProfiles, cpuDifficulty, cpuDifficultyOptions, onCpuDifficultyChange, cpuDifficultyAlignOverride, humanIcon = "face-man", cpuIcon = "robot" }) {
|
|
1263
|
+
const ownHost = usePopoverHost();
|
|
1264
|
+
const popover = host ?? ownHost;
|
|
1265
|
+
const ownPopoverOpen = popover.openId?.startsWith(`${idPrefix}-`) ?? false;
|
|
1266
|
+
const pickerRowPopoverOpen = popover.openId === getColorPopoverId(idPrefix) || secondPickerId !== void 0 && popover.openId === secondPickerId;
|
|
1267
|
+
const showProfilePicker = isHuman && profiles !== void 0 && !!onProfileSelect;
|
|
1268
|
+
const showCpuDifficulty = !isHuman && cpuDifficulty !== void 0 && cpuDifficultyOptions !== void 0 && !!onCpuDifficultyChange;
|
|
1269
|
+
const selectedProfile = profiles?.find((p) => p.id === selectedProfileId) ?? null;
|
|
1270
|
+
return /* @__PURE__ */ jsxs16(View14, { style: [styles16.panel, ownPopoverOpen && styles16.panelOpen], children: [
|
|
1271
|
+
showProfilePicker ? /* @__PURE__ */ jsx19(ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ jsx19(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ jsx19(Text12, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
|
|
1272
|
+
/* @__PURE__ */ jsxs16(View14, { style: [styles16.pickerRow, pickerRowPopoverOpen && styles16.pickerRowOpen], children: [
|
|
1273
|
+
/* @__PURE__ */ jsx19(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 }),
|
|
1274
|
+
secondPicker
|
|
1275
|
+
] }),
|
|
1276
|
+
isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ jsx19(ReadyButton, { color, ready: ready ?? false, onToggleReady })
|
|
1277
|
+
] });
|
|
1278
|
+
}
|
|
1279
|
+
var styles16 = StyleSheet17.create({
|
|
1280
|
+
panel: {
|
|
1281
|
+
alignItems: "center",
|
|
1282
|
+
gap: 12
|
|
1283
|
+
},
|
|
1284
|
+
// See SectionedDropdown's anchorOpen comment — this panel is typically a sibling of another
|
|
1285
|
+
// panel (and/or a shared-controls row), so a popover escaping this panel's bounds needs the panel
|
|
1286
|
+
// itself elevated, not just the popover content, to paint above a later sibling.
|
|
1287
|
+
panelOpen: {
|
|
1288
|
+
zIndex: 100
|
|
1289
|
+
},
|
|
1290
|
+
// Same gap as `panel`'s own vertical rhythm, reused horizontally — the color picker and (when
|
|
1291
|
+
// present) secondPicker sit side by side within this row instead of stacked in the panel's own
|
|
1292
|
+
// column.
|
|
1293
|
+
pickerRow: {
|
|
1294
|
+
alignItems: "center",
|
|
1295
|
+
flexDirection: "row",
|
|
1296
|
+
gap: 12
|
|
1297
|
+
},
|
|
1298
|
+
// A popover is an absolutely-positioned sibling of its own trigger — so a tall one (the color
|
|
1299
|
+
// swatch grid) can extend down far enough to overlap the ReadyButton below, which paints on top of
|
|
1300
|
+
// it by default DOM order since it's a later sibling within `panel`. `panel`'s own panelOpen
|
|
1301
|
+
// elevation only helps this panel paint above OTHER panels (see its own comment) — it does nothing
|
|
1302
|
+
// for stacking *within* this panel, since React Native Web gives each View its own stacking
|
|
1303
|
+
// context. This is what actually fixes that: elevate pickerRow itself above its own later sibling
|
|
1304
|
+
// whenever one of its own popovers is open.
|
|
1305
|
+
pickerRowOpen: {
|
|
1306
|
+
zIndex: 100
|
|
1307
|
+
}
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
// src/PressAwayOverlay.tsx
|
|
1311
|
+
import { Pressable, StyleSheet as StyleSheet18 } from "react-native";
|
|
1312
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
1313
|
+
function PressAwayOverlay({ active, onPress, style }) {
|
|
1314
|
+
if (!active) return null;
|
|
1315
|
+
return /* @__PURE__ */ jsx20(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet18.absoluteFill, style] });
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1150
1318
|
// src/SharedActionBand.tsx
|
|
1151
1319
|
import { IconButton as IconButton4 } from "@rific/feedback-press";
|
|
1152
|
-
import { StyleSheet as
|
|
1153
|
-
import { jsx as
|
|
1320
|
+
import { StyleSheet as StyleSheet19, View as View15 } from "react-native";
|
|
1321
|
+
import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1154
1322
|
function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
|
|
1155
|
-
return /* @__PURE__ */
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
/* @__PURE__ */
|
|
1158
|
-
onRandomize && /* @__PURE__ */
|
|
1159
|
-
onReset && /* @__PURE__ */
|
|
1160
|
-
/* @__PURE__ */
|
|
1323
|
+
return /* @__PURE__ */ jsxs17(View15, { style: [styles17.column, popoverOpen && styles17.columnOpen], children: [
|
|
1324
|
+
/* @__PURE__ */ jsxs17(View15, { style: styles17.actionsRow, children: [
|
|
1325
|
+
/* @__PURE__ */ jsx21(IconButton4, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
|
|
1326
|
+
onRandomize && /* @__PURE__ */ jsx21(IconButton4, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
|
|
1327
|
+
onReset && /* @__PURE__ */ jsx21(IconButton4, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
|
|
1328
|
+
/* @__PURE__ */ jsx21(IconButton4, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
|
|
1161
1329
|
] }),
|
|
1162
1330
|
children
|
|
1163
1331
|
] });
|
|
1164
1332
|
}
|
|
1165
|
-
var
|
|
1333
|
+
var styles17 = StyleSheet19.create({
|
|
1166
1334
|
actionsRow: {
|
|
1167
1335
|
alignItems: "center",
|
|
1168
1336
|
flexDirection: "row",
|
|
@@ -1177,83 +1345,109 @@ var styles13 = StyleSheet15.create({
|
|
|
1177
1345
|
}
|
|
1178
1346
|
});
|
|
1179
1347
|
|
|
1180
|
-
// src/
|
|
1181
|
-
import {
|
|
1182
|
-
import { StyleSheet as
|
|
1183
|
-
import {
|
|
1184
|
-
import { jsx as
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
return /* @__PURE__ */ jsxs13(View13, { style: styles14.row, children: [
|
|
1190
|
-
/* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
|
|
1191
|
-
/* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: [styles14.value, { color: fg }], children: value })
|
|
1192
|
-
] });
|
|
1348
|
+
// src/StaggeredWord.tsx
|
|
1349
|
+
import { useEffect as useEffect2 } from "react";
|
|
1350
|
+
import { StyleSheet as StyleSheet20, View as View16 } from "react-native";
|
|
1351
|
+
import Animated, { Easing, useAnimatedStyle, useSharedValue, withDelay, withTiming } from "react-native-reanimated";
|
|
1352
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
1353
|
+
var STAGGER_MS = 45;
|
|
1354
|
+
var LETTER_DURATION_MS = 320;
|
|
1355
|
+
function getStaggeredWordDuration(letterCount) {
|
|
1356
|
+
return (letterCount - 1) * STAGGER_MS + LETTER_DURATION_MS;
|
|
1193
1357
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
},
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
});
|
|
1204
|
-
|
|
1205
|
-
// src/StatSection.tsx
|
|
1206
|
-
import { useAutoPaperTheme as useAutoPaperTheme6 } from "@rific/auto-paper";
|
|
1207
|
-
import { StyleSheet as StyleSheet17, View as View14 } from "react-native";
|
|
1208
|
-
import { Text as Text10 } from "react-native-paper";
|
|
1209
|
-
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1210
|
-
function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
|
|
1211
|
-
const { dark } = useAutoPaperTheme6();
|
|
1212
|
-
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
1213
|
-
const sectionBg = sectionBgOverride ?? (dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)");
|
|
1214
|
-
return /* @__PURE__ */ jsxs14(View14, { style: [styles15.section, { backgroundColor: sectionBg }], children: [
|
|
1215
|
-
/* @__PURE__ */ jsx18(Text10, { variant: "labelMedium", style: [styles15.label, { color: fg }], children: label }),
|
|
1216
|
-
children
|
|
1217
|
-
] });
|
|
1358
|
+
function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }) {
|
|
1359
|
+
const progress = useSharedValue(reducedMotion ? 1 : 0);
|
|
1360
|
+
useEffect2(() => {
|
|
1361
|
+
if (reducedMotion) return;
|
|
1362
|
+
progress.value = withDelay(index * STAGGER_MS, withTiming(1, { duration: LETTER_DURATION_MS, easing: Easing.out(Easing.back(1.5)) }));
|
|
1363
|
+
}, [reducedMotion]);
|
|
1364
|
+
const style = useAnimatedStyle(() => ({
|
|
1365
|
+
opacity: progress.value,
|
|
1366
|
+
transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
|
|
1367
|
+
}));
|
|
1368
|
+
return /* @__PURE__ */ jsx22(Animated.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
|
|
1218
1369
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
fontWeight: "bold",
|
|
1226
|
-
letterSpacing: 2
|
|
1227
|
-
},
|
|
1228
|
-
section: {
|
|
1229
|
-
borderRadius: 12,
|
|
1230
|
-
gap: 8,
|
|
1231
|
-
padding: 16
|
|
1370
|
+
function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
|
|
1371
|
+
return /* @__PURE__ */ jsx22(View16, { style: [styles18.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ jsx22(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
|
|
1372
|
+
}
|
|
1373
|
+
var styles18 = StyleSheet20.create({
|
|
1374
|
+
row: {
|
|
1375
|
+
flexDirection: "row"
|
|
1232
1376
|
}
|
|
1233
1377
|
});
|
|
1234
1378
|
|
|
1235
1379
|
// src/UpdateDialog.tsx
|
|
1236
1380
|
import { useUpdater as useUpdater2 } from "@rific/updater";
|
|
1237
|
-
import { jsx as
|
|
1381
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
1238
1382
|
function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
|
|
1239
1383
|
const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
|
|
1240
1384
|
useUpdater2({ autoCheck, autoPrompt, onConfirm, onError });
|
|
1241
1385
|
const date = manifest ? new Date(manifest.createdAt) : null;
|
|
1242
|
-
return /* @__PURE__ */
|
|
1386
|
+
return /* @__PURE__ */ jsx23(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) });
|
|
1243
1387
|
}
|
|
1244
1388
|
|
|
1245
|
-
// src/
|
|
1246
|
-
import { useCallback as
|
|
1247
|
-
function
|
|
1248
|
-
const [
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1389
|
+
// src/useQuitConfirmation.ts
|
|
1390
|
+
import { useCallback as useCallback4, useEffect as useEffect3, useRef as useRef3, useState as useState6 } from "react";
|
|
1391
|
+
function useQuitConfirmation(hasProgress, onConfirmedBack) {
|
|
1392
|
+
const [confirmVisible, setConfirmVisible] = useState6(false);
|
|
1393
|
+
const hasProgressRef = useRef3(hasProgress);
|
|
1394
|
+
useEffect3(() => {
|
|
1395
|
+
hasProgressRef.current = hasProgress;
|
|
1396
|
+
});
|
|
1397
|
+
const onConfirmedBackRef = useRef3(onConfirmedBack);
|
|
1398
|
+
useEffect3(() => {
|
|
1399
|
+
onConfirmedBackRef.current = onConfirmedBack;
|
|
1400
|
+
});
|
|
1401
|
+
const requestBack = useCallback4(() => {
|
|
1402
|
+
if (hasProgressRef.current()) setConfirmVisible(true);
|
|
1403
|
+
else onConfirmedBackRef.current();
|
|
1251
1404
|
}, []);
|
|
1252
|
-
const
|
|
1253
|
-
return {
|
|
1405
|
+
const cancelBack = useCallback4(() => setConfirmVisible(false), []);
|
|
1406
|
+
return { confirmVisible, requestBack, cancelBack };
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/useZoneClampedAlign.ts
|
|
1410
|
+
import { useZoneBounds } from "@tastic/split-screen";
|
|
1411
|
+
import { useEffect as useEffect4, useState as useState7 } from "react";
|
|
1412
|
+
import { useWindowDimensions as useWindowDimensions4 } from "react-native";
|
|
1413
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
1414
|
+
var EDGE_MARGIN2 = 12;
|
|
1415
|
+
function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
|
|
1416
|
+
const auto = useAutoAlign(open, contentWidth, contentHeight, rotation);
|
|
1417
|
+
const zone = useZoneBounds();
|
|
1418
|
+
const { height: windowHeight } = useWindowDimensions4();
|
|
1419
|
+
const insets = useSafeAreaInsets();
|
|
1420
|
+
const shouldMeasure = open && auto.measured && zone !== null;
|
|
1421
|
+
const [ownBounds, setOwnBounds] = useState7(null);
|
|
1422
|
+
const [prevShouldMeasure, setPrevShouldMeasure] = useState7(shouldMeasure);
|
|
1423
|
+
if (shouldMeasure !== prevShouldMeasure) {
|
|
1424
|
+
setPrevShouldMeasure(shouldMeasure);
|
|
1425
|
+
setOwnBounds(null);
|
|
1426
|
+
}
|
|
1427
|
+
useEffect4(() => {
|
|
1428
|
+
if (!shouldMeasure) return;
|
|
1429
|
+
auto.triggerRef.current?.measureInWindow((_x, y, _width, height) => {
|
|
1430
|
+
const belowShared = zone.zoneSide === "belowShared";
|
|
1431
|
+
const awayRoom = belowShared ? windowHeight - insets.bottom - (y + height) - EDGE_MARGIN2 : y - insets.top - EDGE_MARGIN2;
|
|
1432
|
+
const towardRoom = belowShared ? y - zone.sharedEdgeY - EDGE_MARGIN2 : zone.sharedEdgeY - (y + height) - EDGE_MARGIN2;
|
|
1433
|
+
const useToward = contentHeight > awayRoom && towardRoom > awayRoom;
|
|
1434
|
+
let awaySide = belowShared ? "below" : "above";
|
|
1435
|
+
let towardSide = belowShared ? "above" : "below";
|
|
1436
|
+
if (zone.rotated) {
|
|
1437
|
+
awaySide = awaySide === "above" ? "below" : "above";
|
|
1438
|
+
towardSide = towardSide === "above" ? "below" : "above";
|
|
1439
|
+
}
|
|
1440
|
+
setOwnBounds({ maxHeight: Math.max(useToward ? towardRoom : awayRoom, 0), verticalAlign: useToward ? towardSide : awaySide });
|
|
1441
|
+
});
|
|
1442
|
+
}, [shouldMeasure, zone, auto.triggerRef, contentHeight, windowHeight, insets.top, insets.bottom]);
|
|
1443
|
+
if (!zone) return auto;
|
|
1444
|
+
if (!ownBounds) return { ...auto, measured: false };
|
|
1445
|
+
return { ...auto, maxHeight: ownBounds.maxHeight, measured: auto.measured, verticalAlign: ownBounds.verticalAlign };
|
|
1254
1446
|
}
|
|
1255
1447
|
export {
|
|
1448
|
+
AchievementCatalogSection,
|
|
1256
1449
|
AchievementRow,
|
|
1450
|
+
ActivityStatSection,
|
|
1257
1451
|
BaseSettingsDialog,
|
|
1258
1452
|
BaseStatsScreen,
|
|
1259
1453
|
ConfirmDialog,
|
|
@@ -1266,20 +1460,28 @@ export {
|
|
|
1266
1460
|
LOCKED_BADGE_COLOR,
|
|
1267
1461
|
LabeledDropdown,
|
|
1268
1462
|
MONO_FONT,
|
|
1463
|
+
PlayerSetupPanel,
|
|
1269
1464
|
PopoverBody,
|
|
1270
1465
|
PressAwayOverlay,
|
|
1271
1466
|
ReadyButton,
|
|
1272
1467
|
SectionedDropdown,
|
|
1273
1468
|
SharedActionBand,
|
|
1274
1469
|
SkiaGate,
|
|
1470
|
+
StaggeredWord,
|
|
1275
1471
|
StatRow,
|
|
1276
1472
|
StatSection,
|
|
1277
1473
|
TriggerGaugeHost,
|
|
1278
1474
|
UpdateDialog,
|
|
1475
|
+
getColorPopoverId,
|
|
1476
|
+
getCpuDifficultyPopoverId,
|
|
1477
|
+
getInlineColorPickerContentSize,
|
|
1279
1478
|
getLabeledDropdownContentHeight,
|
|
1280
1479
|
getOverlayCardColors,
|
|
1480
|
+
getStaggeredWordDuration,
|
|
1281
1481
|
loadSkiaWeb,
|
|
1282
1482
|
overlayStyles,
|
|
1283
1483
|
useAutoAlign,
|
|
1284
|
-
usePopoverHost
|
|
1484
|
+
usePopoverHost,
|
|
1485
|
+
useQuitConfirmation,
|
|
1486
|
+
useZoneClampedAlign
|
|
1285
1487
|
};
|