@tastic/hud 0.14.0 → 0.14.2

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 CHANGED
@@ -78,7 +78,7 @@ interface BaseSettingsDialogProps {
78
78
  onShowHowToPlay?: () => void;
79
79
  children?: ReactNode;
80
80
  }
81
- declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element;
81
+ declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element | null;
82
82
 
83
83
  type MD3TextVariant = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
84
84
  interface Props$b {
package/dist/index.d.ts CHANGED
@@ -78,7 +78,7 @@ interface BaseSettingsDialogProps {
78
78
  onShowHowToPlay?: () => void;
79
79
  children?: ReactNode;
80
80
  }
81
- declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element;
81
+ declare function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound, hideHaptics, hideAppearance, hideUpdateCheck, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps): react.JSX.Element | null;
82
82
 
83
83
  type MD3TextVariant = 'displayLarge' | 'displayMedium' | 'displaySmall' | 'headlineLarge' | 'headlineMedium' | 'headlineSmall' | 'titleLarge' | 'titleMedium' | 'titleSmall' | 'labelLarge' | 'labelMedium' | 'labelSmall' | 'bodyLarge' | 'bodyMedium' | 'bodySmall';
84
84
  interface Props$b {
package/dist/index.js CHANGED
@@ -625,26 +625,29 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
625
625
  onInfo: (title, message) => setInfoMessage({ title, message })
626
626
  });
627
627
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
628
+ const [opened, setOpened] = (0, import_react4.useState)(visible);
629
+ if (visible && !opened) setOpened(true);
628
630
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
629
631
  const showEdgeGuard = import_react_native10.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
630
632
  const showHaptics = import_react_native10.Platform.OS !== "web" && !hideHaptics;
631
633
  const showSound = !hideSound;
632
634
  const showAppearance = !hideAppearance;
633
635
  const showUpdateCheck = import_react_native10.Platform.OS !== "web" && !hideUpdateCheck;
