@tastic/hud 0.12.0 → 0.13.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.js CHANGED
@@ -130,21 +130,21 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
130
130
  height: canvasSize,
131
131
  width: canvasSize
132
132
  };
133
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native12.View, { style: [styles10.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
135
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
133
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native13.View, { style: [styles11.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
134
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
135
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
136
136
  ] }) });
137
137
  }
138
- var import_react_native_skia, import_core5, import_react6, import_react_native12, import_react_native_reanimated, import_jsx_runtime12, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles10;
138
+ var import_react_native_skia, import_core5, import_react6, import_react_native13, import_react_native_reanimated, import_jsx_runtime13, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles11;
139
139
  var init_TriggerGauge = __esm({
140
140
  "src/TriggerGauge.tsx"() {
141
141
  "use strict";
142
142
  import_react_native_skia = require("@shopify/react-native-skia");
143
143
  import_core5 = require("@tastic/core");
144
144
  import_react6 = require("react");
145
- import_react_native12 = require("react-native");
145
+ import_react_native13 = require("react-native");
146
146
  import_react_native_reanimated = require("react-native-reanimated");
147
- import_jsx_runtime12 = require("react/jsx-runtime");
147
+ import_jsx_runtime13 = require("react/jsx-runtime");
148
148
  UNLIT_THICKNESS = 3;
149
149
  LIT_THICKNESS = 7;
150
150
  DASH_GAP_PX = 9;
@@ -154,7 +154,7 @@ var init_TriggerGauge = __esm({
154
154
  MOUNT_DURATION_MS = 450;
155
155
  MOUNT_STAGGER_MS = 40;
156
156
  SELECTION_TRANSITION_DURATION_MS = 260;
157
- styles10 = import_react_native12.StyleSheet.create({
157
+ styles11 = import_react_native13.StyleSheet.create({
158
158
  container: {
159
159
  alignItems: "center",
160
160
  justifyContent: "center",
@@ -169,6 +169,7 @@ var index_exports = {};
169
169
  __export(index_exports, {
170
170
  AchievementCatalogSection: () => AchievementCatalogSection,
171
171
  AchievementRow: () => AchievementRow,
172
+ AchievementUnlockList: () => AchievementUnlockList,
172
173
  ActivityStatSection: () => ActivityStatSection,
173
174
  BaseSettingsDialog: () => BaseSettingsDialog,
174
175
  BaseStatsScreen: () => BaseStatsScreen,
@@ -201,6 +202,7 @@ __export(index_exports, {
201
202
  getOverlayCardColors: () => getOverlayCardColors,
202
203
  getStaggeredWordDuration: () => getStaggeredWordDuration,
203
204
  loadSkiaWeb: () => loadSkiaWeb,
205
+ overlayActionStyles: () => overlayActionStyles,
204
206
  overlayStyles: () => overlayStyles,
205
207
  useAutoAlign: () => useAutoAlign,
206
208
  usePopoverHost: () => usePopoverHost,
@@ -304,21 +306,65 @@ var styles2 = import_react_native3.StyleSheet.create({
304
306
  }
305
307
  });
306
308
 
307
- // src/StatRow.tsx
309
+ // src/AchievementUnlockList.tsx
308
310
  var import_auto_paper3 = require("@rific/auto-paper");
311
+ var import_profile = require("@tastic/profile");
309
312
  var import_react_native4 = require("react-native");
310
313
  var import_react_native_paper3 = require("react-native-paper");
311
314
  var import_jsx_runtime3 = require("react/jsx-runtime");
312
- function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
315
+ var AVATAR_SIZE = 18;
316
+ function AchievementUnlockList({ unlocks, seats, owners, tierColors, fg: fgOverride, style }) {
313
317
  const { dark } = (0, import_auto_paper3.useAutoPaperTheme)();
314
318
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
319
+ const rows = seats.flatMap((seat) => (unlocks[seat] ?? []).map((achievement) => ({ seat, achievement })));
320
+ if (rows.length === 0) return null;
321
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.list, style], children: rows.map(({ seat, achievement }) => {
322
+ const owner = owners[seat];
323
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.row, children: [
324
+ owner.profile ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_profile.ProfileChip, { profile: owner.profile, size: AVATAR_SIZE }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.circle, { backgroundColor: owner.color }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Icon, { source: "account", size: 10, color: (0, import_auto_paper3.getContrastColor)(owner.color) }) }),
325
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.circle, { backgroundColor: tierColors[achievement.tier] }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Icon, { source: achievement.icon, size: 12, color: "#000000" }) }),
326
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { style: [styles3.label, { color: fg }], numberOfLines: 1, children: achievement.title })
327
+ ] }, `${seat}-${achievement.id}`);
328
+ }) });
329
+ }
330
+ var styles3 = import_react_native4.StyleSheet.create({
331
+ circle: {
332
+ alignItems: "center",
333
+ borderRadius: AVATAR_SIZE / 2,
334
+ height: AVATAR_SIZE,
335
+ justifyContent: "center",
336
+ width: AVATAR_SIZE
337
+ },
338
+ label: {
339
+ flexShrink: 1,
340
+ fontSize: 12,
341
+ fontWeight: "700"
342
+ },
343
+ list: {
344
+ gap: 6
345
+ },
346
+ row: {
347
+ alignItems: "center",
348
+ flexDirection: "row",
349
+ gap: 6
350
+ }
351
+ });
352
+
353
+ // src/StatRow.tsx
354
+ var import_auto_paper4 = require("@rific/auto-paper");
355
+ var import_react_native5 = require("react-native");
356
+ var import_react_native_paper4 = require("react-native-paper");
357
+ var import_jsx_runtime4 = require("react/jsx-runtime");
358
+ function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
359
+ const { dark } = (0, import_auto_paper4.useAutoPaperTheme)();
360
+ const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
315
361
  const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
316
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.row, children: [
317
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
318
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyMedium", style: [styles3.value, { color: fg }], children: value })
362
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: styles4.row, children: [
363
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Text, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
364
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Text, { variant: "bodyMedium", style: [styles4.value, { color: fg }], children: value })
319
365
  ] });
320
366
  }
