@tastic/hud 0.8.3 → 0.8.5
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.d.mts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +206 -160
- package/dist/index.mjs +185 -140
- package/package.json +4 -3
- package/src/BaseSettingsDialog.tsx +12 -27
- package/src/ConfirmDialog.tsx +38 -16
- package/src/UpdateDialog.tsx +28 -0
- package/src/index.ts +1 -0
- package/src/useUpdateConfirmBridge.ts +30 -0
package/dist/index.d.mts
CHANGED
|
@@ -64,11 +64,11 @@ declare function BaseStatsScreen({ rotation: rotationOverride, title, titleVaria
|
|
|
64
64
|
interface ConfirmDialogProps {
|
|
65
65
|
visible: boolean;
|
|
66
66
|
title: string;
|
|
67
|
-
message:
|
|
67
|
+
message: ReactNode;
|
|
68
68
|
confirmLabel: string;
|
|
69
|
-
cancelLabel
|
|
69
|
+
cancelLabel?: string;
|
|
70
70
|
onConfirm: () => void;
|
|
71
|
-
onCancel
|
|
71
|
+
onCancel?: () => void;
|
|
72
72
|
rotation?: ViewRotation;
|
|
73
73
|
icon?: string;
|
|
74
74
|
destructive?: boolean;
|
|
@@ -337,4 +337,12 @@ interface TriggerGaugeProps {
|
|
|
337
337
|
|
|
338
338
|
declare function TriggerGaugeHost(props: TriggerGaugeProps): react.JSX.Element;
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
interface UpdateDialogProps {
|
|
341
|
+
rotation?: ViewRotation;
|
|
342
|
+
autoCheck?: boolean;
|
|
343
|
+
autoPrompt?: boolean;
|
|
344
|
+
onError?: (message: string) => void;
|
|
345
|
+
}
|
|
346
|
+
declare function UpdateDialog({ rotation, autoCheck, autoPrompt, onError }: UpdateDialogProps): react.JSX.Element;
|
|
347
|
+
|
|
348
|
+
export { AchievementRow, BaseSettingsDialog, type BaseSettingsDialogProps, BaseStatsScreen, ConfirmDialog, type ConfirmDialogProps, ContentGutter, ControlSchemePicker, type ControlSchemePickerProps, CornerActionButtons, type CornerStatusBadgeSeat, CornerStatusBadges, type CornerStatusBadgesProps, InlineColorPicker, LABELED_DROPDOWN_POPOVER_WIDTH, LOCKED_BADGE_COLOR, LabeledDropdown, type LabeledDropdownOption, MONO_FONT, type MenuOption, type MenuSection, type MultiSelectSection, type OrientationMode, type OverlayCardColors, type PopoverAlign, PopoverBody, type PopoverHost, type PopoverRotation, type PopoverVerticalAlign, PressAwayOverlay, ReadyButton, SectionedDropdown, SharedActionBand, type SingleSelectSection, StatRow, StatSection, TriggerGaugeHost, type TriggerGaugeProps, UpdateDialog, type UpdateDialogProps, getLabeledDropdownContentHeight, getOverlayCardColors, loadSkiaWeb, overlayStyles, useAutoAlign, usePopoverHost };
|
package/dist/index.d.ts
CHANGED
|
@@ -64,11 +64,11 @@ declare function BaseStatsScreen({ rotation: rotationOverride, title, titleVaria
|
|
|
64
64
|
interface ConfirmDialogProps {
|
|
65
65
|
visible: boolean;
|
|
66
66
|
title: string;
|
|
67
|
-
message:
|
|
67
|
+
message: ReactNode;
|
|
68
68
|
confirmLabel: string;
|
|
69
|
-
cancelLabel
|
|
69
|
+
cancelLabel?: string;
|
|
70
70
|
onConfirm: () => void;
|
|
71
|
-
onCancel
|
|
71
|
+
onCancel?: () => void;
|
|
72
72
|
rotation?: ViewRotation;
|
|
73
73
|
icon?: string;
|
|
74
74
|
destructive?: boolean;
|
|
@@ -337,4 +337,12 @@ interface TriggerGaugeProps {
|
|
|
337
337
|
|
|
338
338
|
declare function TriggerGaugeHost(props: TriggerGaugeProps): react.JSX.Element;
|
|
339
339
|
|
|
340
|
-
|
|
340
|
+
interface UpdateDialogProps {
|
|
341
|
+
rotation?: ViewRotation;
|
|
342
|
+
autoCheck?: boolean;
|
|
343
|
+
autoPrompt?: boolean;
|
|
344
|
+
onError?: (message: string) => void;
|
|
345
|
+
}
|
|
346
|
+
declare function UpdateDialog({ rotation, autoCheck, autoPrompt, onError }: UpdateDialogProps): react.JSX.Element;
|
|
347
|
+
|
|
348
|
+
export { AchievementRow, BaseSettingsDialog, type BaseSettingsDialogProps, BaseStatsScreen, ConfirmDialog, type ConfirmDialogProps, ContentGutter, ControlSchemePicker, type ControlSchemePickerProps, CornerActionButtons, type CornerStatusBadgeSeat, CornerStatusBadges, type CornerStatusBadgesProps, InlineColorPicker, LABELED_DROPDOWN_POPOVER_WIDTH, LOCKED_BADGE_COLOR, LabeledDropdown, type LabeledDropdownOption, MONO_FONT, type MenuOption, type MenuSection, type MultiSelectSection, type OrientationMode, type OverlayCardColors, type PopoverAlign, PopoverBody, type PopoverHost, type PopoverRotation, type PopoverVerticalAlign, PressAwayOverlay, ReadyButton, SectionedDropdown, SharedActionBand, type SingleSelectSection, StatRow, StatSection, TriggerGaugeHost, type TriggerGaugeProps, UpdateDialog, type UpdateDialogProps, getLabeledDropdownContentHeight, getOverlayCardColors, loadSkiaWeb, overlayStyles, useAutoAlign, usePopoverHost };
|
package/dist/index.js
CHANGED
|
@@ -28,22 +28,22 @@ __export(TriggerGauge_exports, {
|
|
|
28
28
|
function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, dashWidth, startDeg = DEFAULT_START_DEG, endDeg = startDeg }) {
|
|
29
29
|
const totalDurationMs = MOUNT_DURATION_MS + Math.max(0, segments - 1) * MOUNT_STAGGER_MS;
|
|
30
30
|
const mountProgress = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
31
|
-
(0,
|
|
31
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
32
32
|
mountProgress.value = (0, import_react_native_reanimated.withTiming)(1, { duration: totalDurationMs, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
|
|
33
33
|
}, []);
|
|
34
34
|
const rawSweepDeg = ((endDeg - startDeg) % 360 + 360) % 360;
|
|
35
35
|
const totalSweepDeg = rawSweepDeg === 0 ? 360 : rawSweepDeg;
|
|
36
36
|
const step = segments > 0 ? totalSweepDeg / segments : 0;
|
|
37
|
-
const centerDeg = (0,
|
|
37
|
+
const centerDeg = (0, import_react5.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
|
|
38
38
|
const singleSelect = litIndices.length === 1;
|
|
39
39
|
const angleDeg = (0, import_react_native_reanimated.useSharedValue)(centerDeg(litIndices[0] ?? 0));
|
|
40
40
|
const litIndicesKey = [...litIndices].sort((a, b) => a - b).join(",");
|
|
41
|
-
const [transitionFrom, setTransitionFrom] = (0,
|
|
41
|
+
const [transitionFrom, setTransitionFrom] = (0, import_react5.useState)(litIndices);
|
|
42
42
|
const transitionFromKey = [...transitionFrom].sort((a, b) => a - b).join(",");
|
|
43
|
-
const lastKeyRef = (0,
|
|
44
|
-
const lastIndicesRef = (0,
|
|
43
|
+
const lastKeyRef = (0, import_react5.useRef)(litIndicesKey);
|
|
44
|
+
const lastIndicesRef = (0, import_react5.useRef)(litIndices);
|
|
45
45
|
const selectionProgress = (0, import_react_native_reanimated.useSharedValue)(1);
|
|
46
|
-
(0,
|
|
46
|
+
(0, import_react5.useLayoutEffect)(() => {
|
|
47
47
|
if (litIndicesKey !== lastKeyRef.current) {
|
|
48
48
|
if (singleSelect && lastIndicesRef.current.length === 1) {
|
|
49
49
|
angleDeg.value = (0, import_react_native_reanimated.withTiming)(centerDeg(litIndices[0]), { duration: SELECTION_TRANSITION_DURATION_MS, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
|
|
@@ -125,13 +125,13 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
125
125
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
|
|
126
126
|
] }) });
|
|
127
127
|
}
|
|
128
|
-
var import_react_native_skia, import_core5,
|
|
128
|
+
var import_react_native_skia, import_core5, import_react5, import_react_native9, import_react_native_reanimated, import_jsx_runtime8, 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, styles7;
|
|
129
129
|
var init_TriggerGauge = __esm({
|
|
130
130
|
"src/TriggerGauge.tsx"() {
|
|
131
131
|
"use strict";
|
|
132
132
|
import_react_native_skia = require("@shopify/react-native-skia");
|
|
133
133
|
import_core5 = require("@tastic/core");
|
|
134
|
-
|
|
134
|
+
import_react5 = require("react");
|
|
135
135
|
import_react_native9 = require("react-native");
|
|
136
136
|
import_react_native_reanimated = require("react-native-reanimated");
|
|
137
137
|
import_jsx_runtime8 = require("react/jsx-runtime");
|
|
@@ -179,6 +179,7 @@ __export(index_exports, {
|
|
|
179
179
|
StatRow: () => StatRow,
|
|
180
180
|
StatSection: () => StatSection,
|
|
181
181
|
TriggerGaugeHost: () => TriggerGaugeHost,
|
|
182
|
+
UpdateDialog: () => UpdateDialog,
|
|
182
183
|
getLabeledDropdownContentHeight: () => getLabeledDropdownContentHeight,
|
|
183
184
|
getOverlayCardColors: () => getOverlayCardColors,
|
|
184
185
|
loadSkiaWeb: () => loadSkiaWeb,
|
|
@@ -257,11 +258,18 @@ var styles = import_react_native.StyleSheet.create({
|
|
|
257
258
|
});
|
|
258
259
|
|
|
259
260
|
// src/BaseSettingsDialog.tsx
|
|
261
|
+
var import_auto_paper3 = require("@rific/auto-paper");
|
|
262
|
+
var import_feedback_press2 = require("@rific/feedback-press");
|
|
263
|
+
var import_updater = require("@rific/updater");
|
|
264
|
+
var import_core2 = require("@tastic/core");
|
|
265
|
+
var import_react2 = require("react");
|
|
266
|
+
var import_react_native4 = require("react-native");
|
|
267
|
+
var import_react_native_paper3 = require("react-native-paper");
|
|
268
|
+
|
|
269
|
+
// src/ConfirmDialog.tsx
|
|
260
270
|
var import_auto_paper2 = require("@rific/auto-paper");
|
|
261
271
|
var import_feedback_press = require("@rific/feedback-press");
|
|
262
|
-
var import_updater = require("@rific/updater");
|
|
263
272
|
var import_core = require("@tastic/core");
|
|
264
|
-
var import_react = require("react");
|
|
265
273
|
var import_react_native3 = require("react-native");
|
|
266
274
|
var import_react_native_paper2 = require("react-native-paper");
|
|
267
275
|
|
|
@@ -296,56 +304,164 @@ var overlayStyles = import_react_native2.StyleSheet.create({
|
|
|
296
304
|
}
|
|
297
305
|
});
|
|
298
306
|
|
|
299
|
-
// src/
|
|
307
|
+
// src/ConfirmDialog.tsx
|
|
300
308
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
309
|
+
function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
|
|
310
|
+
const { dark, colors } = (0, import_auto_paper2.useAutoPaperTheme)();
|
|
311
|
+
if (!visible) return null;
|
|
312
|
+
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
|
|
313
|
+
const accent = destructive ? colors.danger : colors.primary;
|
|
314
|
+
const onAccent = destructive ? colors.onDanger : colors.onPrimary;
|
|
315
|
+
const showCancel = cancelLabel !== void 0 && onCancel !== void 0;
|
|
316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [overlayStyles.overlay, styles2.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: [overlayStyles.card, styles2.card, { backgroundColor: cardBg, borderColor: cardBorder }, (0, import_core.toRotationStyle)(rotation)], children: [
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: icon, size: 64, color: accent }),
|
|
318
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { variant: "headlineLarge", style: [styles2.title, { color: accent }], children: title }),
|
|
319
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { variant: "bodyLarge", style: [styles2.body, { color: fg }], children: message }),
|
|
320
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native3.View, { style: styles2.actions, children: [
|
|
321
|
+
showCancel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: onCancel, style: styles2.actionButton, children: cancelLabel }),
|
|
322
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.Button, { mode: "contained", onPress: onConfirm, style: showCancel ? styles2.actionButton : styles2.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
|
|
323
|
+
] })
|
|
324
|
+
] }) }) });
|
|
325
|
+
}
|
|
326
|
+
var styles2 = import_react_native3.StyleSheet.create({
|
|
327
|
+
// minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
|
|
328
|
+
// still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
|
|
329
|
+
// on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
|
|
330
|
+
// row instead (see actions' flexWrap below). This used to be flexBasis: 128, which measured
|
|
331
|
+
// correctly on web but rendered every button roughly SQUARE on iOS - confirmed live (see the
|
|
332
|
+
// "Quit Match?" Cancel/Quit buttons and the single-button "OK" dialogs both coming out ~128pt
|
|
333
|
+
// tall instead of wide). Root cause: react-native-paper's Button renders its Surface as two
|
|
334
|
+
// nested views on iOS only (Surface.tsx's SurfaceIOS, for shadow rendering) - only a curated
|
|
335
|
+
// allowlist of style keys (flex/flexGrow/flexShrink/width/height/position/... - notably NOT
|
|
336
|
+
// flexBasis) reaches the outer view, which is the real flex item inside this row; every other
|
|
337
|
+
// key, flexBasis included, falls through to an inner view whose own unspecified flexDirection
|
|
338
|
+
// defaults to column. flexGrow: 1 landed on the (row-context) outer view and grew width
|
|
339
|
+
// correctly; flexBasis: 128 landed on the (column-context) inner view instead, where a flexBasis
|
|
340
|
+
// sets HEIGHT, not width. minWidth isn't axis-relative like flexBasis, so it constrains width
|
|
341
|
+
// correctly regardless of which of the two views it ends up on. react-native-paper's Button also
|
|
342
|
+
// hardcodes numberOfLines={1} on its label with no override, so a button squeezed under its
|
|
343
|
+
// label's natural width silently ellipsizes ("Cancel" -> "Can...") instead of wrapping - assumed
|
|
344
|
+
// fixable by just giving the row more width, until confirmed live that these two-word labels
|
|
345
|
+
// (Cancel/Reset/New Game) can still lose the truncation fight even with the extra room card's own
|
|
346
|
+
// width fix below provides, on a narrow enough screen.
|
|
347
|
+
actionButton: {
|
|
348
|
+
flexGrow: 1,
|
|
349
|
+
minWidth: 128
|
|
350
|
+
},
|
|
351
|
+
// A lone confirm button (no cancel - BaseSettingsDialog's info-only "OK" dialogs, e.g. the
|
|
352
|
+
// update-check "no update found" message) has nothing left to share actions' width with, so
|
|
353
|
+
// actionButton's own flexGrow: 1 would stretch it across the entire row instead of reading as a
|
|
354
|
+
// normal button. Same 128 floor, no flexGrow, so it stays at that natural size instead of filling
|
|
355
|
+
// the card - centered by actions' own justifyContent below.
|
|
356
|
+
actionButtonSingle: {
|
|
357
|
+
minWidth: 128
|
|
358
|
+
},
|
|
359
|
+
actions: {
|
|
360
|
+
flexDirection: "row",
|
|
361
|
+
flexWrap: "wrap",
|
|
362
|
+
gap: 12,
|
|
363
|
+
justifyContent: "center",
|
|
364
|
+
width: "100%"
|
|
365
|
+
},
|
|
366
|
+
body: {
|
|
367
|
+
textAlign: "center"
|
|
368
|
+
},
|
|
369
|
+
// Additive on top of overlayCard's own shared `card` shape (borderRadius/borderWidth/gap/maxWidth/
|
|
370
|
+
// padding) — claims its full allowance instead of just maxWidth alone, which only caps how wide the
|
|
371
|
+
// card is allowed to get - without an explicit width, a flex-centered child sizes to its own content
|
|
372
|
+
// instead of stretching, so the card (and therefore actions below) can end up narrower than the
|
|
373
|
+
// screen actually has room for, needlessly forcing the action row to wrap sooner than it has to.
|
|
374
|
+
card: {
|
|
375
|
+
width: "100%"
|
|
376
|
+
},
|
|
377
|
+
// Additive on top of overlayCard's own shared `overlay` backdrop — gives the card room to breathe
|
|
378
|
+
// from the screen edges now that it reliably stretches to fill its full width allowance (see
|
|
379
|
+
// card's own width comment) - without this, width: '100%' would run the card edge-to-edge on a
|
|
380
|
+
// screen narrower than maxWidth's own 360.
|
|
381
|
+
overlay: {
|
|
382
|
+
paddingHorizontal: 24
|
|
383
|
+
},
|
|
384
|
+
// textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
|
|
385
|
+
// within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
|
|
386
|
+
// line inside that block still defaults to left-aligned without this.
|
|
387
|
+
title: {
|
|
388
|
+
fontWeight: "bold",
|
|
389
|
+
textAlign: "center"
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// src/useUpdateConfirmBridge.ts
|
|
394
|
+
var import_react = require("react");
|
|
395
|
+
function useUpdateConfirmBridge() {
|
|
396
|
+
const [manifest, setManifest] = (0, import_react.useState)(null);
|
|
397
|
+
const resolveRef = (0, import_react.useRef)(null);
|
|
398
|
+
const onConfirm = (0, import_react.useCallback)(
|
|
399
|
+
(next) => new Promise((resolve) => {
|
|
400
|
+
resolveRef.current = resolve;
|
|
401
|
+
setManifest(next);
|
|
402
|
+
}),
|
|
403
|
+
[]
|
|
404
|
+
);
|
|
405
|
+
const respond = (0, import_react.useCallback)((confirmed) => {
|
|
406
|
+
setManifest(null);
|
|
407
|
+
resolveRef.current?.(confirmed);
|
|
408
|
+
resolveRef.current = null;
|
|
409
|
+
}, []);
|
|
410
|
+
return { manifest, onConfirm, respond };
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/BaseSettingsDialog.tsx
|
|
414
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
301
415
|
function SettingIcon({ source, color, containerColor }) {
|
|
302
|
-
return /* @__PURE__ */ (0,
|
|
416
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Icon, { source, size: 18, color }) });
|
|
303
417
|
}
|
|
304
418
|
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
|
|
305
|
-
const {
|
|
306
|
-
const ambientRotation = (0,
|
|
419
|
+
const { colors } = (0, import_auto_paper3.useAutoPaperTheme)();
|
|
420
|
+
const ambientRotation = (0, import_core2.useRotation)();
|
|
307
421
|
const rotation = rotationOverride ?? ambientRotation;
|
|
308
|
-
const isTouchPrimary = (0,
|
|
309
|
-
const { settings: hapticSettings, set: setHapticSettings } = (0,
|
|
310
|
-
const { settings: soundSettings, set: setSoundSettings } = (0,
|
|
311
|
-
const sound = (0,
|
|
312
|
-
const { forceShort: forceHapticFeedback } = (0,
|
|
313
|
-
const [infoMessage, setInfoMessage] = (0,
|
|
422
|
+
const isTouchPrimary = (0, import_core2.useIsTouchPrimaryDevice)();
|
|
423
|
+
const { settings: hapticSettings, set: setHapticSettings } = (0, import_feedback_press2.useHapticSettings)();
|
|
424
|
+
const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press2.useSoundSettings)();
|
|
425
|
+
const sound = (0, import_react2.useContext)(import_feedback_press2.SoundContext);
|
|
426
|
+
const { forceShort: forceHapticFeedback } = (0, import_feedback_press2.useVibration)();
|
|
427
|
+
const [infoMessage, setInfoMessage] = (0, import_react2.useState)(null);
|
|
428
|
+
const { manifest: updateManifest, onConfirm: onUpdateConfirm, respond: respondToUpdateConfirm } = useUpdateConfirmBridge();
|
|
314
429
|
const { check, checking, updateReady } = (0, import_updater.useUpdater)({
|
|
315
430
|
autoCheck: false,
|
|
316
431
|
autoPrompt: false,
|
|
432
|
+
onConfirm: onUpdateConfirm,
|
|
317
433
|
onError: onUpdateError,
|
|
318
434
|
onInfo: (title, message) => setInfoMessage({ title, message })
|
|
319
435
|
});
|
|
436
|
+
const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
|
|
320
437
|
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
321
|
-
const showEdgeGuard =
|
|
322
|
-
const showHaptics =
|
|
438
|
+
const showEdgeGuard = import_react_native4.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
439
|
+
const showHaptics = import_react_native4.Platform.OS !== "web" && !hideHaptics;
|
|
323
440
|
const showSound = !hideSound;
|
|
324
441
|
const showAppearance = !hideAppearance;
|
|
325
|
-
const showUpdateCheck =
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
/* @__PURE__ */ (0,
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
/* @__PURE__ */ (0,
|
|
334
|
-
|
|
335
|
-
/* @__PURE__ */ (0,
|
|
336
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
|
|
442
|
+
const showUpdateCheck = import_react_native4.Platform.OS !== "web" && !hideUpdateCheck;
|
|
443
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_auto_paper3.Dialog, { visible, onDismiss, style: [styles3.dialog, (0, import_core2.toRotationStyle)(rotation)], children: [
|
|
445
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_auto_paper3.Dialog.Title, { children: "Settings" }),
|
|
446
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_auto_paper3.Dialog.ScrollArea, { style: styles3.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.ScrollView, { contentContainerStyle: styles3.content, showsVerticalScrollIndicator: false, children: [
|
|
447
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.toggleGroup, children: [
|
|
448
|
+
showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles3.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.toggleContent, children: [
|
|
449
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
|
|
450
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.flexShrink, children: [
|
|
451
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
|
|
452
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
|
|
337
453
|
] })
|
|
338
454
|
] }) }),
|
|
339
|
-
showEdgeGuard && /* @__PURE__ */ (0,
|
|
340
|
-
/* @__PURE__ */ (0,
|
|
341
|
-
/* @__PURE__ */ (0,
|
|
342
|
-
/* @__PURE__ */ (0,
|
|
343
|
-
/* @__PURE__ */ (0,
|
|
455
|
+
showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press2.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles3.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.toggleContent, children: [
|
|
456
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
|
|
457
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.flexShrink, children: [
|
|
458
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
|
|
459
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
|
|
344
460
|
] })
|
|
345
461
|
] }) }),
|
|
346
|
-
(showSound || showHaptics) && /* @__PURE__ */ (0,
|
|
347
|
-
showSound && /* @__PURE__ */ (0,
|
|
348
|
-
|
|
462
|
+
(showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.toggleRow, children: [
|
|
463
|
+
showSound && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
464
|
+
import_feedback_press2.TouchableRipple,
|
|
349
465
|
{
|
|
350
466
|
soundDisabled: true,
|
|
351
467
|
onPress: () => {
|
|
@@ -353,16 +469,16 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
353
469
|
setSoundSettings({ enabled });
|
|
354
470
|
if (enabled) sound.selection?.();
|
|
355
471
|
},
|
|
356
|
-
style:
|
|
472
|
+
style: styles3.toggleButtonInRow,
|
|
357
473
|
accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
|
|
358
|
-
children: /* @__PURE__ */ (0,
|
|
359
|
-
/* @__PURE__ */ (0,
|
|
360
|
-
/* @__PURE__ */ (0,
|
|
474
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.toggleContent, children: [
|
|
475
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
476
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
|
|
361
477
|
] })
|
|
362
478
|
}
|
|
363
479
|
),
|
|
364
|
-
showHaptics && /* @__PURE__ */ (0,
|
|
365
|
-
|
|
480
|
+
showHaptics && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
481
|
+
import_feedback_press2.TouchableRipple,
|
|
366
482
|
{
|
|
367
483
|
hapticDisabled: true,
|
|
368
484
|
onPress: () => {
|
|
@@ -370,40 +486,36 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
370
486
|
setHapticSettings({ vibrate });
|
|
371
487
|
if (vibrate) forceHapticFeedback();
|
|
372
488
|
},
|
|
373
|
-
style:
|
|
489
|
+
style: styles3.toggleButtonInRow,
|
|
374
490
|
accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
|
|
375
|
-
children: /* @__PURE__ */ (0,
|
|
376
|
-
/* @__PURE__ */ (0,
|
|
377
|
-
/* @__PURE__ */ (0,
|
|
491
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.toggleContent, children: [
|
|
492
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
493
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
|
|
378
494
|
] })
|
|
379
495
|
}
|
|
380
496
|
)
|
|
381
497
|
] })
|
|
382
498
|
] }),
|
|
383
|
-
showAppearance && /* @__PURE__ */ (0,
|
|
384
|
-
/* @__PURE__ */ (0,
|
|
385
|
-
/* @__PURE__ */ (0,
|
|
499
|
+
showAppearance && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.section, children: [
|
|
500
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "labelMedium", style: [styles3.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
|
|
501
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_auto_paper3.AutoAppearancePicker, { showLabels: false })
|
|
386
502
|
] }),
|
|
387
503
|
children,
|
|
388
|
-
showUpdateCheck && /* @__PURE__ */ (0,
|
|
389
|
-
/* @__PURE__ */ (0,
|
|
504
|
+
showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.section, children: [
|
|
505
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native_paper3.Text, { variant: "labelSmall", style: [styles3.sectionLabel, { color: colors.onSurfaceVariant }], children: [
|
|
390
506
|
"VERSION ",
|
|
391
507
|
version,
|
|
392
508
|
updateReady ? " \xB7 UPDATE READY" : ""
|
|
393
509
|
] }),
|
|
394
|
-
/* @__PURE__ */ (0,
|
|
510
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
|
|
395
511
|
] })
|
|
396
512
|
] }) })
|
|
397
513
|
] }),
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { variant: "headlineLarge", style: [styles2.overlayTitle, { color: colors.secondary }], children: infoMessage.title }),
|
|
401
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { variant: "bodyLarge", style: [styles2.overlayBody, { color: fg }], children: infoMessage.message }),
|
|
402
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press.Button, { mode: "contained", onPress: () => setInfoMessage(null), style: styles2.overlayButton, buttonColor: colors.primary, textColor: colors.onPrimary, children: "OK" })
|
|
403
|
-
] }) }) })
|
|
514
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.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) }),
|
|
515
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ConfirmDialog, { visible: !!infoMessage, title: infoMessage?.title ?? "", message: infoMessage?.message ?? "", confirmLabel: "OK", icon: "information-outline", rotation, onConfirm: () => setInfoMessage(null) })
|
|
404
516
|
] });
|
|
405
517
|
}
|
|
406
|
-
var
|
|
518
|
+
var styles3 = import_react_native4.StyleSheet.create({
|
|
407
519
|
content: {
|
|
408
520
|
gap: 24,
|
|
409
521
|
paddingVertical: 20
|
|
@@ -425,9 +537,6 @@ var styles2 = import_react_native3.StyleSheet.create({
|
|
|
425
537
|
justifyContent: "center",
|
|
426
538
|
width: 36
|
|
427
539
|
},
|
|
428
|
-
overlayBody: { textAlign: "center" },
|
|
429
|
-
overlayButton: { width: 160 },
|
|
430
|
-
overlayTitle: { fontWeight: "bold" },
|
|
431
540
|
scrollArea: {
|
|
432
541
|
marginBottom: 0
|
|
433
542
|
},
|
|
@@ -477,89 +586,15 @@ var styles2 = import_react_native3.StyleSheet.create({
|
|
|
477
586
|
var import_auto_paper4 = require("@rific/auto-paper");
|
|
478
587
|
var import_feedback_press3 = require("@rific/feedback-press");
|
|
479
588
|
var import_core3 = require("@tastic/core");
|
|
480
|
-
var
|
|
589
|
+
var import_react3 = require("react");
|
|
481
590
|
var import_react_native5 = require("react-native");
|
|
482
591
|
var import_react_native_paper4 = require("react-native-paper");
|
|
483
|
-
|
|
484
|
-
// src/ConfirmDialog.tsx
|
|
485
|
-
var import_auto_paper3 = require("@rific/auto-paper");
|
|
486
|
-
var import_feedback_press2 = require("@rific/feedback-press");
|
|
487
|
-
var import_core2 = require("@tastic/core");
|
|
488
|
-
var import_react_native4 = require("react-native");
|
|
489
|
-
var import_react_native_paper3 = require("react-native-paper");
|
|
490
|
-
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
491
|
-
function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
|
|
492
|
-
const { dark, colors } = (0, import_auto_paper3.useAutoPaperTheme)();
|
|
493
|
-
if (!visible) return null;
|
|
494
|
-
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
|
|
495
|
-
const accent = destructive ? colors.danger : colors.primary;
|
|
496
|
-
const onAccent = destructive ? colors.onDanger : colors.onPrimary;
|
|
497
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [overlayStyles.overlay, styles3.overlay], children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: [overlayStyles.card, styles3.card, { backgroundColor: cardBg, borderColor: cardBorder }, (0, import_core2.toRotationStyle)(rotation)], children: [
|
|
498
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Icon, { source: icon, size: 64, color: accent }),
|
|
499
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "headlineLarge", style: [styles3.title, { color: accent }], children: title }),
|
|
500
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper3.Text, { variant: "bodyLarge", style: [styles3.body, { color: fg }], children: message }),
|
|
501
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: styles3.actions, children: [
|
|
502
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press2.Button, { mode: "outlined", onPress: onCancel, style: styles3.actionButton, children: cancelLabel }),
|
|
503
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press2.Button, { mode: "contained", onPress: onConfirm, style: styles3.actionButton, buttonColor: accent, textColor: onAccent, children: confirmLabel })
|
|
504
|
-
] })
|
|
505
|
-
] }) }) });
|
|
506
|
-
}
|
|
507
|
-
var styles3 = import_react_native4.StyleSheet.create({
|
|
508
|
-
// flexBasis (not flex: 1's own 0%) is each button's real floor: whenever both fit side by side,
|
|
509
|
-
// flexGrow still splits any leftover width evenly beyond that floor, same visual result as the
|
|
510
|
-
// old flex: 1 on a roomy screen - but a button can never be squeezed narrower than 128, only
|
|
511
|
-
// wrap to its own row instead (see actions' flexWrap below). react-native-paper's Button
|
|
512
|
-
// hardcodes numberOfLines={1} on its label with no override, so a button squeezed under its
|
|
513
|
-
// label's natural width silently ellipsizes ("Cancel" -> "Can...") instead of wrapping - assumed
|
|
514
|
-
// fixable by just giving the row more width, until confirmed live that these two-word labels
|
|
515
|
-
// (Cancel/Reset/New Game) can still lose the truncation fight even with the extra room card's own
|
|
516
|
-
// width fix below provides, on a narrow enough screen. flexBasis is the real fix: past a certain
|
|
517
|
-
// width there's no side-by-side arrangement that fits both buttons at their natural label size,
|
|
518
|
-
// so the layout has to give (stack) rather than the label (truncate).
|
|
519
|
-
actionButton: {
|
|
520
|
-
flexBasis: 128,
|
|
521
|
-
flexGrow: 1
|
|
522
|
-
},
|
|
523
|
-
actions: {
|
|
524
|
-
flexDirection: "row",
|
|
525
|
-
flexWrap: "wrap",
|
|
526
|
-
gap: 12,
|
|
527
|
-
width: "100%"
|
|
528
|
-
},
|
|
529
|
-
body: {
|
|
530
|
-
textAlign: "center"
|
|
531
|
-
},
|
|
532
|
-
// Additive on top of overlayCard's own shared `card` shape (borderRadius/borderWidth/gap/maxWidth/
|
|
533
|
-
// padding) — claims its full allowance instead of just maxWidth alone, which only caps how wide the
|
|
534
|
-
// card is allowed to get - without an explicit width, a flex-centered child sizes to its own content
|
|
535
|
-
// instead of stretching, so the card (and therefore actions below) can end up narrower than the
|
|
536
|
-
// screen actually has room for, needlessly forcing the action row to wrap sooner than it has to.
|
|
537
|
-
card: {
|
|
538
|
-
width: "100%"
|
|
539
|
-
},
|
|
540
|
-
// Additive on top of overlayCard's own shared `overlay` backdrop — gives the card room to breathe
|
|
541
|
-
// from the screen edges now that it reliably stretches to fill its full width allowance (see
|
|
542
|
-
// card's own width comment) - without this, width: '100%' would run the card edge-to-edge on a
|
|
543
|
-
// screen narrower than maxWidth's own 360.
|
|
544
|
-
overlay: {
|
|
545
|
-
paddingHorizontal: 24
|
|
546
|
-
},
|
|
547
|
-
// textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
|
|
548
|
-
// within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
|
|
549
|
-
// line inside that block still defaults to left-aligned without this.
|
|
550
|
-
title: {
|
|
551
|
-
fontWeight: "bold",
|
|
552
|
-
textAlign: "center"
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
// src/BaseStatsScreen.tsx
|
|
557
592
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
558
593
|
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 }) {
|
|
559
594
|
const { dark, colors } = (0, import_auto_paper4.useAutoPaperTheme)();
|
|
560
595
|
const ambientRotation = (0, import_core3.useRotation)();
|
|
561
596
|
const rotation = rotationOverride ?? ambientRotation;
|
|
562
|
-
const [confirmResetVisible, setConfirmResetVisible] = (0,
|
|
597
|
+
const [confirmResetVisible, setConfirmResetVisible] = (0, import_react3.useState)(false);
|
|
563
598
|
const showReset = !!onReset;
|
|
564
599
|
const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
|
|
565
600
|
const bg = bgOverride ?? (dark ? "#000000" : "#FFFFFF");
|
|
@@ -728,11 +763,11 @@ var styles6 = import_react_native8.StyleSheet.create({
|
|
|
728
763
|
});
|
|
729
764
|
|
|
730
765
|
// src/SkiaGate.tsx
|
|
731
|
-
var
|
|
766
|
+
var import_react4 = require("react");
|
|
732
767
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
733
768
|
function SkiaGate({ getComponent, componentProps, fallback = null }) {
|
|
734
|
-
const [Component, setComponent] = (0,
|
|
735
|
-
(0,
|
|
769
|
+
const [Component, setComponent] = (0, import_react4.useState)(null);
|
|
770
|
+
(0, import_react4.useEffect)(() => {
|
|
736
771
|
let cancelled = false;
|
|
737
772
|
getComponent().then((mod) => {
|
|
738
773
|
if (!cancelled) setComponent(() => mod.default);
|
|
@@ -753,7 +788,7 @@ function TriggerGaugeHost(props) {
|
|
|
753
788
|
}
|
|
754
789
|
|
|
755
790
|
// src/useAutoAlign.ts
|
|
756
|
-
var
|
|
791
|
+
var import_react6 = require("react");
|
|
757
792
|
var import_react_native10 = require("react-native");
|
|
758
793
|
var EDGE_MARGIN = 12;
|
|
759
794
|
function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
|
|
@@ -766,18 +801,18 @@ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
|
|
|
766
801
|
return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
|
|
767
802
|
}
|
|
768
803
|
function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
|
|
769
|
-
const triggerRef = (0,
|
|
804
|
+
const triggerRef = (0, import_react6.useRef)(null);
|
|
770
805
|
const { width: windowWidth, height: windowHeight } = (0, import_react_native10.useWindowDimensions)();
|
|
771
|
-
const [align, setAlign] = (0,
|
|
772
|
-
const [verticalAlign, setVerticalAlign] = (0,
|
|
773
|
-
const [maxHeight, setMaxHeight] = (0,
|
|
774
|
-
const [measured, setMeasured] = (0,
|
|
775
|
-
const [prevOpen, setPrevOpen] = (0,
|
|
806
|
+
const [align, setAlign] = (0, import_react6.useState)("center");
|
|
807
|
+
const [verticalAlign, setVerticalAlign] = (0, import_react6.useState)("below");
|
|
808
|
+
const [maxHeight, setMaxHeight] = (0, import_react6.useState)(contentHeight);
|
|
809
|
+
const [measured, setMeasured] = (0, import_react6.useState)(false);
|
|
810
|
+
const [prevOpen, setPrevOpen] = (0, import_react6.useState)(open);
|
|
776
811
|
if (open !== prevOpen) {
|
|
777
812
|
setPrevOpen(open);
|
|
778
813
|
if (open) setMeasured(false);
|
|
779
814
|
}
|
|
780
|
-
const measure = (0,
|
|
815
|
+
const measure = (0, import_react6.useCallback)(() => {
|
|
781
816
|
triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
|
|
782
817
|
const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
|
|
783
818
|
const centerX = x + triggerWidth / 2;
|
|
@@ -794,7 +829,7 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
|
|
|
794
829
|
setMeasured(true);
|
|
795
830
|
});
|
|
796
831
|
}, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
|
|
797
|
-
(0,
|
|
832
|
+
(0, import_react6.useEffect)(() => {
|
|
798
833
|
if (open) measure();
|
|
799
834
|
}, [open, measure]);
|
|
800
835
|
return { align, maxHeight, measured, triggerRef, verticalAlign };
|
|
@@ -1402,14 +1437,24 @@ var styles16 = import_react_native21.StyleSheet.create({
|
|
|
1402
1437
|
}
|
|
1403
1438
|
});
|
|
1404
1439
|
|
|
1440
|
+
// src/UpdateDialog.tsx
|
|
1441
|
+
var import_updater2 = require("@rific/updater");
|
|
1442
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
1443
|
+
function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
|
|
1444
|
+
const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
|
|
1445
|
+
(0, import_updater2.useUpdater)({ autoCheck, autoPrompt, onConfirm, onError });
|
|
1446
|
+
const date = manifest ? new Date(manifest.createdAt) : null;
|
|
1447
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.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) });
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1405
1450
|
// src/usePopoverHost.ts
|
|
1406
|
-
var
|
|
1451
|
+
var import_react7 = require("react");
|
|
1407
1452
|
function usePopoverHost() {
|
|
1408
|
-
const [openId, setOpenId] = (0,
|
|
1409
|
-
const toggle = (0,
|
|
1453
|
+
const [openId, setOpenId] = (0, import_react7.useState)(null);
|
|
1454
|
+
const toggle = (0, import_react7.useCallback)((id) => {
|
|
1410
1455
|
setOpenId((prev) => prev === id ? null : id);
|
|
1411
1456
|
}, []);
|
|
1412
|
-
const close = (0,
|
|
1457
|
+
const close = (0, import_react7.useCallback)(() => setOpenId(null), []);
|
|
1413
1458
|
return { openId, toggle, close };
|
|
1414
1459
|
}
|
|
1415
1460
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1436,6 +1481,7 @@ function usePopoverHost() {
|
|
|
1436
1481
|
StatRow,
|
|
1437
1482
|
StatSection,
|
|
1438
1483
|
TriggerGaugeHost,
|
|
1484
|
+
UpdateDialog,
|
|
1439
1485
|
getLabeledDropdownContentHeight,
|
|
1440
1486
|
getOverlayCardColors,
|
|
1441
1487
|
loadSkiaWeb,
|