@tastic/hud 0.8.2 → 0.8.3
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 +33 -5
- package/dist/index.d.ts +33 -5
- package/dist/index.js +158 -154
- package/dist/index.mjs +83 -81
- package/package.json +2 -2
- package/src/BaseSettingsDialog.tsx +8 -28
- package/src/BaseStatsScreen.tsx +2 -2
- package/src/ConfirmDialog.tsx +18 -31
- package/src/index.ts +1 -0
- package/src/overlayCard.ts +48 -0
package/dist/index.mjs
CHANGED
|
@@ -74,10 +74,43 @@ var styles = StyleSheet.create({
|
|
|
74
74
|
import { AutoAppearancePicker, Dialog, useAutoPaperTheme as useAutoPaperTheme2 } from "@rific/auto-paper";
|
|
75
75
|
import { Button, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from "@rific/feedback-press";
|
|
76
76
|
import { useUpdater } from "@rific/updater";
|
|
77
|
-
import { useIsTouchPrimaryDevice, useRotation } from "@tastic/core";
|
|
77
|
+
import { toRotationStyle, useIsTouchPrimaryDevice, useRotation } from "@tastic/core";
|
|
78
78
|
import { useContext, useState } from "react";
|
|
79
|
-
import { Platform, ScrollView, StyleSheet as
|
|
79
|
+
import { Platform, ScrollView, StyleSheet as StyleSheet3, View as View2 } from "react-native";
|
|
80
80
|
import { Icon as Icon2, Portal, Text as Text2 } from "react-native-paper";
|
|
81
|
+
|
|
82
|
+
// src/overlayCard.ts
|
|
83
|
+
import { StyleSheet as StyleSheet2 } from "react-native";
|
|
84
|
+
function getOverlayCardColors(dark) {
|
|
85
|
+
return {
|
|
86
|
+
fg: dark ? "#FFFFFF" : "#000000",
|
|
87
|
+
fgMuted: dark ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)",
|
|
88
|
+
cardBg: dark ? "#111111" : "#F2F2F2",
|
|
89
|
+
cardBorder: dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
var overlayStyles = StyleSheet2.create({
|
|
93
|
+
card: {
|
|
94
|
+
alignItems: "center",
|
|
95
|
+
borderRadius: 20,
|
|
96
|
+
borderWidth: 1,
|
|
97
|
+
gap: 16,
|
|
98
|
+
maxWidth: 360,
|
|
99
|
+
padding: 32
|
|
100
|
+
},
|
|
101
|
+
overlay: {
|
|
102
|
+
alignItems: "center",
|
|
103
|
+
backgroundColor: "rgba(0,0,0,0.72)",
|
|
104
|
+
bottom: 0,
|
|
105
|
+
justifyContent: "center",
|
|
106
|
+
left: 0,
|
|
107
|
+
position: "absolute",
|
|
108
|
+
right: 0,
|
|
109
|
+
top: 0
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// src/BaseSettingsDialog.tsx
|
|
81
114
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
82
115
|
function SettingIcon({ source, color, containerColor }) {
|
|
83
116
|
return /* @__PURE__ */ jsx2(View2, { style: [styles2.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx2(Icon2, { source, size: 18, color }) });
|
|
@@ -104,11 +137,9 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
104
137
|
const showSound = !hideSound;
|
|
105
138
|
const showAppearance = !hideAppearance;
|
|
106
139
|
const showUpdateCheck = Platform.OS !== "web" && !hideUpdateCheck;
|
|
107
|
-
const fg
|
|
108
|
-
const cardBg = dark ? "#111111" : "#F2F2F2";
|
|
109
|
-
const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
|
|
140
|
+
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
|
|
110
141
|
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
111
|
-
/* @__PURE__ */ jsxs2(Dialog, { visible, onDismiss, style: [styles2.dialog, rotation
|
|
142
|
+
/* @__PURE__ */ jsxs2(Dialog, { visible, onDismiss, style: [styles2.dialog, toRotationStyle(rotation)], children: [
|
|
112
143
|
/* @__PURE__ */ jsx2(Dialog.Title, { children: "Settings" }),
|
|
113
144
|
/* @__PURE__ */ jsx2(Dialog.ScrollArea, { style: styles2.scrollArea, children: /* @__PURE__ */ jsxs2(ScrollView, { contentContainerStyle: styles2.content, showsVerticalScrollIndicator: false, children: [
|
|
114
145
|
/* @__PURE__ */ jsxs2(View2, { style: styles2.toggleGroup, children: [
|
|
@@ -178,7 +209,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
178
209
|
] })
|
|
179
210
|
] }) })
|
|
180
211
|
] }),
|
|
181
|
-
infoMessage && /* @__PURE__ */ jsx2(Portal, { children: /* @__PURE__ */ jsx2(View2, { style:
|
|
212
|
+
infoMessage && /* @__PURE__ */ jsx2(Portal, { children: /* @__PURE__ */ jsx2(View2, { style: overlayStyles.overlay, children: /* @__PURE__ */ jsxs2(View2, { style: [overlayStyles.card, { backgroundColor: cardBg, borderColor: cardBorder }, toRotationStyle(rotation)], children: [
|
|
182
213
|
/* @__PURE__ */ jsx2(Icon2, { source: "information-outline", size: 64, color: colors.secondary }),
|
|
183
214
|
/* @__PURE__ */ jsx2(Text2, { variant: "headlineLarge", style: [styles2.overlayTitle, { color: colors.secondary }], children: infoMessage.title }),
|
|
184
215
|
/* @__PURE__ */ jsx2(Text2, { variant: "bodyLarge", style: [styles2.overlayBody, { color: fg }], children: infoMessage.message }),
|
|
@@ -186,7 +217,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
186
217
|
] }) }) })
|
|
187
218
|
] });
|
|
188
219
|
}
|
|
189
|
-
var styles2 =
|
|
220
|
+
var styles2 = StyleSheet3.create({
|
|
190
221
|
content: {
|
|
191
222
|
gap: 24,
|
|
192
223
|
paddingVertical: 20
|
|
@@ -208,26 +239,8 @@ var styles2 = StyleSheet2.create({
|
|
|
208
239
|
justifyContent: "center",
|
|
209
240
|
width: 36
|
|
210
241
|
},
|
|
211
|
-
overlay: {
|
|
212
|
-
alignItems: "center",
|
|
213
|
-
backgroundColor: "rgba(0,0,0,0.72)",
|
|
214
|
-
bottom: 0,
|
|
215
|
-
justifyContent: "center",
|
|
216
|
-
left: 0,
|
|
217
|
-
position: "absolute",
|
|
218
|
-
right: 0,
|
|
219
|
-
top: 0
|
|
220
|
-
},
|
|
221
242
|
overlayBody: { textAlign: "center" },
|
|
222
243
|
overlayButton: { width: 160 },
|
|
223
|
-
overlayCard: {
|
|
224
|
-
alignItems: "center",
|
|
225
|
-
borderRadius: 20,
|
|
226
|
-
borderWidth: 1,
|
|
227
|
-
gap: 16,
|
|
228
|
-
maxWidth: 360,
|
|
229
|
-
padding: 32
|
|
230
|
-
},
|
|
231
244
|
overlayTitle: { fontWeight: "bold" },
|
|
232
245
|
scrollArea: {
|
|
233
246
|
marginBottom: 0
|
|
@@ -279,24 +292,23 @@ import { useAutoPaperTheme as useAutoPaperTheme4 } from "@rific/auto-paper";
|
|
|
279
292
|
import { Button as Button3, IconButton } from "@rific/feedback-press";
|
|
280
293
|
import { useRotation as useRotation2 } from "@tastic/core";
|
|
281
294
|
import { useState as useState2 } from "react";
|
|
282
|
-
import { ScrollView as ScrollView2, StyleSheet as
|
|
295
|
+
import { ScrollView as ScrollView2, StyleSheet as StyleSheet5, View as View4 } from "react-native";
|
|
283
296
|
import { Text as Text4 } from "react-native-paper";
|
|
284
297
|
|
|
285
298
|
// src/ConfirmDialog.tsx
|
|
286
299
|
import { useAutoPaperTheme as useAutoPaperTheme3 } from "@rific/auto-paper";
|
|
287
300
|
import { Button as Button2 } from "@rific/feedback-press";
|
|
288
|
-
import {
|
|
301
|
+
import { toRotationStyle as toRotationStyle2 } from "@tastic/core";
|
|
302
|
+
import { StyleSheet as StyleSheet4, View as View3 } from "react-native";
|
|
289
303
|
import { Icon as Icon3, Portal as Portal2, Text as Text3 } from "react-native-paper";
|
|
290
304
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
291
305
|
function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
|
|
292
306
|
const { dark, colors } = useAutoPaperTheme3();
|
|
293
307
|
if (!visible) return null;
|
|
294
|
-
const fg
|
|
295
|
-
const cardBg = dark ? "#111111" : "#F2F2F2";
|
|
296
|
-
const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
|
|
308
|
+
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark);
|
|
297
309
|
const accent = destructive ? colors.danger : colors.primary;
|
|
298
310
|
const onAccent = destructive ? colors.onDanger : colors.onPrimary;
|
|
299
|
-
return /* @__PURE__ */ jsx3(Portal2, { children: /* @__PURE__ */ jsx3(View3, { style: styles3.overlay, children: /* @__PURE__ */ jsxs3(View3, { style: [styles3.card, { backgroundColor: cardBg, borderColor: cardBorder }, rotation
|
|
311
|
+
return /* @__PURE__ */ jsx3(Portal2, { children: /* @__PURE__ */ jsx3(View3, { style: [overlayStyles.overlay, styles3.overlay], children: /* @__PURE__ */ jsxs3(View3, { style: [overlayStyles.card, styles3.card, { backgroundColor: cardBg, borderColor: cardBorder }, toRotationStyle2(rotation)], children: [
|
|
300
312
|
/* @__PURE__ */ jsx3(Icon3, { source: icon, size: 64, color: accent }),
|
|
301
313
|
/* @__PURE__ */ jsx3(Text3, { variant: "headlineLarge", style: [styles3.title, { color: accent }], children: title }),
|
|
302
314
|
/* @__PURE__ */ jsx3(Text3, { variant: "bodyLarge", style: [styles3.body, { color: fg }], children: message }),
|
|
@@ -306,7 +318,7 @@ function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onC
|
|
|
306
318
|
] })
|
|
307
319
|
] }) }) });
|
|
308
320
|
}
|
|
309
|
-
var styles3 =
|
|
321
|
+
var styles3 = StyleSheet4.create({
|
|
310
322
|
// flexBasis (not flex: 1's own 0%) is each button's real floor: whenever both fit side by side,
|
|
311
323
|
// flexGrow still splits any leftover width evenly beyond that floor, same visual result as the
|
|
312
324
|
// old flex: 1 on a roomy screen - but a button can never be squeezed narrower than 128, only
|
|
@@ -331,32 +343,20 @@ var styles3 = StyleSheet3.create({
|
|
|
331
343
|
body: {
|
|
332
344
|
textAlign: "center"
|
|
333
345
|
},
|
|
346
|
+
// Additive on top of overlayCard's own shared `card` shape (borderRadius/borderWidth/gap/maxWidth/
|
|
347
|
+
// padding) — claims its full allowance instead of just maxWidth alone, which only caps how wide the
|
|
348
|
+
// card is allowed to get - without an explicit width, a flex-centered child sizes to its own content
|
|
349
|
+
// instead of stretching, so the card (and therefore actions below) can end up narrower than the
|
|
350
|
+
// screen actually has room for, needlessly forcing the action row to wrap sooner than it has to.
|
|
334
351
|
card: {
|
|
335
|
-
alignItems: "center",
|
|
336
|
-
borderRadius: 20,
|
|
337
|
-
borderWidth: 1,
|
|
338
|
-
gap: 16,
|
|
339
|
-
maxWidth: 360,
|
|
340
|
-
padding: 32,
|
|
341
|
-
// Claims its full allowance instead of just maxWidth alone, which only caps how wide the card
|
|
342
|
-
// is allowed to get - without an explicit width, a flex-centered child sizes to its own content
|
|
343
|
-
// instead of stretching, so the card (and therefore actions below) can end up narrower than the
|
|
344
|
-
// screen actually has room for, needlessly forcing the action row to wrap sooner than it has to.
|
|
345
352
|
width: "100%"
|
|
346
353
|
},
|
|
354
|
+
// Additive on top of overlayCard's own shared `overlay` backdrop — gives the card room to breathe
|
|
355
|
+
// from the screen edges now that it reliably stretches to fill its full width allowance (see
|
|
356
|
+
// card's own width comment) - without this, width: '100%' would run the card edge-to-edge on a
|
|
357
|
+
// screen narrower than maxWidth's own 360.
|
|
347
358
|
overlay: {
|
|
348
|
-
|
|
349
|
-
backgroundColor: "rgba(0,0,0,0.72)",
|
|
350
|
-
bottom: 0,
|
|
351
|
-
justifyContent: "center",
|
|
352
|
-
left: 0,
|
|
353
|
-
// Gives the card room to breathe from the screen edges now that it reliably stretches to fill
|
|
354
|
-
// its full width allowance (see card's own width comment) - without this, width: '100%' would
|
|
355
|
-
// run the card edge-to-edge on a screen narrower than maxWidth's own 360.
|
|
356
|
-
paddingHorizontal: 24,
|
|
357
|
-
position: "absolute",
|
|
358
|
-
right: 0,
|
|
359
|
-
top: 0
|
|
359
|
+
paddingHorizontal: 24
|
|
360
360
|
},
|
|
361
361
|
// textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
|
|
362
362
|
// within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
|
|
@@ -406,7 +406,7 @@ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", t
|
|
|
406
406
|
)
|
|
407
407
|
] });
|
|
408
408
|
}
|
|
409
|
-
var styles4 =
|
|
409
|
+
var styles4 = StyleSheet5.create({
|
|
410
410
|
container: {
|
|
411
411
|
flex: 1
|
|
412
412
|
},
|
|
@@ -438,7 +438,7 @@ var styles4 = StyleSheet4.create({
|
|
|
438
438
|
|
|
439
439
|
// src/ContentGutter.tsx
|
|
440
440
|
import { computeContentBounds } from "@tastic/core";
|
|
441
|
-
import { StyleSheet as
|
|
441
|
+
import { StyleSheet as StyleSheet6, useWindowDimensions, View as View5 } from "react-native";
|
|
442
442
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
443
443
|
function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
|
|
444
444
|
const { width: windowWidth } = useWindowDimensions();
|
|
@@ -449,7 +449,7 @@ function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, childr
|
|
|
449
449
|
/* @__PURE__ */ jsx5(View5, { style: [styles5.gutter, { width: gutterWidth }], children: rightGutter })
|
|
450
450
|
] });
|
|
451
451
|
}
|
|
452
|
-
var styles5 =
|
|
452
|
+
var styles5 = StyleSheet6.create({
|
|
453
453
|
// overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
|
|
454
454
|
// column instead of clipping cleanly at its own real width.
|
|
455
455
|
gutter: {
|
|
@@ -468,7 +468,7 @@ import { Platform as Platform3 } from "react-native";
|
|
|
468
468
|
import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
|
|
469
469
|
import { IconButton as IconButton2, TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
|
|
470
470
|
import { useRotation as useRotation3 } from "@tastic/core";
|
|
471
|
-
import { ScrollView as ScrollView3, StyleSheet as
|
|
471
|
+
import { ScrollView as ScrollView3, StyleSheet as StyleSheet8, View as View8 } from "react-native";
|
|
472
472
|
import { Icon as Icon4, Text as Text5 } from "react-native-paper";
|
|
473
473
|
|
|
474
474
|
// src/fonts.ts
|
|
@@ -476,7 +476,7 @@ import { Platform as Platform2 } from "react-native";
|
|
|
476
476
|
var MONO_FONT = Platform2.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
477
477
|
|
|
478
478
|
// src/PopoverBody.tsx
|
|
479
|
-
import { StyleSheet as
|
|
479
|
+
import { StyleSheet as StyleSheet7, View as View6 } from "react-native";
|
|
480
480
|
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
481
481
|
var CARET_SIZE = 7;
|
|
482
482
|
var CARET_RING_OFFSET = 2;
|
|
@@ -499,7 +499,7 @@ function PopoverBody({ visible, children, align = "center", verticalAlign = "bel
|
|
|
499
499
|
] })
|
|
500
500
|
] });
|
|
501
501
|
}
|
|
502
|
-
var styles6 =
|
|
502
|
+
var styles6 = StyleSheet7.create({
|
|
503
503
|
caret: {
|
|
504
504
|
borderLeftColor: "transparent",
|
|
505
505
|
borderRightColor: "transparent",
|
|
@@ -721,7 +721,7 @@ function MultiSection({
|
|
|
721
721
|
section.allClear && /* @__PURE__ */ jsx8(TouchableRipple2, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles7.item, children: /* @__PURE__ */ jsx8(Text5, { variant: "labelLarge", style: [styles7.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
|
|
722
722
|
] });
|
|
723
723
|
}
|
|
724
|
-
var styles7 =
|
|
724
|
+
var styles7 = StyleSheet8.create({
|
|
725
725
|
allClearLabel: {
|
|
726
726
|
fontWeight: "bold",
|
|
727
727
|
textAlign: "center"
|
|
@@ -738,7 +738,7 @@ var styles7 = StyleSheet7.create({
|
|
|
738
738
|
zIndex: 100
|
|
739
739
|
},
|
|
740
740
|
divider: {
|
|
741
|
-
height:
|
|
741
|
+
height: StyleSheet8.hairlineWidth,
|
|
742
742
|
marginVertical: 4
|
|
743
743
|
},
|
|
744
744
|
item: {
|
|
@@ -800,7 +800,7 @@ function ControlSchemePicker({ id, host, value, onChange, options, takenValue, a
|
|
|
800
800
|
|
|
801
801
|
// src/CornerActionButtons.tsx
|
|
802
802
|
import { IconButton as IconButton3 } from "@rific/feedback-press";
|
|
803
|
-
import { StyleSheet as
|
|
803
|
+
import { StyleSheet as StyleSheet9 } from "react-native";
|
|
804
804
|
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
805
805
|
function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
|
|
806
806
|
return /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
@@ -808,7 +808,7 @@ function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow
|
|
|
808
808
|
/* @__PURE__ */ jsx10(IconButton3, { icon: "cog", iconColor: fg, size: 24, style: [styles8.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
|
|
809
809
|
] });
|
|
810
810
|
}
|
|
811
|
-
var styles8 =
|
|
811
|
+
var styles8 = StyleSheet9.create({
|
|
812
812
|
back: {
|
|
813
813
|
position: "absolute"
|
|
814
814
|
},
|
|
@@ -818,7 +818,7 @@ var styles8 = StyleSheet8.create({
|
|
|
818
818
|
});
|
|
819
819
|
|
|
820
820
|
// src/CornerStatusBadges.tsx
|
|
821
|
-
import { StyleSheet as
|
|
821
|
+
import { StyleSheet as StyleSheet10, View as View9 } from "react-native";
|
|
822
822
|
import { Icon as Icon5 } from "react-native-paper";
|
|
823
823
|
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
824
824
|
var BADGE_SIZE = 30;
|
|
@@ -833,7 +833,7 @@ function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
|
|
|
833
833
|
p2 && /* @__PURE__ */ jsx11(View9, { pointerEvents: "none", style: p2OnLeftSide ? styles9.topLeft : styles9.topRight, children: /* @__PURE__ */ jsx11(StatusBadge, { icon: p2.icon }) })
|
|
834
834
|
] });
|
|
835
835
|
}
|
|
836
|
-
var styles9 =
|
|
836
|
+
var styles9 = StyleSheet10.create({
|
|
837
837
|
badge: {
|
|
838
838
|
alignItems: "center",
|
|
839
839
|
backgroundColor: "rgba(0,0,0,0.28)",
|
|
@@ -855,7 +855,7 @@ var styles9 = StyleSheet9.create({
|
|
|
855
855
|
import { defaultColors, getContrastColor } from "@rific/auto-paper";
|
|
856
856
|
import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
|
|
857
857
|
import { clamp, useRotation as useRotation4 } from "@tastic/core";
|
|
858
|
-
import { ScrollView as ScrollView4, StyleSheet as
|
|
858
|
+
import { ScrollView as ScrollView4, StyleSheet as StyleSheet11, useWindowDimensions as useWindowDimensions3, View as View10 } from "react-native";
|
|
859
859
|
import { Icon as Icon6, Text as Text6 } from "react-native-paper";
|
|
860
860
|
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
861
861
|
var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
|
|
@@ -911,7 +911,7 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
|
|
|
911
911
|
}) }) })
|
|
912
912
|
] });
|
|
913
913
|
}
|
|
914
|
-
var styles10 =
|
|
914
|
+
var styles10 = StyleSheet11.create({
|
|
915
915
|
anchor: {
|
|
916
916
|
position: "relative"
|
|
917
917
|
},
|
|
@@ -985,7 +985,7 @@ var styles10 = StyleSheet10.create({
|
|
|
985
985
|
// src/LabeledDropdown.tsx
|
|
986
986
|
import { getContrastColor as getContrastColor2 } from "@rific/auto-paper";
|
|
987
987
|
import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
|
|
988
|
-
import { ScrollView as ScrollView5, StyleSheet as
|
|
988
|
+
import { ScrollView as ScrollView5, StyleSheet as StyleSheet12, View as View11 } from "react-native";
|
|
989
989
|
import { Icon as Icon7, Text as Text7 } from "react-native-paper";
|
|
990
990
|
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
991
991
|
var TRIGGER_HEIGHT = 28;
|
|
@@ -1025,7 +1025,7 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
|
|
|
1025
1025
|
}) }) })
|
|
1026
1026
|
] });
|
|
1027
1027
|
}
|
|
1028
|
-
var styles11 =
|
|
1028
|
+
var styles11 = StyleSheet12.create({
|
|
1029
1029
|
anchor: {
|
|
1030
1030
|
position: "relative"
|
|
1031
1031
|
},
|
|
@@ -1083,16 +1083,16 @@ function loadSkiaWeb() {
|
|
|
1083
1083
|
}
|
|
1084
1084
|
|
|
1085
1085
|
// src/PressAwayOverlay.tsx
|
|
1086
|
-
import { Pressable, StyleSheet as
|
|
1086
|
+
import { Pressable, StyleSheet as StyleSheet13 } from "react-native";
|
|
1087
1087
|
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1088
1088
|
function PressAwayOverlay({ active, onPress, style }) {
|
|
1089
1089
|
if (!active) return null;
|
|
1090
|
-
return /* @__PURE__ */ jsx14(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [
|
|
1090
|
+
return /* @__PURE__ */ jsx14(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet13.absoluteFill, style] });
|
|
1091
1091
|
}
|
|
1092
1092
|
|
|
1093
1093
|
// src/ReadyButton.tsx
|
|
1094
1094
|
import { TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
|
|
1095
|
-
import { StyleSheet as
|
|
1095
|
+
import { StyleSheet as StyleSheet14 } from "react-native";
|
|
1096
1096
|
import { Text as Text8 } from "react-native-paper";
|
|
1097
1097
|
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1098
1098
|
function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
|
|
@@ -1101,7 +1101,7 @@ function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MON
|
|
|
1101
1101
|
const labelColorStyle = { color: ready ? "#000000" : color };
|
|
1102
1102
|
return /* @__PURE__ */ jsx15(TouchableRipple5, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx15(Text8, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
|
|
1103
1103
|
}
|
|
1104
|
-
var styles12 =
|
|
1104
|
+
var styles12 = StyleSheet14.create({
|
|
1105
1105
|
readyButton: {
|
|
1106
1106
|
alignItems: "center",
|
|
1107
1107
|
borderRadius: 12,
|
|
@@ -1115,7 +1115,7 @@ var styles12 = StyleSheet13.create({
|
|
|
1115
1115
|
|
|
1116
1116
|
// src/SharedActionBand.tsx
|
|
1117
1117
|
import { IconButton as IconButton4 } from "@rific/feedback-press";
|
|
1118
|
-
import { StyleSheet as
|
|
1118
|
+
import { StyleSheet as StyleSheet15, View as View12 } from "react-native";
|
|
1119
1119
|
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1120
1120
|
function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
|
|
1121
1121
|
return /* @__PURE__ */ jsxs12(View12, { style: [styles13.column, popoverOpen && styles13.columnOpen], children: [
|
|
@@ -1128,7 +1128,7 @@ function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popove
|
|
|
1128
1128
|
children
|
|
1129
1129
|
] });
|
|
1130
1130
|
}
|
|
1131
|
-
var styles13 =
|
|
1131
|
+
var styles13 = StyleSheet15.create({
|
|
1132
1132
|
actionsRow: {
|
|
1133
1133
|
alignItems: "center",
|
|
1134
1134
|
flexDirection: "row",
|
|
@@ -1145,7 +1145,7 @@ var styles13 = StyleSheet14.create({
|
|
|
1145
1145
|
|
|
1146
1146
|
// src/StatRow.tsx
|
|
1147
1147
|
import { useAutoPaperTheme as useAutoPaperTheme5 } from "@rific/auto-paper";
|
|
1148
|
-
import { StyleSheet as
|
|
1148
|
+
import { StyleSheet as StyleSheet16, View as View13 } from "react-native";
|
|
1149
1149
|
import { Text as Text9 } from "react-native-paper";
|
|
1150
1150
|
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1151
1151
|
function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
|
|
@@ -1157,7 +1157,7 @@ function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
|
|
|
1157
1157
|
/* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: [styles14.value, { color: fg }], children: value })
|
|
1158
1158
|
] });
|
|
1159
1159
|
}
|
|
1160
|
-
var styles14 =
|
|
1160
|
+
var styles14 = StyleSheet16.create({
|
|
1161
1161
|
row: {
|
|
1162
1162
|
alignItems: "center",
|
|
1163
1163
|
flexDirection: "row",
|
|
@@ -1170,7 +1170,7 @@ var styles14 = StyleSheet15.create({
|
|
|
1170
1170
|
|
|
1171
1171
|
// src/StatSection.tsx
|
|
1172
1172
|
import { useAutoPaperTheme as useAutoPaperTheme6 } from "@rific/auto-paper";
|
|
1173
|
-
import { StyleSheet as
|
|
1173
|
+
import { StyleSheet as StyleSheet17, View as View14 } from "react-native";
|
|
1174
1174
|
import { Text as Text10 } from "react-native-paper";
|
|
1175
1175
|
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1176
1176
|
function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
|
|
@@ -1182,7 +1182,7 @@ function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, chil
|
|
|
1182
1182
|
children
|
|
1183
1183
|
] });
|
|
1184
1184
|
}
|
|
1185
|
-
var styles15 =
|
|
1185
|
+
var styles15 = StyleSheet17.create({
|
|
1186
1186
|
// Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
|
|
1187
1187
|
// same visual weight as StatRow's own row labels below it (both used the identical muted color;
|
|
1188
1188
|
// letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
|
|
@@ -1232,7 +1232,9 @@ export {
|
|
|
1232
1232
|
StatSection,
|
|
1233
1233
|
TriggerGaugeHost,
|
|
1234
1234
|
getLabeledDropdownContentHeight,
|
|
1235
|
+
getOverlayCardColors,
|
|
1235
1236
|
loadSkiaWeb,
|
|
1237
|
+
overlayStyles,
|
|
1236
1238
|
useAutoAlign,
|
|
1237
1239
|
usePopoverHost
|
|
1238
1240
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tastic/hud",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Visual component kit for local-multiplayer React Native games: inline (non-modal) popovers, dropdowns, color pickers, gauges, ready buttons, and dialogs, built to stay scoped to one player's own zone on a shared screen",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@rific/feedback-press": "^0.10.8",
|
|
78
78
|
"@rific/updater": "^0.6.0",
|
|
79
79
|
"@shopify/react-native-skia": "^2.6.2",
|
|
80
|
-
"@tastic/core": "^0.
|
|
80
|
+
"@tastic/core": "^0.4.1",
|
|
81
81
|
"@testing-library/dom": "^10.4.1",
|
|
82
82
|
"@testing-library/react": "^16.3.2",
|
|
83
83
|
"@types/jest": "^30.0.0",
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { AutoAppearancePicker, Dialog, useAutoPaperTheme } from '@rific/auto-paper'
|
|
2
2
|
import { Button, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from '@rific/feedback-press'
|
|
3
3
|
import { useUpdater } from '@rific/updater'
|
|
4
|
-
import { useIsTouchPrimaryDevice, useRotation } from '@tastic/core'
|
|
4
|
+
import { toRotationStyle, useIsTouchPrimaryDevice, useRotation, type ViewRotation } from '@tastic/core'
|
|
5
5
|
import { ReactNode, useContext, useState } from 'react'
|
|
6
6
|
import { Platform, ScrollView, StyleSheet, View } from 'react-native'
|
|
7
7
|
import { Icon, Portal, Text } from 'react-native-paper'
|
|
8
8
|
|
|
9
|
+
import { getOverlayCardColors, overlayStyles } from './overlayCard'
|
|
10
|
+
|
|
9
11
|
interface SettingIconProps {
|
|
10
12
|
source: string
|
|
11
13
|
color: string
|
|
@@ -31,7 +33,7 @@ export interface BaseSettingsDialogProps {
|
|
|
31
33
|
// dialog), so it just rotates its own content in place. Defaults to a live ambient read via
|
|
32
34
|
// useRotation() when omitted; pass this only when a caller's own reading needs to differ from the
|
|
33
35
|
// ambient one (rare — most callers should simply omit it).
|
|
34
|
-
rotation?:
|
|
36
|
+
rotation?: ViewRotation
|
|
35
37
|
// Each app's own OTA version (e.g. release.otaVersion) — not something this package can read
|
|
36
38
|
// itself, since every consuming app tracks its own release.ts independently. Accepts a number too
|
|
37
39
|
// since that's what release.otaVersion actually is in most apps (a bare incrementing counter, not
|
|
@@ -118,15 +120,11 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
|
|
|
118
120
|
const showAppearance = !hideAppearance
|
|
119
121
|
const showUpdateCheck = Platform.OS !== 'web' && !hideUpdateCheck
|
|
120
122
|
|
|
121
|
-
|
|
122
|
-
// tinted) background role.
|
|
123
|
-
const fg = dark ? '#FFFFFF' : '#000000'
|
|
124
|
-
const cardBg = dark ? '#111111' : '#F2F2F2'
|
|
125
|
-
const cardBorder = dark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.2)'
|
|
123
|
+
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark)
|
|
126
124
|
|
|
127
125
|
return (
|
|
128
126
|
<>
|
|
129
|
-
<Dialog visible={visible} onDismiss={onDismiss} style={[styles.dialog, rotation
|
|
127
|
+
<Dialog visible={visible} onDismiss={onDismiss} style={[styles.dialog, toRotationStyle(rotation)]}>
|
|
130
128
|
<Dialog.Title>Settings</Dialog.Title>
|
|
131
129
|
{/* react-native-paper's Dialog.ScrollArea has a fixed 24px marginBottom baked in (meant to
|
|
132
130
|
reserve room for a Dialog.Actions row below it) — overridden to 0 since this dialog has
|
|
@@ -265,8 +263,8 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
|
|
|
265
263
|
</Dialog>
|
|
266
264
|
{infoMessage && (
|
|
267
265
|
<Portal>
|
|
268
|
-
<View style={
|
|
269
|
-
<View style={[
|
|
266
|
+
<View style={overlayStyles.overlay}>
|
|
267
|
+
<View style={[overlayStyles.card, { backgroundColor: cardBg, borderColor: cardBorder }, toRotationStyle(rotation)]}>
|
|
270
268
|
<Icon source='information-outline' size={64} color={colors.secondary} />
|
|
271
269
|
<Text variant='headlineLarge' style={[styles.overlayTitle, { color: colors.secondary }]}>
|
|
272
270
|
{infoMessage.title}
|
|
@@ -307,26 +305,8 @@ const styles = StyleSheet.create({
|
|
|
307
305
|
justifyContent: 'center',
|
|
308
306
|
width: 36
|
|
309
307
|
},
|
|
310
|
-
overlay: {
|
|
311
|
-
alignItems: 'center',
|
|
312
|
-
backgroundColor: 'rgba(0,0,0,0.72)',
|
|
313
|
-
bottom: 0,
|
|
314
|
-
justifyContent: 'center',
|
|
315
|
-
left: 0,
|
|
316
|
-
position: 'absolute',
|
|
317
|
-
right: 0,
|
|
318
|
-
top: 0
|
|
319
|
-
},
|
|
320
308
|
overlayBody: { textAlign: 'center' },
|
|
321
309
|
overlayButton: { width: 160 },
|
|
322
|
-
overlayCard: {
|
|
323
|
-
alignItems: 'center',
|
|
324
|
-
borderRadius: 20,
|
|
325
|
-
borderWidth: 1,
|
|
326
|
-
gap: 16,
|
|
327
|
-
maxWidth: 360,
|
|
328
|
-
padding: 32
|
|
329
|
-
},
|
|
330
310
|
overlayTitle: { fontWeight: 'bold' },
|
|
331
311
|
scrollArea: {
|
|
332
312
|
marginBottom: 0
|
package/src/BaseStatsScreen.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useAutoPaperTheme } from '@rific/auto-paper'
|
|
2
2
|
import { Button, IconButton } from '@rific/feedback-press'
|
|
3
|
-
import { useRotation } from '@tastic/core'
|
|
3
|
+
import { useRotation, type ViewRotation } from '@tastic/core'
|
|
4
4
|
import { ReactNode, useState } from 'react'
|
|
5
5
|
import { ScrollView, StyleSheet, View } from 'react-native'
|
|
6
6
|
import { Text } from 'react-native-paper'
|
|
@@ -20,7 +20,7 @@ interface Props {
|
|
|
20
20
|
// read via useRotation() when omitted — note this does NOT make the header/scrollable content
|
|
21
21
|
// below rotate; the caller's own screen still needs its own FakeLandscapeView wrap for that
|
|
22
22
|
// (this component has no transform on its own main body).
|
|
23
|
-
rotation?:
|
|
23
|
+
rotation?: ViewRotation
|
|
24
24
|
title?: string
|
|
25
25
|
// 'headlineSmall' (this screen's own default, below) — was originally 'displaySmall' (the full
|
|
26
26
|
// display tier's own smallest step), then 'headlineLarge', both still read as oversized for a
|
package/src/ConfirmDialog.tsx
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { useAutoPaperTheme } from '@rific/auto-paper'
|
|
2
2
|
import { Button } from '@rific/feedback-press'
|
|
3
|
+
import { toRotationStyle, type ViewRotation } from '@tastic/core'
|
|
3
4
|
import { StyleSheet, View } from 'react-native'
|
|
4
5
|
import { Icon, Portal, Text } from 'react-native-paper'
|
|
5
6
|
|
|
7
|
+
import { getOverlayCardColors, overlayStyles } from './overlayCard'
|
|
8
|
+
|
|
6
9
|
export interface ConfirmDialogProps {
|
|
7
10
|
visible: boolean
|
|
8
11
|
title: string
|
|
@@ -11,10 +14,10 @@ export interface ConfirmDialogProps {
|
|
|
11
14
|
cancelLabel: string
|
|
12
15
|
onConfirm: () => void
|
|
13
16
|
onCancel: () => void
|
|
14
|
-
// Live physical-hold rotation (see @tastic/
|
|
17
|
+
// Live physical-hold rotation (see @tastic/core's getViewRotation) - same convention as
|
|
15
18
|
// BaseSettingsDialog's own rotation prop; defaults to 0 for a caller with no per-player zone to
|
|
16
19
|
// match (a portrait-only or single-player game has nothing to stay consistent with).
|
|
17
|
-
rotation?:
|
|
20
|
+
rotation?: ViewRotation
|
|
18
21
|
// Any react-native-paper Icon `source` name, shown above the title - defaults to a plain
|
|
19
22
|
// question mark, since this component has no way to know why a caller is asking.
|
|
20
23
|
icon?: string
|
|
@@ -35,18 +38,14 @@ export function ConfirmDialog({ visible, title, message, confirmLabel, cancelLab
|
|
|
35
38
|
const { dark, colors } = useAutoPaperTheme()
|
|
36
39
|
if (!visible) return null
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
// tinted) background role - same convention BaseSettingsDialog's own overlay card uses.
|
|
40
|
-
const fg = dark ? '#FFFFFF' : '#000000'
|
|
41
|
-
const cardBg = dark ? '#111111' : '#F2F2F2'
|
|
42
|
-
const cardBorder = dark ? 'rgba(255,255,255,0.2)' : 'rgba(0,0,0,0.2)'
|
|
41
|
+
const { fg, cardBg, cardBorder } = getOverlayCardColors(dark)
|
|
43
42
|
const accent = destructive ? colors.danger : colors.primary
|
|
44
43
|
const onAccent = destructive ? colors.onDanger : colors.onPrimary
|
|
45
44
|
|
|
46
45
|
return (
|
|
47
46
|
<Portal>
|
|
48
|
-
<View style={styles.overlay}>
|
|
49
|
-
<View style={[styles.card, { backgroundColor: cardBg, borderColor: cardBorder }, rotation
|
|
47
|
+
<View style={[overlayStyles.overlay, styles.overlay]}>
|
|
48
|
+
<View style={[overlayStyles.card, styles.card, { backgroundColor: cardBg, borderColor: cardBorder }, toRotationStyle(rotation)]}>
|
|
50
49
|
<Icon source={icon} size={64} color={accent} />
|
|
51
50
|
<Text variant='headlineLarge' style={[styles.title, { color: accent }]}>
|
|
52
51
|
{title}
|
|
@@ -93,32 +92,20 @@ const styles = StyleSheet.create({
|
|
|
93
92
|
body: {
|
|
94
93
|
textAlign: 'center'
|
|
95
94
|
},
|
|
95
|
+
// Additive on top of overlayCard's own shared `card` shape (borderRadius/borderWidth/gap/maxWidth/
|
|
96
|
+
// padding) — claims its full allowance instead of just maxWidth alone, which only caps how wide the
|
|
97
|
+
// card is allowed to get - without an explicit width, a flex-centered child sizes to its own content
|
|
98
|
+
// instead of stretching, so the card (and therefore actions below) can end up narrower than the
|
|
99
|
+
// screen actually has room for, needlessly forcing the action row to wrap sooner than it has to.
|
|
96
100
|
card: {
|
|
97
|
-
alignItems: 'center',
|
|
98
|
-
borderRadius: 20,
|
|
99
|
-
borderWidth: 1,
|
|
100
|
-
gap: 16,
|
|
101
|
-
maxWidth: 360,
|
|
102
|
-
padding: 32,
|
|
103
|
-
// Claims its full allowance instead of just maxWidth alone, which only caps how wide the card
|
|
104
|
-
// is allowed to get - without an explicit width, a flex-centered child sizes to its own content
|
|
105
|
-
// instead of stretching, so the card (and therefore actions below) can end up narrower than the
|
|
106
|
-
// screen actually has room for, needlessly forcing the action row to wrap sooner than it has to.
|
|
107
101
|
width: '100%'
|
|
108
102
|
},
|
|
103
|
+
// Additive on top of overlayCard's own shared `overlay` backdrop — gives the card room to breathe
|
|
104
|
+
// from the screen edges now that it reliably stretches to fill its full width allowance (see
|
|
105
|
+
// card's own width comment) - without this, width: '100%' would run the card edge-to-edge on a
|
|
106
|
+
// screen narrower than maxWidth's own 360.
|
|
109
107
|
overlay: {
|
|
110
|
-
|
|
111
|
-
backgroundColor: 'rgba(0,0,0,0.72)',
|
|
112
|
-
bottom: 0,
|
|
113
|
-
justifyContent: 'center',
|
|
114
|
-
left: 0,
|
|
115
|
-
// Gives the card room to breathe from the screen edges now that it reliably stretches to fill
|
|
116
|
-
// its full width allowance (see card's own width comment) - without this, width: '100%' would
|
|
117
|
-
// run the card edge-to-edge on a screen narrower than maxWidth's own 360.
|
|
118
|
-
paddingHorizontal: 24,
|
|
119
|
-
position: 'absolute',
|
|
120
|
-
right: 0,
|
|
121
|
-
top: 0
|
|
108
|
+
paddingHorizontal: 24
|
|
122
109
|
},
|
|
123
110
|
// textAlign is load-bearing, not decorative, once `title` wraps to more than one line - centered
|
|
124
111
|
// within card's own alignItems: 'center' only centers the Text's block as a whole; each wrapped
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { MONO_FONT } from './fonts'
|
|
|
10
10
|
export { InlineColorPicker } from './InlineColorPicker'
|
|
11
11
|
export { getLabeledDropdownContentHeight, LABELED_DROPDOWN_POPOVER_WIDTH, LabeledDropdown, type LabeledDropdownOption } from './LabeledDropdown'
|
|
12
12
|
export { loadSkiaWeb } from './loadSkiaWeb'
|
|
13
|
+
export { getOverlayCardColors, type OverlayCardColors, overlayStyles } from './overlayCard'
|
|
13
14
|
export { PopoverBody } from './PopoverBody'
|
|
14
15
|
export { PressAwayOverlay } from './PressAwayOverlay'
|
|
15
16
|
export { ReadyButton } from './ReadyButton'
|