321
- var styles3 = import_react_native4.StyleSheet.create({
367
+ var styles4 = import_react_native5.StyleSheet.create({
322
368
  row: {
323
369
  alignItems: "center",
324
370
  flexDirection: "row",
@@ -330,20 +376,20 @@ var styles3 = import_react_native4.StyleSheet.create({
330
376
  });
331
377
 
332
378
  // src/StatSection.tsx
333
- var import_auto_paper4 = require("@rific/auto-paper");
334
- var import_react_native5 = require("react-native");
335
- var import_react_native_paper4 = require("react-native-paper");
336
- var import_jsx_runtime4 = require("react/jsx-runtime");
379
+ var import_auto_paper5 = require("@rific/auto-paper");
380
+ var import_react_native6 = require("react-native");
381
+ var import_react_native_paper5 = require("react-native-paper");
382
+ var import_jsx_runtime5 = require("react/jsx-runtime");
337
383
  function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
338
- const { dark } = (0, import_auto_paper4.useAutoPaperTheme)();
384
+ const { dark } = (0, import_auto_paper5.useAutoPaperTheme)();
339
385
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
340
386
  const sectionBg = sectionBgOverride ?? (dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)");
341
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: [styles4.section, { backgroundColor: sectionBg }], children: [
342
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Text, { variant: "labelMedium", style: [styles4.label, { color: fg }], children: label }),
387
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: [styles5.section, { backgroundColor: sectionBg }], children: [
388
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper5.Text, { variant: "labelMedium", style: [styles5.label, { color: fg }], children: label }),
343
389
  children
344
390
  ] });
345
391
  }
346
- var styles4 = import_react_native5.StyleSheet.create({
392
+ var styles5 = import_react_native6.StyleSheet.create({
347
393
  // Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
348
394
  // same visual weight as StatRow's own row labels below it (both used the identical muted color;
349
395
  // letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
@@ -360,33 +406,33 @@ var styles4 = import_react_native5.StyleSheet.create({
360
406
  });
361
407
 
362
408
  // src/ActivityStatSection.tsx
363
- var import_jsx_runtime5 = require("react/jsx-runtime");
409
+ var import_jsx_runtime6 = require("react/jsx-runtime");
364
410
  function ActivityStatSection({ stats }) {
365
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(StatSection, { label: "ACTIVITY", children: [
366
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Days Played", value: String(stats.distinctDaysPlayed) }),
367
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Day Streak", value: String(stats.currentDayStreak) }),
368
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatRow, { label: "Best Day Streak", value: String(stats.bestDayStreak) })
411
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(StatSection, { label: "ACTIVITY", children: [
412
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRow, { label: "Days Played", value: String(stats.distinctDaysPlayed) }),
413
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRow, { label: "Day Streak", value: String(stats.currentDayStreak) }),
414
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(StatRow, { label: "Best Day Streak", value: String(stats.bestDayStreak) })
369
415
  ] });
370
416
  }
371
417
 
372
418
  // src/BaseSettingsDialog.tsx
373
- var import_auto_paper6 = require("@rific/auto-paper");
419
+ var import_auto_paper7 = require("@rific/auto-paper");
374
420
  var import_feedback_press2 = require("@rific/feedback-press");
375
421
  var import_updater = require("@rific/updater");
376
422
  var import_core2 = require("@tastic/core");
377
423
  var import_react3 = require("react");
378
- var import_react_native8 = require("react-native");
379
- var import_react_native_paper6 = require("react-native-paper");
424
+ var import_react_native9 = require("react-native");
425
+ var import_react_native_paper7 = require("react-native-paper");
380
426
 
381
427
  // src/ConfirmDialog.tsx
382
- var import_auto_paper5 = require("@rific/auto-paper");
428
+ var import_auto_paper6 = require("@rific/auto-paper");
383
429
  var import_feedback_press = require("@rific/feedback-press");
384
430
  var import_core = require("@tastic/core");
385
- var import_react_native7 = require("react-native");
386
- var import_react_native_paper5 = require("react-native-paper");
431
+ var import_react_native8 = require("react-native");
432
+ var import_react_native_paper6 = require("react-native-paper");
387
433
 
388
434
  // src/overlayCard.ts
389
- var import_react_native6 = require("react-native");
435
+ var import_react_native7 = require("react-native");
390
436
  function getOverlayCardColors(dark) {
391
437
  return {
392
438
  fg: dark ? "#FFFFFF" : "#000000",
@@ -395,7 +441,7 @@ function getOverlayCardColors(dark) {
395
441
  cardBorder: dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"
396
442
  };
397
443
  }
398
- var overlayStyles = import_react_native6.StyleSheet.create({
444
+ var overlayStyles = import_react_native7.StyleSheet.create({
399
445
  card: {
400
446
  alignItems: "center",
401
447
  borderRadius: 20,
@@ -415,27 +461,7 @@ var overlayStyles = import_react_native6.StyleSheet.create({
415
461
  top: 0
416
462
  }
417
463
  });
418
-
419
- // src/ConfirmDialog.tsx
420
- var import_jsx_runtime6 = require("react/jsx-runtime");
421
- function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
422
- const { dark, colors } = (0, import_auto_paper5.useAutoPaperTheme)();
423
- if (!visible) return null;
424
- const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
425
- const accent = destructive ? colors.danger : colors.primary;
426
- const onAccent = destructive ? colors.onDanger : colors.onPrimary;
427
- const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
428
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: [overlayStyles.overlay, styles5.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: [overlayStyles.card, styles5.card, { backgroundColor: cardBg, borderColor: cardBorder }, (0, import_core.toRotationStyle)(rotation)], children: [
429
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Icon, { source: icon, size: 64, color: accent }),
430
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Text, { variant: "headlineLarge", style: [styles5.title, { color: accent }], children: title }),
431
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Text, { variant: "bodyLarge", style: [styles5.body, { color: fg }], children: message }),
432
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: styles5.actions, children: [
433
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: styles5.actionButton, children: cancelLabel }),
434
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? styles5.actionButton : styles5.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
435
- ] })
436
- ] }) }) });
437
- }
438
- var styles5 = import_react_native7.StyleSheet.create({
464
+ var overlayActionStyles = import_react_native7.StyleSheet.create({
439
465
  // minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
440
466
  // still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
441
467
  // on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
@@ -454,8 +480,8 @@ var styles5 = import_react_native7.StyleSheet.create({
454
480
  // hardcodes numberOfLines={1} on its label with no override, so a button squeezed under its
455
481
  // label's natural width silently ellipsizes ("Cancel" -> "Can...") instead of wrapping - assumed
456
482
  // fixable by just giving the row more width, until confirmed live that these two-word labels
457
- // (Cancel/Reset/New Game) can still lose the truncation fight even with the extra room card's own
458
- // width fix below provides, on a narrow enough screen.
483
+ // (Cancel/Reset/New Game) can still lose the truncation fight even with the extra room ConfirmDialog's own
484
+ // card width fix provides, on a narrow enough screen.
459
485
  actionButton: {
460
486
  flexGrow: 1,
461
487
  minWidth: 128
@@ -474,7 +500,29 @@ var styles5 = import_react_native7.StyleSheet.create({
474
500
  gap: 12,
475
501
  justifyContent: "center",
476
502
  width: "100%"
477
- },
503
+ }
504
+ });
505
+
506
+ // src/ConfirmDialog.tsx
507
+ var import_jsx_runtime7 = require("react/jsx-runtime");
508
+ function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
509
+ const { dark, colors } = (0, import_auto_paper6.useAutoPaperTheme)();
510
+ if (!visible) return null;
511
+ const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
512
+ const accent = destructive ? colors.danger : colors.primary;
513
+ const onAccent = destructive ? colors.onDanger : colors.onPrimary;
514
+ const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
515
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [overlayStyles.overlay, styles6.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: [overlayStyles.card, styles6.card, { backgroundColor: cardBg, borderColor: cardBorder }, (0, import_core.toRotationStyle)(rotation)], children: [
516
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Icon, { source: icon, size: 64, color: accent }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "headlineLarge", style: [styles6.title, { color: accent }], children: title }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: [styles6.body, { color: fg }], children: message }),
519
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: overlayActionStyles.actions, children: [
520
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
521
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
522
+ ] })
523
+ ] }) }) });
524
+ }
525
+ var styles6 = import_react_native8.StyleSheet.create({
478
526
  body: {
479
527
  textAlign: "center"
480
528
  },
@@ -523,12 +571,12 @@ function useUpdateConfirmBridge() {
523
571
  }
524
572
 
525
573
  // src/BaseSettingsDialog.tsx
526
- var import_jsx_runtime7 = require("react/jsx-runtime");
574
+ var import_jsx_runtime8 = require("react/jsx-runtime");
527
575
  function SettingIcon({ source, color, containerColor }) {
528
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [styles6.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Icon, { source, size: 18, color }) });
576
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Icon, { source, size: 18, color }) });
529
577
  }
