@tastic/hud 0.17.0 → 0.19.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.
@@ -35,9 +35,11 @@ __export(chrome_exports, {
35
35
  ActivityStatSection: () => ActivityStatSection,
36
36
  BaseSettingsDialog: () => BaseSettingsDialog,
37
37
  BaseStatsScreen: () => BaseStatsScreen,
38
+ COMPACT_DIALOG_HEIGHT: () => COMPACT_DIALOG_HEIGHT,
38
39
  ConfirmDialog: () => ConfirmDialog,
39
40
  ContentGutter: () => ContentGutter,
40
41
  CornerActionButtons: () => CornerActionButtons,
42
+ DialogHeader: () => DialogHeader,
41
43
  LOCKED_BADGE_COLOR: () => LOCKED_BADGE_COLOR,
42
44
  MONO_FONT: () => MONO_FONT,
43
45
  OverlayBackdrop: () => OverlayBackdrop,
@@ -47,10 +49,11 @@ __export(chrome_exports, {
47
49
  StatRow: () => StatRow,
48
50
  StatSection: () => StatSection,
49
51
  UpdateDialog: () => UpdateDialog,
50
- getOverlayCardColors: () => getOverlayCardColors,
51
52
  getStaggeredWordDuration: () => getStaggeredWordDuration,
53
+ isCompactDialogHeight: () => isCompactDialogHeight,
52
54
  overlayActionStyles: () => overlayActionStyles,
53
55
  overlayStyles: () => overlayStyles,
56
+ useCompactDialog: () => useCompactDialog,
54
57
  useOverlayCardColors: () => useOverlayCardColors
55
58
  });
56
59
  module.exports = __toCommonJS(chrome_exports);
@@ -216,39 +219,74 @@ function ActivityStatSection({ stats }) {
216
219
  }
217
220
 
218
221
  // src/BaseSettingsDialog.tsx
219
- var import_auto_paper7 = require("@rific/auto-paper");
222
+ var import_auto_paper8 = require("@rific/auto-paper");
220
223
  var import_feedback_press2 = require("@rific/feedback-press");
221
224
  var import_updater = require("@rific/updater");
222
- var import_core3 = require("@tastic/core");
223
- var import_react4 = require("react");
224
- var import_react_native10 = require("react-native");
225
- var import_react_native_paper7 = require("react-native-paper");
225
+ var import_core4 = require("@tastic/core");
226
+ var import_react5 = require("react");
227
+ var import_react_native12 = require("react-native");
228
+ var import_react_native_paper8 = require("react-native-paper");
229
+ var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
226
230
 
227
231
  // src/ConfirmDialog.tsx
228
- var import_auto_paper6 = require("@rific/auto-paper");
232
+ var import_auto_paper7 = require("@rific/auto-paper");
229
233
  var import_feedback_press = require("@rific/feedback-press");
230
- var import_core = require("@tastic/core");
231
- var import_react_native8 = require("react-native");
232
- var import_react_native_paper5 = require("react-native-paper");
234
+ var import_core2 = require("@tastic/core");
235
+ var import_react_native10 = require("react-native");
236
+ var import_react_native_paper6 = require("react-native-paper");
233
237
 
234
- // src/overlayCard.ts
238
+ // src/DialogHeader.tsx
239
+ var import_auto_paper5 = require("@rific/auto-paper");
235
240
  var import_react_native6 = require("react-native");
236
- function getOverlayCardColors(dark) {
237
- return {
238
- fg: dark ? "#FFFFFF" : "#000000",
239
- fgMuted: dark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)",
240
- cardBg: dark ? "#111111" : "#F2F2F2",
241
- cardBorder: dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"
242
- };
241
+ var import_react_native_paper5 = require("react-native-paper");
242
+ var import_jsx_runtime6 = require("react/jsx-runtime");
243
+ var COMPACT_DIALOG_HEIGHT = 528;
244
+ function isCompactDialogHeight(height) {
245
+ return height < COMPACT_DIALOG_HEIGHT;
243
246
  }
244
- var overlayStyles = import_react_native6.StyleSheet.create({
247
+ function DialogHeader({ icon, title, color, compact = false, style }) {
248
+ const { colors } = (0, import_auto_paper5.useAutoPaperTheme)();
249
+ const accent = color ?? colors.primary;
250
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: [compact ? styles5.compact : styles5.full, style], children: [
251
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Icon, { source: icon, size: compact ? COMPACT_ICON_SIZE : ICON_SIZE, color: accent }),
252
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper5.Text, { accessibilityRole: "header", variant: compact ? "headlineSmall" : "headlineLarge", style: [styles5.title, compact && styles5.titleCompact, { color: accent }], children: title })
253
+ ] });
254
+ }
255
+ var ICON_SIZE = 64;
256
+ var COMPACT_ICON_SIZE = 32;
257
+ var styles5 = import_react_native6.StyleSheet.create({
258
+ compact: {
259
+ alignItems: "center",
260
+ alignSelf: "stretch",
261
+ flexDirection: "row",
262
+ gap: 12,
263
+ justifyContent: "center"
264
+ },
265
+ full: {
266
+ alignItems: "center",
267
+ alignSelf: "stretch",
268
+ gap: 16
269
+ },
270
+ // textAlign matters once a title wraps: the card centers the Text's block, but each wrapped line
271
+ // still defaults to left-aligned without it.
272
+ title: {
273
+ fontWeight: "bold",
274
+ textAlign: "center"
275
+ },
276
+ titleCompact: {
277
+ flexShrink: 1
278
+ }
279
+ });
280
+
281
+ // src/overlayCard.ts
282
+ var import_react_native7 = require("react-native");
283
+ var overlayStyles = import_react_native7.StyleSheet.create({
245
284
  card: {
246
285
  alignItems: "center",
247
- borderRadius: 20,
248
- borderWidth: 1,
286
+ borderRadius: 28,
249
287
  gap: 16,
250
288
  maxWidth: 360,
251
- padding: 32
289
+ padding: 24
252
290
  },
253
291
  overlay: {
254
292
  alignItems: "center",
@@ -261,7 +299,7 @@ var overlayStyles = import_react_native6.StyleSheet.create({
261
299
  top: 0
262
300
  }
263
301
  });
264
- var overlayActionStyles = import_react_native6.StyleSheet.create({
302
+ var overlayActionStyles = import_react_native7.StyleSheet.create({
265
303
  // minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
266
304
  // still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
267
305
  // on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
@@ -304,46 +342,63 @@ var overlayActionStyles = import_react_native6.StyleSheet.create({
304
342
  });
305
343
 
306
344
  // src/OverlaySurface.tsx
307
- var import_auto_paper5 = require("@rific/auto-paper");
308
- var import_react_native7 = require("react-native");
309
- var import_jsx_runtime6 = require("react/jsx-runtime");
345
+ var import_auto_paper6 = require("@rific/auto-paper");
346
+ var import_react_native8 = require("react-native");
347
+ var import_jsx_runtime7 = require("react/jsx-runtime");
310
348
  function useOverlayCardColors() {
311
- const { colors } = (0, import_auto_paper5.useAutoPaperTheme)();
349
+ const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
312
350
  return { fg: colors.onSurface, fgMuted: colors.onSurfaceVariant, cardBorder: colors.outlineVariant, backdrop: colors.backdrop };
313
351
  }
314
- function OverlayBackdrop({ children, style }) {
352
+ function OverlayBackdrop({ children, style, onLayout }) {
315
353
  const { backdrop } = useOverlayCardColors();
316
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
354
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { onLayout, style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
317
355
  }
318
356
  function OverlayCard({ children, style, ...rest }) {
319
- const { cardBorder } = useOverlayCardColors();
320
- const blur = (0, import_auto_paper5.useBlur)();
321
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_auto_paper5.BlurView, { blur, elevation: 3, style: [overlayStyles.card, styles5.card, { borderColor: cardBorder }, style], ...rest, children });
357
+ const { isV3, roundness } = (0, import_auto_paper6.useAutoPaperTheme)();
358
+ const blur = (0, import_auto_paper6.useBlur)();
359
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_auto_paper6.BlurView, { blur, style: [overlayStyles.card, styles6.card, { borderRadius: (isV3 ? 7 : 1) * roundness }, style], ...rest, children });
322
360
  }
323
- var styles5 = import_react_native7.StyleSheet.create({
361
+ var styles6 = import_react_native8.StyleSheet.create({
324
362
  card: { overflow: "hidden" }
325
363
  });
326
364
 
365
+ // src/useCompactDialog.ts
366
+ var import_core = require("@tastic/core");
367
+ var import_react2 = require("react");
368
+ var import_react_native9 = require("react-native");
369
+ function useCompactDialog(rotation = 0) {
370
+ const window = (0, import_react_native9.useWindowDimensions)();
371
+ const framed = (0, import_core.useRotatedWindowDimensions)();
372
+ const [measured, setMeasured] = (0, import_react2.useState)(null);
373
+ const onLayout = (0, import_react2.useCallback)((e) => {
374
+ const { width, height } = e.nativeEvent.layout;
375
+ setMeasured((prev) => prev && prev.width === width && prev.height === height ? prev : { width, height });
376
+ }, []);
377
+ const box = measured ?? (rotation === 0 ? framed : window);
378
+ const turned = rotation === 90 || rotation === -90;
379
+ return { compact: isCompactDialogHeight(turned ? box.width : box.height), onLayout };
380
+ }
381
+
327
382
  // src/ConfirmDialog.tsx
328
- var import_jsx_runtime7 = require("react/jsx-runtime");
383
+ var import_jsx_runtime8 = require("react/jsx-runtime");
329
384
  function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
330
- const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
385
+ const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
331
386
  const { fg } = useOverlayCardColors();
387
+ const { compact, onLayout } = useCompactDialog(rotation);
332
388
  if (!visible) return null;
333
389
  const accent = destructive ? colors.danger : colors.primary;
334
390
  const onAccent = destructive ? colors.onDanger : colors.onPrimary;
335
391
  const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
336
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(OverlayBackdrop, { style: styles6.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(OverlayCard, { style: [styles6.card, (0, import_core.toRotationStyle)(rotation)], children: [
337
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Icon, { source: icon, size: 64, color: accent }),
338
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { variant: "headlineLarge", style: [styles6.title, { color: accent }], children: title }),
339
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { variant: "bodyLarge", style: [styles6.body, { color: fg }], children: message }),
340
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: overlayActionStyles.actions, children: [
341
- showCancel && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
342
- /* @__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 })
392
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(OverlayBackdrop, { style: styles7.overlay, onLayout, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(OverlayCard, { style: [styles7.card, (0, import_core2.toRotationStyle)(rotation)], children: [
393
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DialogHeader, { icon, title, color: accent, compact }),
394
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Text, { variant: "bodyLarge", style: [styles7.body, { color: fg }], children: message }),
395
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native10.View, { style: overlayActionStyles.actions, children: [
396
+ showCancel && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
397
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
343
398
  ] })
344
399
  ] }) }) });
345
400
  }
346
- var styles6 = import_react_native8.StyleSheet.create({
401
+ var styles7 = import_react_native10.StyleSheet.create({
347
402
  body: {
348
403
  textAlign: "center"
349
404
  },
@@ -361,35 +416,28 @@ var styles6 = import_react_native8.StyleSheet.create({
361
416
  // screen narrower than maxWidth's own 360.
362
417
  overlay: {
363
418
  paddingHorizontal: 24
364
- },
365
- // textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
366
- // within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
367
- // line inside that block still defaults to left-aligned without this.
368
- title: {
369
- fontWeight: "bold",
370
- textAlign: "center"
371
419
  }
372
420
  });
373
421
 
374
422
  // src/RotatedFrame.tsx
375
- var import_core2 = require("@tastic/core");
376
- var import_react2 = require("react");
377
- var import_react_native9 = require("react-native");
378
- var import_react_native_paper6 = require("react-native-paper");
423
+ var import_core3 = require("@tastic/core");
424
+ var import_react3 = require("react");
425
+ var import_react_native11 = require("react-native");
426
+ var import_react_native_paper7 = require("react-native-paper");
379
427
  var import_react_native_safe_area_context = require("react-native-safe-area-context");
380
- var import_jsx_runtime8 = require("react/jsx-runtime");
428
+ var import_jsx_runtime9 = require("react/jsx-runtime");
381
429
  function RotatedFrame({ children, rotation: rotationOverride, rotatedSafeArea = false, portalHost = false, passThrough = false, maxContentWidth }) {
382
- const ambientRotation = (0, import_core2.useRotation)();
430
+ const ambientRotation = (0, import_core3.useRotation)();
383
431
  const rotation = rotationOverride ?? ambientRotation;
384
- const window = (0, import_react_native9.useWindowDimensions)();
385
- const { width, height } = (0, import_core2.rotateDimensions)(window.width, window.height, rotation);
432
+ const window = (0, import_react_native11.useWindowDimensions)();
433
+ const { width, height } = (0, import_core3.rotateDimensions)(window.width, window.height, rotation);
386
434
  const rawInsets = (0, import_react_native_safe_area_context.useSafeAreaInsets)();
387
- const insets = (0, import_react2.useMemo)(() => rotatedSafeArea ? (0, import_core2.rotateInsets)(rawInsets, rotation) : rawInsets, [rotatedSafeArea, rawInsets, rotation]);
435
+ const insets = (0, import_react3.useMemo)(() => rotatedSafeArea ? (0, import_core3.rotateInsets)(rawInsets, rotation) : rawInsets, [rotatedSafeArea, rawInsets, rotation]);
388
436
  const cappedWidth = maxContentWidth !== void 0 && width > height ? maxContentWidth : void 0;
389
- const column = /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native9.View, { style: [styles7.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
390
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core2.FakeLandscapeView, { rotation, passThrough, style: styles7.root, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Portal.Host, { children: column }) : column }) });
437
+ const column = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native11.View, { style: [styles8.column, cappedWidth !== void 0 && { maxWidth: cappedWidth }], pointerEvents: passThrough ? "box-none" : void 0, children });
438
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core3.FakeLandscapeView, { rotation, passThrough, style: styles8.root, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_safe_area_context.SafeAreaInsetsContext.Provider, { value: insets, children: portalHost ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Portal.Host, { children: column }) : column }) });
391
439
  }
392
- var styles7 = import_react_native9.StyleSheet.create({
440
+ var styles8 = import_react_native11.StyleSheet.create({
393
441
  // A centred column: full width up to `maxWidth`, so a capped frame sits in the middle of a wider window.
394
442
  column: {
395
443
  alignSelf: "center",
@@ -402,18 +450,18 @@ var styles7 = import_react_native9.StyleSheet.create({
402
450
  });
403
451
 
404
452
  // src/useUpdateConfirmBridge.ts
405
- var import_react3 = require("react");
453
+ var import_react4 = require("react");
406
454
  function useUpdateConfirmBridge() {
407
- const [manifest, setManifest] = (0, import_react3.useState)(null);
408
- const resolveRef = (0, import_react3.useRef)(null);
409
- const onConfirm = (0, import_react3.useCallback)(
455
+ const [manifest, setManifest] = (0, import_react4.useState)(null);
456
+ const resolveRef = (0, import_react4.useRef)(null);
457
+ const onConfirm = (0, import_react4.useCallback)(
410
458
  (next) => new Promise((resolve) => {
411
459
  resolveRef.current = resolve;
412
460
  setManifest(next);
413
461
  }),
414
462
  []
415
463
  );
416
- const respond = (0, import_react3.useCallback)((confirmed) => {
464
+ const respond = (0, import_react4.useCallback)((confirmed) => {
417
465
  setManifest(null);
418
466
  resolveRef.current?.(confirmed);
419
467
  resolveRef.current = null;
@@ -422,22 +470,27 @@ function useUpdateConfirmBridge() {
422
470
  }
423
471
 
424
472
  // src/BaseSettingsDialog.tsx
425
- var import_jsx_runtime9 = require("react/jsx-runtime");
473
+ var import_jsx_runtime10 = require("react/jsx-runtime");
426
474
  function SettingIcon({ source, color, containerColor }) {
427
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Icon, { source, size: 18, color }) });
475
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [styles9.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Icon, { source, size: 18, color }) });
428
476
  }
429
- function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
430
- const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
431
- const ambientRotation = (0, import_core3.useRotation)();
477
+ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
478
+ const { colors } = (0, import_auto_paper8.useAutoPaperTheme)();
479
+ const ambientRotation = (0, import_core4.useRotation)();
432
480
  const rotation = rotationOverride ?? ambientRotation;
433
- const isTouchPrimary = (0, import_core3.useIsTouchPrimaryDevice)();
481
+ const window = (0, import_react_native12.useWindowDimensions)();
482
+ const turned = rotation === 90 || rotation === -90;
483
+ const compactHeader = isCompactDialogHeight(turned ? window.width : window.height);
484
+ const insets = (0, import_core4.rotateInsets)((0, import_react_native_safe_area_context2.useSafeAreaInsets)(), rotation);
485
+ const sheetWidth = Math.min(overlayStyles.card.maxWidth, (turned ? window.height : window.width) - 2 * Math.max(insets.left, insets.right, SHEET_GUTTER));
486
+ const isTouchPrimary = (0, import_core4.useIsTouchPrimaryDevice)();
434
487
  const { settings: hapticSettings, set: setHapticSettings } = (0, import_feedback_press2.useHapticSettings)();
435
488
  const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press2.useSoundSettings)();
436
- const sound = (0, import_react4.useContext)(import_feedback_press2.SoundContext);
489
+ const sound = (0, import_react5.useContext)(import_feedback_press2.SoundContext);
437
490
  const { forceShort: forceHapticFeedback } = (0, import_feedback_press2.useVibration)();
438
- const { settings: themeSettings, set: setThemeSettings } = (0, import_auto_paper7.useThemeSettings)();
439
- const expoBlur = (0, import_auto_paper7.useBlurModule)();
440
- const [infoMessage, setInfoMessage] = (0, import_react4.useState)(null);
491
+ const { settings: themeSettings, set: setThemeSettings } = (0, import_auto_paper8.useThemeSettings)();
492
+ const expoBlur = (0, import_auto_paper8.useBlurModule)();
493
+ const [infoMessage, setInfoMessage] = (0, import_react5.useState)(null);
441
494
  const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
442
495
  const { check, checking, updateReady } = (0, import_updater.useUpdater)({
443
496
  autoCheck: false,
@@ -447,117 +500,132 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
447
500
  onInfo: (title, message) => setInfoMessage({ title, message })
448
501
  });
449
502
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
450
- const [opened, setOpened] = (0, import_react4.useState)(visible);
503
+ const [opened, setOpened] = (0, import_react5.useState)(visible);
451
504
  if (visible && !opened) setOpened(true);
452
505
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
453
- const showEdgeGuard = import_react_native10.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
454
- const showHaptics = import_react_native10.Platform.OS !== "web" && !hideHaptics;
506
+ const showEdgeGuard = import_react_native12.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
507
+ const showKeepAwake = isTouchPrimary && keepAwake !== void 0 && onKeepAwakeChange !== void 0;
508
+ const showHaptics = import_react_native12.Platform.OS !== "web" && !hideHaptics;
455
509
  const showSound = !hideSound;
456
510
  const showAppearance = !hideAppearance;
457
- const showBlur = showAppearance && import_react_native10.Platform.OS !== "android" && expoBlur !== void 0 && expoBlur !== null;
458
- const showUpdateCheck = import_react_native10.Platform.OS !== "web" && !hideUpdateCheck;
511
+ const showBlur = showAppearance && import_react_native12.Platform.OS !== "android" && expoBlur !== void 0 && expoBlur !== null;
512
+ const showUpdateCheck = import_react_native12.Platform.OS !== "web" && !hideUpdateCheck;
459
513
  if (!opened) return null;
460
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
461
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: styles8.dialog, children: [
462
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
463
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.ScrollArea, { style: styles8.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.ScrollView, { contentContainerStyle: styles8.content, showsVerticalScrollIndicator: false, children: [
464
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleGroup, children: [
465
- showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles8.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
466
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
467
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
468
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
469
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
470
- ] })
471
- ] }) }),
472
- showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles8.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
473
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
474
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
475
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
476
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
477
- ] })
478
- ] }) }),
479
- (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleRow, children: [
480
- showSound && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
481
- import_feedback_press2.TouchableRipple,
482
- {
483
- soundDisabled: true,
484
- onPress: () => {
485
- const enabled = !soundSettings.enabled;
486
- setSoundSettings({ enabled });
487
- if (enabled) sound.selection?.();
488
- },
489
- style: styles8.toggleButtonInRow,
490
- accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
491
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
492
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
493
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
494
- ] })
495
- }
496
- ),
497
- showHaptics && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
514
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
515
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_auto_paper8.Dialog, { visible, onDismiss, style: [styles9.dialog, { width: sheetWidth }], children: [
516
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper8.Dialog.ScrollArea, { style: styles9.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_auto_paper8.FadingScrollView, { contentContainerStyle: styles9.scrollContent, showsVerticalScrollIndicator: false, children: [
517
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(DialogHeader, { icon: "cog", title: "Settings", compact: compactHeader }),
518
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.content, children: [
519
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleGroup, children: [
520
+ showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles9.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
521
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
522
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.flexShrink, children: [
523
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
524
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pin current layout" })
525
+ ] })
526
+ ] }) }),
527
+ showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles9.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
528
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
529
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.flexShrink, children: [
530
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
531
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Require second swipe" })
532
+ ] })
533
+ ] }) }),
534
+ showKeepAwake && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onKeepAwakeChange(!keepAwake), style: styles9.toggleButton, accessibilityLabel: `Keep awake ${keepAwake ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
535
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: keepAwake ? "eye" : "eye-closed", color: keepAwake ? colors.tertiary : colors.onSurfaceVariant, containerColor: keepAwake ? colors.tertiaryContainer : colors.surfaceVariant }),
536
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.flexShrink, children: [
537
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Keep Awake" }),
538
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Stop auto-lock mid-match" })
539
+ ] })
540
+ ] }) }),
541
+ (showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleRow, children: [
542
+ showSound && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
543
+ import_feedback_press2.TouchableRipple,
544
+ {
545
+ soundDisabled: true,
546
+ onPress: () => {
547
+ const enabled = !soundSettings.enabled;
548
+ setSoundSettings({ enabled });
549
+ if (enabled) sound.selection?.();
550
+ },
551
+ style: styles9.toggleButtonInRow,
552
+ accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
553
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
554
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
555
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
556
+ ] })
557
+ }
558
+ ),
559
+ showHaptics && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
560
+ import_feedback_press2.TouchableRipple,
561
+ {
562
+ hapticDisabled: true,
563
+ onPress: () => {
564
+ const vibrate = !hapticSettings.vibrate;
565
+ setHapticSettings({ vibrate });
566
+ if (vibrate) forceHapticFeedback();
567
+ },
568
+ style: styles9.toggleButtonInRow,
569
+ accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
570
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
571
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
572
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
573
+ ] })
574
+ }
575
+ )
576
+ ] }),
577
+ onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
498
578
  import_feedback_press2.TouchableRipple,
499
579
  {
500
- hapticDisabled: true,
501
580
  onPress: () => {
502
- const vibrate = !hapticSettings.vibrate;
503
- setHapticSettings({ vibrate });
504
- if (vibrate) forceHapticFeedback();
581
+ onDismiss();
582
+ onShowHowToPlay();
505
583
  },
506
- style: styles8.toggleButtonInRow,
507
- accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
508
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
509
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
510
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
584
+ style: styles9.toggleButton,
585
+ accessibilityLabel: "How to Play",
586
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
587
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
588
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.flexShrink, children: [
589
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
590
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay quick intro" })
591
+ ] })
511
592
  ] })
512
593
  }
513
594
  )
514
595
  ] }),
515
- onShowHowToPlay && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
516
- import_feedback_press2.TouchableRipple,
517
- {
518
- onPress: () => {
519
- onDismiss();
520
- onShowHowToPlay();
521
- },
522
- style: styles8.toggleButton,
523
- accessibilityLabel: "How to Play",
524
- children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
525
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: "help-circle-outline", color: colors.secondary, containerColor: colors.secondaryContainer }),
526
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
527
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "How to Play" }),
528
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Replay the quick intro" })
529
- ] })
596
+ showAppearance && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.section, children: [
597
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "labelMedium", style: [styles9.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
598
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_auto_paper8.AutoAppearancePicker, { showLabels: false }),
599
+ showBlur && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => setThemeSettings({ blur: !themeSettings.blur }), style: styles9.toggleButton, accessibilityLabel: `Blur ${themeSettings.blur ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.toggleContent, children: [
600
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SettingIcon, { source: themeSettings.blur ? "blur" : "blur-off", color: themeSettings.blur ? colors.tertiary : colors.onSurfaceVariant, containerColor: themeSettings.blur ? colors.tertiaryContainer : colors.surfaceVariant }),
601
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.flexShrink, children: [
602
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Blur" }),
603
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Frost behind dialogs" })
530
604
  ] })
531
- }
532
- )
533
- ] }),
534
- showAppearance && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
535
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "labelMedium", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
536
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.AutoAppearancePicker, { showLabels: false }),
537
- showBlur && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => setThemeSettings({ blur: !themeSettings.blur }), style: styles8.toggleButton, accessibilityLabel: `Blur ${themeSettings.blur ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleContent, children: [
538
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: themeSettings.blur ? "blur" : "blur-off", color: themeSettings.blur ? colors.tertiary : colors.onSurfaceVariant, containerColor: themeSettings.blur ? colors.tertiaryContainer : colors.surfaceVariant }),
539
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper7.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Blur" })
540
- ] }) })
541
- ] }),
542
- children,
543
- showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.section, children: [
544
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native_paper7.Text, { variant: "labelSmall", style: [styles8.sectionLabel, { color: colors.onSurfaceVariant }], children: [
545
- "VERSION ",
546
- version,
547
- updateReady ? " \xB7 UPDATE READY" : ""
605
+ ] }) })
548
606
  ] }),
549
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
607
+ children,
608
+ showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native12.View, { style: styles9.section, children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_paper8.Text, { variant: "labelMedium", style: [styles9.sectionLabel, { color: colors.onSurfaceVariant }], children: [
610
+ "VERSION ",
611
+ version,
612
+ updateReady ? " \xB7 UPDATE READY" : ""
613
+ ] }),
614
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
615
+ ] })
550
616
  ] })
551
- ] }) })
617
+ ] }) }),
618
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native12.View, { style: [overlayActionStyles.actions, styles9.footer], children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press2.Button, { mode: "contained", onPress: onDismiss, style: overlayActionStyles.actionButtonSingle, buttonColor: colors.primary, textColor: colors.onPrimary, children: "Done" }) })
552
619
  ] }),
553
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation: 0, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
554
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
620
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ConfirmDialog, { visible: !!updateManifest, title: "Update Available", message: updateManifestDate ? `Released ${updateManifestDate.toLocaleDateString()} at ${updateManifestDate.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation: 0, onConfirm: () => respondToUpdateConfirm(true), onCancel: () => respondToUpdateConfirm(false) }),
621
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation: 0, onConfirm: () => setInfoMessage(null) })
555
622
  ] }) });
556
623
  }
557
- var styles8 = import_react_native10.StyleSheet.create({
624
+ var SHEET_GUTTER = 24;
625
+ var styles9 = import_react_native12.StyleSheet.create({
626
+ // The rows' sections, 24pt apart.
558
627
  content: {
559
- gap: 24,
560
- paddingVertical: 20
628
+ gap: 24
561
629
  },
562
630
  // Caps the card so it never grows past the screen - without this the dialog just keeps
563
631
  // growing to fit its content and the overflow gets clipped by the screen edge, which is
@@ -569,6 +637,11 @@ var styles8 = import_react_native10.StyleSheet.create({
569
637
  flexShrink: {
570
638
  flexShrink: 1
571
639
  },
640
+ // The overlay cards' 24pt padding, as the sheet's own insets (its scroll area pads 24 sideways).
641
+ footer: {
642
+ paddingBottom: 24,
643
+ paddingHorizontal: 24
644
+ },
572
645
  iconBadge: {
573
646
  alignItems: "center",
574
647
  borderRadius: 10,
@@ -576,9 +649,20 @@ var styles8 = import_react_native10.StyleSheet.create({
576
649
  justifyContent: "center",
577
650
  width: 36
578
651
  },
652
+ // No hairline dividers above and below the scroll area (Paper's MD2-era borders): none of the
653
+ // fleet's other dialogs draws one, so the sheet matches them (Jay, 2026-10-15).
579
654
  scrollArea: {
655
+ borderBottomWidth: 0,
656
+ borderTopWidth: 0,
580
657
  marginBottom: 0
581
658
  },
659
+ // The header and the rows scroll together: the card's 24pt inset above the header, the overlay
660
+ // cards' 16pt gap between it and the rows, and 16pt below the last row before the Done row.
661
+ scrollContent: {
662
+ gap: 16,
663
+ paddingBottom: 16,
664
+ paddingTop: 24
665
+ },
582
666
  section: {
583
667
  gap: 12
584
668
  },
@@ -622,31 +706,31 @@ var styles8 = import_react_native10.StyleSheet.create({
622
706
  });
623
707
 
624
708
  // src/BaseStatsScreen.tsx
625
- var import_auto_paper8 = require("@rific/auto-paper");
709
+ var import_auto_paper9 = require("@rific/auto-paper");
626
710
  var import_feedback_press3 = require("@rific/feedback-press");
627
- var import_core4 = require("@tastic/core");
628
- var import_react5 = require("react");
629
- var import_react_native11 = require("react-native");
630
- var import_react_native_paper8 = require("react-native-paper");
631
- var import_jsx_runtime10 = require("react/jsx-runtime");
711
+ var import_core5 = require("@tastic/core");
712
+ var import_react6 = require("react");
713
+ var import_react_native13 = require("react-native");
714
+ var import_react_native_paper9 = require("react-native-paper");
715
+ var import_jsx_runtime11 = require("react/jsx-runtime");
632
716
  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 }) {
633
- const { dark, colors } = (0, import_auto_paper8.useAutoPaperTheme)();
634
- const ambientRotation = (0, import_core4.useRotation)();
717
+ const { dark, colors } = (0, import_auto_paper9.useAutoPaperTheme)();
718
+ const ambientRotation = (0, import_core5.useRotation)();
635
719
  const rotation = rotationOverride ?? ambientRotation;
636
- const [confirmResetVisible, setConfirmResetVisible] = (0, import_react5.useState)(false);
720
+ const [confirmResetVisible, setConfirmResetVisible] = (0, import_react6.useState)(false);
637
721
  const showReset = !!onReset;
638
722
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
639
723
  const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
640
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.container, { backgroundColor: bg }], children: [
641
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: [styles9.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
642
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
643
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper8.Text, { variant: titleVariant, style: [styles9.title, { color: fg }], children: title })
724
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: [styles10.container, { backgroundColor: bg }], children: [
725
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.View, { style: [styles10.header, { paddingTop: 8 + insets.top, paddingLeft: 8 + insets.left }], children: [
726
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, onPress: onBack }),
727
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper9.Text, { variant: titleVariant, style: [styles10.title, { color: fg }], children: title })
644
728
  ] }),
645
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.ScrollView, { style: styles9.scrollView, contentContainerStyle: [styles9.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
729
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native13.ScrollView, { style: styles10.scrollView, contentContainerStyle: [styles10.content, { paddingBottom: 32 + insets.bottom }], showsVerticalScrollIndicator: false, children: [
646
730
  children,
647
- showReset && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles9.resetButton, children: resetLabel })
731
+ showReset && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: () => setConfirmResetVisible(true), buttonColor: colors.danger, textColor: colors.onDanger, style: styles10.resetButton, children: resetLabel })
648
732
  ] }),
649
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
733
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
650
734
  ConfirmDialog,
651
735
  {
652
736
  visible: confirmResetVisible,
@@ -666,7 +750,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
666
750
  )
667
751
  ] });
668
752
  }
669
- var styles9 = import_react_native11.StyleSheet.create({
753
+ var styles10 = import_react_native13.StyleSheet.create({
670
754
  container: {
671
755
  flex: 1
672
756
  },
@@ -697,19 +781,19 @@ var styles9 = import_react_native11.StyleSheet.create({
697
781
  });
698
782
 
699
783
  // src/ContentGutter.tsx
700
- var import_core5 = require("@tastic/core");
701
- var import_react_native12 = require("react-native");
702
- var import_jsx_runtime11 = require("react/jsx-runtime");
784
+ var import_core6 = require("@tastic/core");
785
+ var import_react_native14 = require("react-native");
786
+ var import_jsx_runtime12 = require("react/jsx-runtime");
703
787
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
704
- const { width: windowWidth } = (0, import_core5.useRotatedWindowDimensions)();
705
- const { contentWidth, gutterWidth } = (0, import_core5.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
706
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles10.row, style], children: [
707
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: leftGutter }),
708
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: { width: contentWidth }, children }),
709
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native12.View, { style: [styles10.gutter, { width: gutterWidth }], children: rightGutter })
788
+ const { width: windowWidth } = (0, import_core6.useRotatedWindowDimensions)();
789
+ const { contentWidth, gutterWidth } = (0, import_core6.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
790
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native14.View, { style: [styles11.row, style], children: [
791
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native14.View, { style: [styles11.gutter, { width: gutterWidth }], children: leftGutter }),
792
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native14.View, { style: { width: contentWidth }, children }),
793
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native14.View, { style: [styles11.gutter, { width: gutterWidth }], children: rightGutter })
710
794
  ] });
711
795
  }
712
- var styles10 = import_react_native12.StyleSheet.create({
796
+ var styles11 = import_react_native14.StyleSheet.create({
713
797
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
714
798
  // column instead of clipping cleanly at its own real width.
715
799
  gutter: {
@@ -722,15 +806,15 @@ var styles10 = import_react_native12.StyleSheet.create({
722
806
 
723
807
  // src/CornerActionButtons.tsx
724
808
  var import_feedback_press4 = require("@rific/feedback-press");
725
- var import_react_native13 = require("react-native");
726
- var import_jsx_runtime12 = require("react/jsx-runtime");
809
+ var import_react_native15 = require("react-native");
810
+ var import_jsx_runtime13 = require("react/jsx-runtime");
727
811
  function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back", hitSlop }) {
728
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
729
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press4.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles11.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
730
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press4.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles11.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
812
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
813
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press4.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles12.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
814
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press4.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles12.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
731
815
  ] });
732
816
  }
733
- var styles11 = import_react_native13.StyleSheet.create({
817
+ var styles12 = import_react_native15.StyleSheet.create({
734
818
  back: {
735
819
  position: "absolute"
736
820
  },
@@ -740,10 +824,10 @@ var styles11 = import_react_native13.StyleSheet.create({
740
824
  });
741
825
 
742
826
  // src/StaggeredWord.tsx
743
- var import_react6 = require("react");
744
- var import_react_native14 = require("react-native");
827
+ var import_react7 = require("react");
828
+ var import_react_native16 = require("react-native");
745
829
  var import_react_native_reanimated = __toESM(require("react-native-reanimated"));
746
- var import_jsx_runtime13 = require("react/jsx-runtime");
830
+ var import_jsx_runtime14 = require("react/jsx-runtime");
747
831
  var STAGGER_MS = 45;
748
832
  var LETTER_DURATION_MS = 320;
749
833
  function getStaggeredWordDuration(letterCount) {
@@ -751,7 +835,7 @@ function getStaggeredWordDuration(letterCount) {
751
835
  }
752
836
  function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }) {
753
837
  const progress = (0, import_react_native_reanimated.useSharedValue)(reducedMotion ? 1 : 0);
754
- (0, import_react6.useEffect)(() => {
838
+ (0, import_react7.useEffect)(() => {
755
839
  if (reducedMotion) return;
756
840
  progress.value = (0, import_react_native_reanimated.withDelay)(index * STAGGER_MS, (0, import_react_native_reanimated.withTiming)(1, { duration: LETTER_DURATION_MS, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.back(1.5)) }));
757
841
  }, [reducedMotion]);
@@ -759,12 +843,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
759
843
  opacity: progress.value,
760
844
  transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
761
845
  }));
762
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_reanimated.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
846
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_reanimated.default.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
763
847
  }
764
848
  function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
765
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, { style: [styles12.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
849
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native16.View, { style: [styles13.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
766
850
  }
767
- var styles12 = import_react_native14.StyleSheet.create({
851
+ var styles13 = import_react_native16.StyleSheet.create({
768
852
  row: {
769
853
  flexDirection: "row"
770
854
  }
@@ -772,12 +856,12 @@ var styles12 = import_react_native14.StyleSheet.create({
772
856
 
773
857
  // src/UpdateDialog.tsx
774
858
  var import_updater2 = require("@rific/updater");
775
- var import_jsx_runtime14 = require("react/jsx-runtime");
859
+ var import_jsx_runtime15 = require("react/jsx-runtime");
776
860
  function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
777
861
  const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
778
862
  (0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
779
863
  const date = manifest ? new Date(manifest.createdAt) : null;
780
- return /* @__PURE__ */ (0, import_jsx_runtime14.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) });
864
+ return /* @__PURE__ */ (0, import_jsx_runtime15.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) });
781
865
  }
782
866
  // Annotate the CommonJS export names for ESM import in node:
783
867
  0 && (module.exports = {
@@ -786,9 +870,11 @@ function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onErr
786
870
  ActivityStatSection,
787
871
  BaseSettingsDialog,
788
872
  BaseStatsScreen,
873
+ COMPACT_DIALOG_HEIGHT,
789
874
  ConfirmDialog,
790
875
  ContentGutter,
791
876
  CornerActionButtons,
877
+ DialogHeader,
792
878
  LOCKED_BADGE_COLOR,
793
879
  MONO_FONT,
794
880
  OverlayBackdrop,
@@ -798,9 +884,10 @@ function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onErr
798
884
  StatRow,
799
885
  StatSection,
800
886
  UpdateDialog,
801
- getOverlayCardColors,
802
887
  getStaggeredWordDuration,
888
+ isCompactDialogHeight,
803
889
  overlayActionStyles,
804
890
  overlayStyles,
891
+ useCompactDialog,
805
892
  useOverlayCardColors
806
893
  });