636
+ if (!opened) return null;
634
637
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
635
638
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_auto_paper7.Dialog, { visible, onDismiss, style: styles8.dialog, children: [
636
639
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_auto_paper7.Dialog.Title, { children: "Settings" }),
637
640
  /* @__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: [
638
641
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.toggleGroup, children: [
639
642
  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: [
640
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
643
+ /* @__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 }),
641
644
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
642
645
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
643
646
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
644
647
  ] })
645
648
  ] }) }),
646
649
  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: [
647
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
650
+ /* @__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 }),
648
651
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.flexShrink, children: [
649
652
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
650
653
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper8.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
package/dist/index.mjs CHANGED
@@ -346,26 +346,29 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
346
346
  onInfo: (title, message) => setInfoMessage({ title, message })
347
347
  });
348
348
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null;
349
+ const [opened, setOpened] = useState2(visible);
350
+ if (visible && !opened) setOpened(true);
349
351
  const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
350
352
  const showEdgeGuard = Platform2.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
351
353
  const showHaptics = Platform2.OS !== "web" && !hideHaptics;
352
354
  const showSound = !hideSound;
353
355
  const showAppearance = !hideAppearance;
354
356
  const showUpdateCheck = Platform2.OS !== "web" && !hideUpdateCheck;
357
+ if (!opened) return null;
355
358
  return /* @__PURE__ */ jsx9(Portal3, { children: /* @__PURE__ */ jsxs8(RotatedFrame, { rotation, rotatedSafeArea: true, portalHost: true, passThrough: true, children: [
356
359
  /* @__PURE__ */ jsxs8(Dialog, { visible, onDismiss, style: styles8.dialog, children: [
357
360
  /* @__PURE__ */ jsx9(Dialog.Title, { children: "Settings" }),
358
361
  /* @__PURE__ */ jsx9(Dialog.ScrollArea, { style: styles8.scrollArea, children: /* @__PURE__ */ jsxs8(ScrollView, { contentContainerStyle: styles8.content, showsVerticalScrollIndicator: false, children: [
359
362
  /* @__PURE__ */ jsxs8(View7, { style: styles8.toggleGroup, children: [
360
363
  showLockOrientation && /* @__PURE__ */ jsx9(TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles8.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ jsxs8(View7, { style: styles8.toggleContent, children: [
361
- /* @__PURE__ */ jsx9(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
364
+ /* @__PURE__ */ jsx9(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.tertiary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant }),
362
365
  /* @__PURE__ */ jsxs8(View7, { style: styles8.flexShrink, children: [
363
366
  /* @__PURE__ */ jsx9(Text7, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
364
367
  /* @__PURE__ */ jsx9(Text7, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
365
368
  ] })
366
369
  ] }) }),
367
370
  showEdgeGuard && /* @__PURE__ */ jsx9(TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles8.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ jsxs8(View7, { style: styles8.toggleContent, children: [
368
- /* @__PURE__ */ jsx9(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
371
+ /* @__PURE__ */ jsx9(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant }),
369
372
  /* @__PURE__ */ jsxs8(View7, { style: styles8.flexShrink, children: [
370
373
  /* @__PURE__ */ jsx9(Text7, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
371
374
  /* @__PURE__ */ jsx9(Text7, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tastic/hud",
3
- "version": "0.14.0",
3
+ "version": "0.14.2",
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",
@@ -18,7 +18,9 @@ interface SettingIconProps {
18
18
 
19
19
  // Small colored badge per row (icon tinted on its own MD3 container color) — echoes the
20
20
  // primary/secondary/tertiary triad that's already each consuming app's own identity, so the
21
- // settings list picks up that same palette instead of introducing new colors of its own.
21
+ // settings list picks up that same palette instead of introducing new colors of its own. Every
22
+ // on/off row (Lock Orientation, Edge Guard, Sound, Haptics) is tertiary while on, and an app adding
23
+ // its own toggle rows should match; secondary is for the always-on action row (How to Play).
22
24
  function SettingIcon({ source, color, containerColor }: SettingIconProps) {
23
25
  return (
24
26
  <View style={[styles.iconBadge, { backgroundColor: containerColor }]}>
@@ -123,6 +125,14 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
123
125
  onInfo: (title, message) => setInfoMessage({ title, message })
124
126
  })
125
127
  const updateManifestDate = updateManifest ? new Date(updateManifest.createdAt) : null
128
+ // The frame below is mounted from the first open on and then kept, so the Dialog's close fade
129
+ // still plays after `visible` turns false. Never mounting it before that keeps a screen that never
130
+ // opens Settings free of the extra (pass-through) layer, mounts the Portal at open time like the
131
+ // Dialog's own Portal always was (so it lands above portals mounted earlier), and means nothing
132
+ // here needs a Paper Portal.Host until the sheet is actually opened. The update and info cards are
133
+ // only reachable from inside the sheet, so they never need it earlier either.
134
+ const [opened, setOpened] = useState(visible)
135
+ if (visible && !opened) setOpened(true)
126
136
 
127
137
  const showLockOrientation = isTouchPrimary && lockOrientation !== undefined && onLockOrientationChange !== undefined
128
138
  const showEdgeGuard = Platform.OS === 'ios' && deferBottomEdgeGestures !== undefined && onDeferBottomEdgeGestures !== undefined
@@ -139,8 +149,9 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
139
149
  // to the turned footprint, with rotated safe-area insets and its own Portal.Host. The Dialog and the
140
150
  // two ConfirmDialogs below portal into THAT host, so they lay out against the turned window with no
141
151
  // transform of their own (hence rotation={0} on the ConfirmDialogs). The frame is pass-through at
142
- // every level and stays mounted with this component, which keeps the Dialog's close fade; at
152
+ // every level and stays mounted once the sheet has opened, which keeps the Dialog's close fade; at
143
153
  // rotation 0 it is an identity frame.
154
+ if (!opened) return null
144
155
  return (
145
156
  <Portal>
146
157
  <RotatedFrame rotation={rotation} rotatedSafeArea portalHost passThrough>
@@ -164,7 +175,7 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
164
175
  {showLockOrientation && (
165
176
  <TouchableRipple onPress={() => onLockOrientationChange!(!lockOrientation)} style={styles.toggleButton} accessibilityLabel={`Lock orientation ${lockOrientation ? 'on' : 'off'}`}>
166
177
  <View style={styles.toggleContent}>
167
- <SettingIcon source={lockOrientation ? 'lock' : 'lock-open-variant-outline'} color={lockOrientation ? colors.secondary : colors.onSurfaceVariant} containerColor={lockOrientation ? colors.secondaryContainer : colors.surfaceVariant} />
178
+ <SettingIcon source={lockOrientation ? 'lock' : 'lock-open-variant-outline'} color={lockOrientation ? colors.tertiary : colors.onSurfaceVariant} containerColor={lockOrientation ? colors.tertiaryContainer : colors.surfaceVariant} />
168
179
  <View style={styles.flexShrink}>
169
180
  <Text variant='bodyLarge' style={{ color: colors.onSurface }}>
170
181
  Lock Orientation
@@ -186,7 +197,7 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
186
197
  {showEdgeGuard && (
187
198
  <TouchableRipple onPress={() => onDeferBottomEdgeGestures!(!deferBottomEdgeGestures)} style={styles.toggleButton} accessibilityLabel={`Edge guard ${deferBottomEdgeGestures ? 'on' : 'off'}`}>
188
199
  <View style={styles.toggleContent}>
189
- <SettingIcon source={deferBottomEdgeGestures ? 'shield-check-outline' : 'shield-off-outline'} color={deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant} containerColor={deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant} />
200
+ <SettingIcon source={deferBottomEdgeGestures ? 'shield-check-outline' : 'shield-off-outline'} color={deferBottomEdgeGestures ? colors.tertiary : colors.onSurfaceVariant} containerColor={deferBottomEdgeGestures ? colors.tertiaryContainer : colors.surfaceVariant} />
190
201
  <View style={styles.flexShrink}>
191
202
  <Text variant='bodyLarge' style={{ color: colors.onSurface }}>
192
203
  Edge Guard