530
- function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
531
- const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
578
+ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
579
+ const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
532
580
  const ambientRotation = (0, import_core2.useRotation)();
533
581
  const rotation = rotationOverride ?? ambientRotation;
534
582
  const isTouchPrimary = (0, import_core2.useIsTouchPrimaryDevice)();
@@ -547,32 +595,32 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
547
595
  });
548
596
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
549
597
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
550
- const showEdgeGuard = import_react_native8.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
551
- const showHaptics = import_react_native8.Platform.OS !== "web" && !hideHaptics;
598
+ const showEdgeGuard = import_react_native9.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
599
+ const showHaptics = import_react_native9.Platform.OS !== "web" && !hideHaptics;
552
600
  const showSound = !hideSound;
553
601
  const showAppearance = !hideAppearance;
554
- const showUpdateCheck = import_react_native8.Platform.OS !== "web" && !hideUpdateCheck;
555
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
556
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_auto_paper6.Dialog, { visible, onDismiss, style: [styles6.dialog, (0, import_core2.toRotationStyle)(rotation)], children: [
557
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_auto_paper6.Dialog.Title, { children: "Settings" }),
558
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_auto_paper6.Dialog.ScrollArea, { style: styles6.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.ScrollView, { contentContainerStyle: styles6.content, showsVerticalScrollIndicator: false, children: [
559
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.toggleGroup, children: [
560
- showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles6.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.toggleContent, children: [
561
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
562
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.flexShrink, children: [
563
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
564
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
602
+ const showUpdateCheck = import_react_native9.Platform.OS !== "web" && !hideUpdateCheck;
603
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
604
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: [styles7.dialog, (0, import_core2.toRotationStyle)(rotation)], children: [
605
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
606
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.Dialog.ScrollArea, { style: styles7.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.ScrollView, { contentContainerStyle: styles7.content, showsVerticalScrollIndicator: false, children: [
607
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleGroup, children: [
608
+ showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles7.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
610
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
611
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
612
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
565
613
  ] })
566
614
  ] }) }),
567
- showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles6.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.toggleContent, children: [
568
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
569
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.flexShrink, children: [
570
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
571
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
615
+ showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles7.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
616
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
617
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
618
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
619
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
572
620
  ] })
573
621
  ] }) }),
574
- (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.toggleRow, children: [
575
- showSound && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
622
+ (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleRow, children: [
623
+ showSound && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
576
624
  import_feedback_press2.TouchableRipple,
577
625
  {
578
626
  soundDisabled: true,
@@ -581,15 +629,15 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
581
629
  setSoundSettings({ enabled });
582
630
  if (enabled) sound.selection?.();
583
631
  },
584
- style: styles6.toggleButtonInRow,
632
+ style: styles7.toggleButtonInRow,
585
633
  accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
586
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.toggleContent, children: [
587
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
588
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
634
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
635
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
636
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
589
637
  ] })
590
638
  }
591
639
  ),
592
- showHaptics && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
640
+ showHaptics && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
593
641
  import_feedback_press2.TouchableRipple,
594
642
  {
595
643
  hapticDisabled: true,
@@ -598,36 +646,54 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
598
646
  setHapticSettings({ vibrate });
599
647
  if (vibrate) forceHapticFeedback();
600
648
  },
601
- style: styles6.toggleButtonInRow,
649
+ style: styles7.toggleButtonInRow,
602
650
  accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
603
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.toggleContent, children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
605
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
651
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
652
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
653
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
606
654
  ] })
607
655
  }
608
656
  )
609
- ] })
657
+ ] }),
658
+ onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
659
+ import_feedback_press2.TouchableRipple,
660
+ {
661
+ onPress: () => {
662
+ onDismiss();
663
+ onShowHowToPlay();
664
+ },
665
+ style: styles7.toggleButton,
666
+ accessibilityLabel: "How to Play",
667
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.toggleContent, children: [
668
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
669
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.flexShrink, children: [
670
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
671
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
672
+ ] })
673
+ ] })
674
+ }
675
+ )
610
676
  ] }),
611
- showAppearance && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.section, children: [
612
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper6.Text, { variant: "labelMedium", style: [styles6.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
613
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_auto_paper6.AutoAppearancePicker, { showLabels: false })
677
+ showAppearance && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.section, children: [
678
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: "labelMedium", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_auto_paper7.AutoAppearancePicker, { showLabels: false })
614
680
  ] }),
615
681
  children,
616
- showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles6.section, children: [
617
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native_paper6.Text, { variant: "labelSmall", style: [styles6.sectionLabel, { color: colors.onSurfaceVariant }], children: [
682
+ showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: styles7.section, children: [
683
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_paper7.Text, { variant: "labelSmall", style: [styles7.sectionLabel, { color: colors.onSurfaceVariant }], children: [
618
684
  "VERSION ",
619
685
  version,
620
686
  updateReady ? " \xB7 UPDATE READY" : ""
621
687
  ] }),
622
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
688
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
623
689
  ] })
624
690
  ] }) })
625
691
  ] }),
626
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
627
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation, onConfirm: () => setInfoMessage(null) })
692
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
693
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation, onConfirm: () => setInfoMessage(null) })
628
694
  ] });
629
695
  }
630
- var styles6 = import_react_native8.StyleSheet.create({
696
+ var styles7 = import_react_native9.StyleSheet.create({
631
697
  content: {
632
698
  gap: 24,
633
699
  paddingVertical: 20
@@ -695,31 +761,31 @@ var styles6 = import_react_native8.StyleSheet.create({
695
761
  });
696
762
 
697
763
  // src/BaseStatsScreen.tsx
698
- var import_auto_paper7 = require("@rific/auto-paper");
764
+ var import_auto_paper8 = require("@rific/auto-paper");
699
765
  var import_feedback_press3 = require("@rific/feedback-press");
700
766
  var import_core3 = require("@tastic/core");
701
767
  var import_react4 = require("react");
702
- var import_react_native9 = require("react-native");
703
- var import_react_native_paper7 = require("react-native-paper");
704
- var import_jsx_runtime8 = require("react/jsx-runtime");
768
+ var import_react_native10 = require("react-native");
769
+ var import_react_native_paper8 = require("react-native-paper");
770
+ var import_jsx_runtime9 = require("react/jsx-runtime");
705
771
  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 }) {
706
- const { dark, colors } = (0, import_auto_paper7.useAutoPaperTheme)();
772
+ const { dark, colors } = (0, import_auto_paper8.useAutoPaperTheme)();
707
773
  const ambientRotation = (0, import_core3.useRotation)();
708
774
  const rotation = rotationOverride ?? ambientRotation;
709
775
  const [confirmResetVisible, setConfirmResetVisible] = (0, import_react4.useState)(false);
710
776
  const showReset = !!onReset;
711
777
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
712
778
  const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
713
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: [styles7.container, { backgroundColor: bg }], children: [
714
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.View, { style: [styles7.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
715
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
716
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper7.Text, { variant: titleVariant, style: [styles7.title, { color: fg }], children: title })
779
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.container, { backgroundColor: bg }], children: [
780
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
781
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
782
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: titleVariant, style: [styles8.title, { color: fg }], children: title })
717
783
  ] }),
718
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native9.ScrollView, { style: styles7.scrollView, contentContainerStyle: [styles7.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
784
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { style: styles8.scrollView, contentContainerStyle: [styles8.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
719
785
  children,
720
- showReset && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles7.resetButton, children: resetLabel })
786
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles8.resetButton, children: resetLabel })
721
787
  ] }),
722
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
788
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
723
789
  ConfirmDialog,
724
790
  {
725
791
  visible: confirmResetVisible,
@@ -739,7 +805,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
739
805
  )
740
806
  ] });
741
807
  }
742
- var styles7 = import_react_native9.StyleSheet.create({
808
+ var styles8 = import_react_native10.StyleSheet.create({
743
809
  container: {
744
810
  flex: 1
745
811
  },
@@ -771,18 +837,18 @@ var styles7 = import_react_native9.StyleSheet.create({
771
837
 
772
838
  // src/ContentGutter.tsx
773
839
  var import_core4 = require("@tastic/core");
774
- var import_react_native10 = require("react-native");
775
- var import_jsx_runtime9 = require("react/jsx-runtime");
840
+ var import_react_native11 = require("react-native");
841
+ var import_jsx_runtime10 = require("react/jsx-runtime");
776
842
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
777
- const { width: windowWidth } = (0, import_react_native10.useWindowDimensions)();
843
+ const { width: windowWidth } = (0, import_core4.useRotatedWindowDimensions)();
778
844
  const { contentWidth, gutterWidth } = (0, import_core4.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
779
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: [styles8.row, style], children: [
780
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.gutter, { width: gutterWidth }], children: leftGutter }),
781
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: { width: contentWidth }, children }),
782
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.gutter, { width: gutterWidth }], children: rightGutter })
845
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.row, style], children: [
846
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.gutter, { width: gutterWidth }], children: leftGutter }),
847
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: { width: contentWidth }, children }),
848
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.gutter, { width: gutterWidth }], children: rightGutter })
783
849
  ] });
784
850
  }
785
- var styles8 = import_react_native10.StyleSheet.create({
851
+ var styles9 = import_react_native11.StyleSheet.create({
786
852
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
787
853
  // column instead of clipping cleanly at its own real width.
788
854
  gutter: {
@@ -795,40 +861,40 @@ var styles8 = import_react_native10.StyleSheet.create({
795
861
 
796
862
  // src/ControlSchemePicker.tsx
797
863
  var import_core7 = require("@tastic/core");
798
- var import_react_native15 = require("react-native");
864
+ var import_react_native16 = require("react-native");
799
865
 
800
866
  // src/SectionedDropdown.tsx
801
- var import_auto_paper8 = require("@rific/auto-paper");
867
+ var import_auto_paper9 = require("@rific/auto-paper");
802
868
  var import_feedback_press4 = require("@rific/feedback-press");
803
869
  var import_core6 = require("@tastic/core");
804
- var import_react_native14 = require("react-native");
805
- var import_react_native_paper8 = require("react-native-paper");
870
+ var import_react_native15 = require("react-native");
871
+ var import_react_native_paper9 = require("react-native-paper");
806
872
 
807
873
  // src/PopoverBody.tsx
808
- var import_react_native11 = require("react-native");
809
- var import_jsx_runtime10 = require("react/jsx-runtime");
874
+ var import_react_native12 = require("react-native");
875
+ var import_jsx_runtime11 = require("react/jsx-runtime");
810
876
  var CARET_SIZE = 7;
811
877
  var CARET_RING_OFFSET = 2;
812
878
  var CARET_DIP = 1;
813
879
  function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
814
880
  if (!visible) return null;
815
881
  const above = verticalAlign === "above";
816
- const alignStyle = align === "left" ? styles9.contentLeft : align === "right" ? styles9.contentRight : styles9.contentCenter;
817
- const verticalStyle = above ? styles9.contentAbove : styles9.contentBelow;
882
+ const alignStyle = align === "left" ? styles10.contentLeft : align === "right" ? styles10.contentRight : styles10.contentCenter;
883
+ const verticalStyle = above ? styles10.contentAbove : styles10.contentBelow;
818
884
  const ringSize = CARET_SIZE + caretBorderWidth;
819
885
  const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
820
886
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
821
887
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
822
888
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
823
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.content, alignStyle, verticalStyle], children: [
889
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.content, alignStyle, verticalStyle], children: [
824
890
  children,
825
- caretColor && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
826
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
827
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles9.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
891
+ caretColor && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
893
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
828
894
  ] })
829
895
  ] });
830
896
  }
831
- var styles9 = import_react_native11.StyleSheet.create({
897
+ var styles10 = import_react_native12.StyleSheet.create({
832
898
  caret: {
833
899
  borderLeftColor: "transparent",
834
900
  borderRightColor: "transparent",
@@ -872,7 +938,7 @@ var styles9 = import_react_native11.StyleSheet.create({
872
938
 
873
939
  // src/SkiaGate.tsx
874
940
  var import_react5 = require("react");
875
- var import_jsx_runtime11 = require("react/jsx-runtime");
941
+ var import_jsx_runtime12 = require("react/jsx-runtime");
876
942
  function SkiaGate({ getComponent, componentProps, fallback = null }) {
877
943
  const [Component, setComponent] = (0, import_react5.useState)(null);
878
944
  (0, import_react5.useEffect)(() => {
@@ -885,19 +951,19 @@ function SkiaGate({ getComponent, componentProps, fallback = null }) {
885
951
  };
886
952
  }, [getComponent]);
887
953
  if (!Component) return fallback;
888
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Component, { ...componentProps });
954
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Component, { ...componentProps });
889
955
  }
890
956
 
891
957
  // src/TriggerGaugeHost.tsx
892
- var import_jsx_runtime13 = require("react/jsx-runtime");
958
+ var import_jsx_runtime14 = require("react/jsx-runtime");
893
959
  var getTriggerGauge = () => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((mod) => ({ default: mod.TriggerGauge }));
894
960
  function TriggerGaugeHost(props) {
895
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
961
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
896
962
  }
897
963
 
898
964
  // src/useAutoAlign.ts
899
965
  var import_react7 = require("react");
900
- var import_react_native13 = require("react-native");
966
+ var import_react_native14 = require("react-native");
901
967
  var EDGE_MARGIN = 12;
902
968
  function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
903
969
  if (rotation === 0) return { x, y, width, height };
@@ -910,7 +976,7 @@ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
910
976
  }
911
977
  function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
912
978
  const triggerRef = (0, import_react7.useRef)(null);
913
- const { width: windowWidth, height: windowHeight } = (0, import_react_native13.useWindowDimensions)();
979
+ const { width: windowWidth, height: windowHeight } = (0, import_react_native14.useWindowDimensions)();
914
980
  const [align, setAlign] = (0, import_react7.useState)("center");
915
981
  const [verticalAlign, setVerticalAlign] = (0, import_react7.useState)("below");
916
982
  const [maxHeight, setMaxHeight] = (0, import_react7.useState)(contentHeight);
@@ -944,7 +1010,7 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
944
1010
  }
945
1011
 
946
1012
  // src/SectionedDropdown.tsx
947
- var import_jsx_runtime14 = require("react/jsx-runtime");
1013
+ var import_jsx_runtime15 = require("react/jsx-runtime");
948
1014
  var MENU_BORDER_WIDTH = 1;
949
1015
  var TRIGGER_SIZE = 44;
950
1016
  var MENU_MIN_WIDTH = 200;
@@ -959,8 +1025,8 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
959
1025
  const ambientRotation = (0, import_core6.useRotation)();
960
1026
  const rotation = rotationOverride ?? ambientRotation;
961
1027
  const menuBg = dark ? "#000000" : "#FFFFFF";
962
- const menuBorderColor = (0, import_auto_paper8.getBlendedColor)(mutedColor, menuBg, 0.5);
963
- const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper8.getColorRoles)(accentColor, menuBg).onColor;
1028
+ const menuBorderColor = (0, import_auto_paper9.getBlendedColor)(mutedColor, menuBg, 0.5);
1029
+ const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper9.getColorRoles)(accentColor, menuBg).onColor;
964
1030
  const fg = dark ? "#FFFFFF" : "#000000";
965
1031
  const open = host.openId === id;
966
1032
  const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
@@ -994,17 +1060,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
994
1060
  }
995
1061
  gaugeOffset += section.options.length;
996
1062
  }
997
- const anchorStyle = [styles11.anchor, open && styles11.anchorOpen];
1063
+ const anchorStyle = [styles12.anchor, open && styles12.anchorOpen];
998
1064
  const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
999
1065
  const dividerStyle = { backgroundColor: menuBorderColor };
1000
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native14.View, { style: anchorStyle, children: [
1001
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native14.View, { ref: triggerRef, collapsable: false, style: styles11.triggerBox, children: [
1002
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1003
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1066
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: anchorStyle, children: [
1067
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { ref: triggerRef, collapsable: false, style: styles12.triggerBox, children: [
1068
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1069
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1004
1070
  ] }),
1005
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native14.ScrollView, { style: [styles11.menu, menuStyle], contentContainerStyle: styles11.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native14.View, { children: [
1006
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native14.View, { style: [styles11.divider, dividerStyle] }),
1007
- section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1071
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.ScrollView, { style: [styles12.menu, menuStyle], contentContainerStyle: styles12.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { children: [
1072
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native15.View, { style: [styles12.divider, dividerStyle] }),
1073
+ section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1008
1074
  SingleSection,
1009
1075
  {
1010
1076
  section,
@@ -1017,7 +1083,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
1017
1083
  if (autoDismiss) host.close();
1018
1084
  }
1019
1085
  }
1020
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1086
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1021
1087
  ] }, section.id)) }) })
1022
1088
  ] });
1023
1089
  }
@@ -1029,18 +1095,18 @@ function SingleSection({
1029
1095
  labelFontFamily,
1030
1096
  onSelect
1031
1097
  }) {
1032
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: section.options.map((option) => {
1098
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children: section.options.map((option) => {
1033
1099
  const selected = option.value === section.value;
1034
1100
  const taken = !selected && option.value === section.takenValue;
1035
1101
  const rowColor = selected ? onAccentColor : mutedColor;
1036
- const itemStyle = [styles11.item, selected && { backgroundColor: accentColor }, taken && styles11.itemTaken];
1102
+ const itemStyle = [styles12.item, selected && { backgroundColor: accentColor }, taken && styles12.itemTaken];
1037
1103
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1038
1104
  const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
1039
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native14.View, { style: styles11.itemRow, children: [
1040
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1041
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native14.View, { style: styles11.itemLabelColumn, children: [
1042
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1043
- option.description && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1105
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: styles12.itemRow, children: [
1106
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: styles12.itemLabelColumn, children: [
1108
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1109
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1044
1110
  ] })
1045
1111
  ] }) }, option.value);
1046
1112
  }) });
@@ -1054,23 +1120,23 @@ function MultiSection({
1054
1120
  allClearLabels
1055
1121
  }) {
1056
1122
  const allSelected = section.value.length === section.options.length;
1057
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
1123
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1058
1124
  section.options.map((option, i) => {
1059
1125
  const selected = section.value.includes(option.value);
1060
1126
  const rowColor = selected ? onAccentColor : mutedColor;
1061
1127
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
1062
1128
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
1063
- const itemStyle = [styles11.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1129
+ const itemStyle = [styles12.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1064
1130
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1065
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native14.View, { style: styles11.itemRow, children: [
1066
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1067
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { variant: "labelLarge", style: [styles11.itemLabelFlex, labelStyle], children: option.label })
1131
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native15.View, { style: styles12.itemRow, children: [
1132
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1133
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: [styles12.itemLabelFlex, labelStyle], children: option.label })
1068
1134
  ] }) }, option.value);
1069
1135
  }),
1070
- section.allClear && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles11.item, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { variant: "labelLarge", style: [styles11.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1136
+ section.allClear && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles12.item, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: [styles12.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1071
1137
  ] });
1072
1138
  }
1073
- var styles11 = import_react_native14.StyleSheet.create({
1139
+ var styles12 = import_react_native15.StyleSheet.create({
1074
1140
  allClearLabel: {
1075
1141
  fontWeight: "bold",
1076
1142
  textAlign: "center"
@@ -1087,7 +1153,7 @@ var styles11 = import_react_native14.StyleSheet.create({
1087
1153
  zIndex: 100
1088
1154
  },
1089
1155
  divider: {
1090
- height: import_react_native14.StyleSheet.hairlineWidth,
1156
+ height: import_react_native15.StyleSheet.hairlineWidth,
1091
1157
  marginVertical: 4
1092
1158
  },
1093
1159
  item: {
@@ -1140,24 +1206,24 @@ var styles11 = import_react_native14.StyleSheet.create({
1140
1206
  });
1141
1207
 
1142
1208
  // src/ControlSchemePicker.tsx
1143
- var import_jsx_runtime15 = require("react/jsx-runtime");
1209
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1144
1210
  function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily }) {
1145
1211
  const isTouchPrimary = (0, import_core7.useIsTouchPrimaryDevice)();
1146
- if (import_react_native15.Platform.OS !== "web" || isTouchPrimary) return null;
1147
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
1212
+ if (import_react_native16.Platform.OS !== "web" || isTouchPrimary) return null;
1213
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
1148
1214
  }
1149
1215
 
1150
1216
  // src/CornerActionButtons.tsx
1151
1217
  var import_feedback_press5 = require("@rific/feedback-press");
1152
- var import_react_native16 = require("react-native");
1153
- var import_jsx_runtime16 = require("react/jsx-runtime");
1218
+ var import_react_native17 = require("react-native");
1219
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1154
1220
  function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
1155
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1156
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles12.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
1157
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles12.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
1221
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1222
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles13.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
1223
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles13.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
1158
1224
  ] });
1159
1225
  }
1160
- var styles12 = import_react_native16.StyleSheet.create({
1226
+ var styles13 = import_react_native17.StyleSheet.create({
1161
1227
  back: {
1162
1228
  position: "absolute"
1163
1229
  },
@@ -1167,22 +1233,22 @@ var styles12 = import_react_native16.StyleSheet.create({
1167
1233
  });
1168
1234
 
1169
1235
  // src/CornerStatusBadges.tsx
1170
- var import_react_native17 = require("react-native");
1171
- var import_react_native_paper9 = require("react-native-paper");
1172
- var import_jsx_runtime17 = require("react/jsx-runtime");
1236
+ var import_react_native18 = require("react-native");
1237
+ var import_react_native_paper10 = require("react-native-paper");
1238
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1173
1239
  var BADGE_SIZE = 30;
1174
1240
  function StatusBadge({ icon }) {
1175
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native17.View, { style: styles13.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper9.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { style: styles14.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1176
1242
  }
1177
1243
  function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
1178
1244
  const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
1179
1245
  const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
1180
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
1181
- p1 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native17.View, { pointerEvents: "none", style: p1OnRightSide ? styles13.bottomRight : styles13.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { icon: p1.icon }) }),
1182
- p2 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native17.View, { pointerEvents: "none", style: p2OnLeftSide ? styles13.topLeft : styles13.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(StatusBadge, { icon: p2.icon }) })
1246
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
1247
+ p1 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { pointerEvents: "none", style: p1OnRightSide ? styles14.bottomRight : styles14.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusBadge, { icon: p1.icon }) }),
1248
+ p2 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { pointerEvents: "none", style: p2OnLeftSide ? styles14.topLeft : styles14.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(StatusBadge, { icon: p2.icon }) })
1183
1249
  ] });
1184
1250
  }
1185
- var styles13 = import_react_native17.StyleSheet.create({
1251
+ var styles14 = import_react_native18.StyleSheet.create({
1186
1252
  badge: {
1187
1253
  alignItems: "center",
1188
1254
  backgroundColor: "rgba(0,0,0,0.28)",
@@ -1201,12 +1267,12 @@ var styles13 = import_react_native17.StyleSheet.create({
1201
1267
  });
1202
1268
 
1203
1269
  // src/InlineColorPicker.tsx
1204
- var import_auto_paper9 = require("@rific/auto-paper");
1270
+ var import_auto_paper10 = require("@rific/auto-paper");
1205
1271
  var import_feedback_press6 = require("@rific/feedback-press");
1206
1272
  var import_core8 = require("@tastic/core");
1207
- var import_react_native18 = require("react-native");
1208
- var import_react_native_paper10 = require("react-native-paper");
1209
- var import_jsx_runtime18 = require("react/jsx-runtime");
1273
+ var import_react_native19 = require("react-native");
1274
+ var import_react_native_paper11 = require("react-native-paper");
1275
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1210
1276
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
1211
1277
  var DEFAULT_SIZE = 48;
1212
1278
  var SWATCH_SIZE = 28;
@@ -1227,11 +1293,11 @@ function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
1227
1293
  const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
1228
1294
  return { width, height };
1229
1295
  }
1230
- function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper9.defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1296
+ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper10.defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1231
1297
  const ambientRotation = (0, import_core8.useRotation)();
1232
1298
  const rotation = rotationOverride ?? ambientRotation;
1233
1299
  const menuBg = dark ? "#000000" : "#FFFFFF";
1234
- const { width: windowWidth } = (0, import_react_native18.useWindowDimensions)();
1300
+ const { width: windowWidth } = (0, import_react_native19.useWindowDimensions)();
1235
1301
  const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
1236
1302
  const open = host.openId === id;
1237
1303
  const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
@@ -1240,16 +1306,16 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1240
1306
  const align = forcedAlign ?? placement.align;
1241
1307
  const displayFor = previewValue ?? ((hex) => hex);
1242
1308
  const displayValue = displayFor(value);
1243
- const contrastColor = (0, import_auto_paper9.getContrastColor)(displayValue);
1309
+ const contrastColor = (0, import_auto_paper10.getContrastColor)(displayValue);
1244
1310
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
1245
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native18.View, { style: [styles14.anchor, open && styles14.anchorOpen], children: [
1246
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles14.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, { ref: triggerRef, collapsable: false, style: styles14.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Text, { style: [styles14.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1247
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.ScrollView, { style: [styles14.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles14.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1311
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native19.View, { style: [styles15.anchor, open && styles15.anchorOpen], children: [
1312
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles15.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, { ref: triggerRef, collapsable: false, style: styles15.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Text, { style: [styles15.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.ScrollView, { style: [styles15.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles15.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1248
1314
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
1249
1315
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
1250
1316
  const swappable = taken && allowSwapTaken;
1251
1317
  const swatchDisplay = displayFor(swatch.value);
1252
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1318
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1253
1319
  import_feedback_press6.TouchableRipple,
1254
1320
  {
1255
1321
  disabled: taken && !swappable,
@@ -1258,15 +1324,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
1258
1324
  if (autoDismiss) host.close();
1259
1325
  },
1260
1326
  borderless: true,
1261
- style: [styles14.swatch, { backgroundColor: swatchDisplay }, selected && styles14.swatchSelected, taken && !swappable && styles14.swatchTaken],
1262
- children: selected ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Icon, { source: "check", size: 16, color: (0, import_auto_paper9.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper9.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Icon, { source: "close", size: 16, color: (0, import_auto_paper9.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native18.View, {})
1327
+ style: [styles15.swatch, { backgroundColor: swatchDisplay }, selected && styles15.swatchSelected, taken && !swappable && styles15.swatchTaken],
1328
+ children: selected ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "check", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "close", size: 16, color: (0, import_auto_paper10.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.View, {})
1263
1329
  },
1264
1330
  swatch.value
1265
1331
  );
1266
1332
  }) }) })
1267
1333
  ] });
1268
1334
  }
1269
- var styles14 = import_react_native18.StyleSheet.create({
1335
+ var styles15 = import_react_native19.StyleSheet.create({
1270
1336
  anchor: {
1271
1337
  position: "relative"
1272
1338
  },
@@ -1338,11 +1404,11 @@ var styles14 = import_react_native18.StyleSheet.create({
1338
1404
  });
1339
1405
 
1340
1406
  // src/LabeledDropdown.tsx
1341
- var import_auto_paper10 = require("@rific/auto-paper");
1407
+ var import_auto_paper11 = require("@rific/auto-paper");
1342
1408
  var import_feedback_press7 = require("@rific/feedback-press");
1343
- var import_react_native19 = require("react-native");
1344
- var import_react_native_paper11 = require("react-native-paper");
1345
- var import_jsx_runtime19 = require("react/jsx-runtime");
1409
+ var import_react_native20 = require("react-native");
1410
+ var import_react_native_paper12 = require("react-native-paper");
1411
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1346
1412
  var TRIGGER_HEIGHT = 28;
1347
1413
  var POPOVER_WIDTH = 180;
1348
1414
  var ROW_HEIGHT = 36;
@@ -1365,22 +1431,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
1365
1431
  onChange(option.value);
1366
1432
  host.close();
1367
1433
  };
1368
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native19.View, { style: [styles15.anchor, open && styles15.anchorOpen], children: [
1369
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles15.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native19.View, { ref: triggerRef, collapsable: false, style: styles15.triggerInner, children: [
1370
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Text, { style: [styles15.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1371
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: "menu-down", size: 16, color })
1434
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { style: [styles16.anchor, open && styles16.anchorOpen], children: [
1435
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles16.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { ref: triggerRef, collapsable: false, style: styles16.triggerInner, children: [
1436
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { style: [styles16.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1437
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: "menu-down", size: 16, color })
1372
1438
  ] }) }),
1373
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native19.ScrollView, { style: [styles15.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles15.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1439
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native20.ScrollView, { style: [styles16.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles16.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1374
1440
  const isSelected = option.value === value;
1375
- const onColor = (0, import_auto_paper10.getContrastColor)(color);
1376
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles15.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native19.View, { style: styles15.rowInner, children: [
1377
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1378
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Text, { style: [styles15.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1441
+ const onColor = (0, import_auto_paper11.getContrastColor)(color);
1442
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles16.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_native20.View, { style: styles16.rowInner, children: [
1443
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1444
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { style: [styles16.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1379
1445
  ] }) }, option.value);
1380
1446
  }) }) })
1381
1447
  ] });
1382
1448
  }
1383
- var styles15 = import_react_native19.StyleSheet.create({
1449
+ var styles16 = import_react_native20.StyleSheet.create({
1384
1450
  anchor: {
1385
1451
  position: "relative"
1386
1452
  },
@@ -1438,22 +1504,22 @@ function loadSkiaWeb() {
1438
1504
  }
1439
1505
 
1440
1506
  // src/PlayerSetupPanel.tsx
1441
- var import_profile = require("@tastic/profile");
1442
- var import_react_native21 = require("react-native");
1443
- var import_react_native_paper13 = require("react-native-paper");
1507
+ var import_profile2 = require("@tastic/profile");
1508
+ var import_react_native22 = require("react-native");
1509
+ var import_react_native_paper14 = require("react-native-paper");
1444
1510
 
1445
1511
  // src/ReadyButton.tsx
1446
1512
  var import_feedback_press8 = require("@rific/feedback-press");
1447
- var import_react_native20 = require("react-native");
1448
- var import_react_native_paper12 = require("react-native-paper");
1449
- var import_jsx_runtime20 = require("react/jsx-runtime");
1513
+ var import_react_native21 = require("react-native");
1514
+ var import_react_native_paper13 = require("react-native-paper");
1515
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1450
1516
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
1451
- const readyButtonStyle = [styles16.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1517
+ const readyButtonStyle = [styles17.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1452
1518
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
1453
1519
  const labelColorStyle = { color: ready ? "#000000" : color };
1454
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_native_paper12.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1520
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1455
1521
  }
1456
- var styles16 = import_react_native20.StyleSheet.create({
1522
+ var styles17 = import_react_native21.StyleSheet.create({
1457
1523
  readyButton: {
1458
1524
  alignItems: "center",
1459
1525
  borderRadius: 12,
@@ -1477,7 +1543,7 @@ function usePopoverHost() {
1477
1543
  }
1478
1544
 
1479
1545
  // src/PlayerSetupPanel.tsx
1480
- var import_jsx_runtime21 = require("react/jsx-runtime");
1546
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1481
1547
  function getColorPopoverId(idPrefix) {
1482
1548
  return `${idPrefix}-color`;
1483
1549
  }
@@ -1492,16 +1558,16 @@ function PlayerSetupPanel({ idPrefix, host, label, labelFontFamily, color, onCol
1492
1558
  const showProfilePicker = isHuman && profiles !== void 0 && !!onProfileSelect;
1493
1559
  const showCpuDifficulty = !isHuman && cpuDifficulty !== void 0 && cpuDifficultyOptions !== void 0 && !!onCpuDifficultyChange;
1494
1560
  const selectedProfile = profiles?.find((p) => p.id === selectedProfileId) ?? null;
1495
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: [styles17.panel, ownPopoverOpen && styles17.panelOpen], children: [
1496
- showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_profile.ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native_paper13.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1497
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_native21.View, { style: [styles17.pickerRow, pickerRowPopoverOpen && styles17.pickerRowOpen], children: [
1498
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
1561
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { style: [styles18.panel, ownPopoverOpen && styles18.panelOpen], children: [
1562
+ showProfilePicker ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_profile2.ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles }) : showCpuDifficulty ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LabeledDropdown, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, alignOverride: cpuDifficultyAlignOverride }) : label && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native_paper14.Text, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
1563
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_native22.View, { style: [styles18.pickerRow, pickerRowPopoverOpen && styles18.pickerRowOpen], children: [
1564
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
1499
1565
  secondPicker
1500
1566
  ] }),
1501
- isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1567
+ isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ReadyButton, { color, ready: ready ?? false, onToggleReady })
1502
1568
  ] });
1503
1569
  }
1504
- var styles17 = import_react_native21.StyleSheet.create({
1570
+ var styles18 = import_react_native22.StyleSheet.create({
1505
1571
  panel: {
1506
1572
  alignItems: "center",
1507
1573
  gap: 12
@@ -1533,29 +1599,29 @@ var styles17 = import_react_native21.StyleSheet.create({
1533
1599
  });
1534
1600
 
1535
1601
  // src/PressAwayOverlay.tsx
1536
- var import_react_native22 = require("react-native");
1537
- var import_jsx_runtime22 = require("react/jsx-runtime");
1602
+ var import_react_native23 = require("react-native");
1603
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1538
1604
  function PressAwayOverlay({ active, onPress, style }) {
1539
1605
  if (!active) return null;
1540
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native22.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native22.StyleSheet.absoluteFill, style] });
1606
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_native23.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native23.StyleSheet.absoluteFill, style] });
1541
1607
  }
1542
1608
 
1543
1609
  // src/SharedActionBand.tsx
1544
1610
  var import_feedback_press9 = require("@rific/feedback-press");
1545
- var import_react_native23 = require("react-native");
1546
- var import_jsx_runtime23 = require("react/jsx-runtime");
1611
+ var import_react_native24 = require("react-native");
1612
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1547
1613
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
1548
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native23.View, { style: [styles18.column, popoverOpen && styles18.columnOpen], children: [
1549
- /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_native23.View, { style: styles18.actionsRow, children: [
1550
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1551
- onRandomize && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1552
- onReset && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1553
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1614
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native24.View, { style: [styles19.column, popoverOpen && styles19.columnOpen], children: [
1615
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_native24.View, { style: styles19.actionsRow, children: [
1616
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1617
+ onRandomize && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1618
+ onReset && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1619
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1554
1620
  ] }),
1555
1621
  children
1556
1622
  ] });
1557
1623
  }
1558
- var styles18 = import_react_native23.StyleSheet.create({
1624
+ var styles19 = import_react_native24.StyleSheet.create({
1559
1625
  actionsRow: {
1560
1626
  alignItems: "center",
1561
1627
  flexDirection: "row",
@@ -1572,9 +1638,9 @@ var styles18 = import_react_native23.StyleSheet.create({
1572
1638
 
1573
1639
  // src/StaggeredWord.tsx
1574
1640
  var import_react9 = require("react");
1575
- var import_react_native24 = require("react-native");
1641
+ var import_react_native25 = require("react-native");
1576
1642
  var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
1577
- var import_jsx_runtime24 = require("react/jsx-runtime");
1643
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1578
1644
  var STAGGER_MS = 45;
1579
1645
  var LETTER_DURATION_MS = 320;
1580
1646
  function getStaggeredWordDuration(letterCount) {
@@ -1590,12 +1656,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
1590
1656
  opacity: progress.value,
1591
1657
  transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
1592
1658
  }));
1593
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native_reanimated2.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
1659
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native_reanimated2.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
1594
1660
  }
1595
1661
  function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
1596
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_native24.View, { style: [styles19.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
1662
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_native25.View, { style: [styles20.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
1597
1663
  }
1598
- var styles19 = import_react_native24.StyleSheet.create({
1664
+ var styles20 = import_react_native25.StyleSheet.create({
1599
1665
  row: {
1600
1666
  flexDirection: "row"
1601
1667
  }
@@ -1603,12 +1669,12 @@ var styles19 = import_react_native24.StyleSheet.create({
1603
1669
 
1604
1670
  // src/UpdateDialog.tsx
1605
1671
  var import_updater2 = require("@rific/updater");
1606
- var import_jsx_runtime25 = require("react/jsx-runtime");
1672
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1607
1673
  function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
1608
1674
  const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
1609
1675
  (0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
1610
1676
  const date = manifest ? new Date(manifest.createdAt) : null;
1611
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
1677
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
1612
1678
  }
1613
1679
 
1614
1680
  // src/useQuitConfirmation.ts
@@ -1634,13 +1700,13 @@ function useQuitConfirmation(hasProgress, onConfirmedBack) {
1634
1700
  // src/useZoneClampedAlign.ts
1635
1701
  var import_split_screen = require("@tastic/split-screen");
1636
1702
  var import_react11 = require("react");
1637
- var import_react_native25 = require("react-native");
1703
+ var import_react_native26 = require("react-native");
1638
1704
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
1639
1705
  var EDGE_MARGIN2 = 12;
1640
1706
  function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1641
1707
  const auto = useAutoAlign(open, contentWidth, contentHeight, rotation);
1642
1708
  const zone = (0, import_split_screen.useZoneBounds)();
1643
- const { height: windowHeight } = (0, import_react_native25.useWindowDimensions)();
1709
+ const { height: windowHeight } = (0, import_react_native26.useWindowDimensions)();
1644
1710
  const insets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
1645
1711
  const shouldMeasure = open && auto.measured && zone !== null;
1646
1712
  const [ownBounds, setOwnBounds] = (0, import_react11.useState)(null);
@@ -1673,6 +1739,7 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1673
1739
  0 && (module.exports = {
1674
1740
  AchievementCatalogSection,
1675
1741
  AchievementRow,
1742
+ AchievementUnlockList,
1676
1743
  ActivityStatSection,
1677
1744
  BaseSettingsDialog,
1678
1745
  BaseStatsScreen,
@@ -1705,6 +1772,7 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
1705
1772
  getOverlayCardColors,
1706
1773
  getStaggeredWordDuration,
1707
1774
  loadSkiaWeb,
1775
+ overlayActionStyles,
1708
1776
  overlayStyles,
1709
1777
  useAutoAlign,
1710
1778
  usePopoverHost,