@tastic/hud 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tastic/hud",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
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",
@@ -88,7 +88,7 @@
88
88
  "@infinitetoken/jest-config": "^0.5.2",
89
89
  "@infinitetoken/tsconfig": "^0.6.0",
90
90
  "@rific/auto-paper": "^0.13.3",
91
- "@rific/core": "^0.3.1",
91
+ "@rific/core": "^0.4.0",
92
92
  "@rific/feedback-press": "^0.13.0",
93
93
  "@rific/updater": "^0.7.1",
94
94
  "@shopify/react-native-skia": "^2.14.0",
@@ -117,6 +117,7 @@
117
117
  },
118
118
  "peerDependencies": {
119
119
  "@rific/auto-paper": "^0.13.0",
120
+ "@rific/core": ">=0.4.0",
120
121
  "@rific/feedback-press": ">=0.10.2",
121
122
  "@rific/updater": ">=0.4.0",
122
123
  "@shopify/react-native-skia": ">=2.6.0",
@@ -1,4 +1,5 @@
1
1
  import { AutoAppearancePicker, Dialog, FadingScrollView, useAutoPaperTheme, useBlurModule, useThemeSettings } from '@rific/auto-paper'
2
+ import { useExpoKeepAwake, useKeepAwakeSettings } from '@rific/core'
2
3
  import { Button, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from '@rific/feedback-press'
3
4
  import { useUpdater } from '@rific/updater'
4
5
  import { rotateInsets, useIsTouchPrimaryDevice, useRotation, type ViewRotation } from '@tastic/core'
@@ -56,13 +57,7 @@ export interface BaseSettingsDialogProps {
56
57
  // @tastic/edge-guard's own swizzle is a no-op on every other platform.
57
58
  deferBottomEdgeGestures?: boolean
58
59
  onDeferBottomEdgeGestures?: (value: boolean) => void
59
- // Optional, and always passed as a pair - omit both for an app that doesn't keep the screen awake.
60
- // This dialog only shows and reports the toggle; the app itself keeps the screen on while it's set
61
- // (expo-keep-awake on its match screen), so this package needs no native dependency for it. Shown
62
- // on the same devices as Lock Orientation (see isTouchPrimary below): a desktop/laptop browser
63
- // stays awake on its own while someone is playing with its keyboard or mouse.
64
- keepAwake?: boolean
65
- onKeepAwakeChange?: (value: boolean) => void
60
+ // No Keep Awake props: that row reads @rific/core's Keep Awake setting itself (see showKeepAwake).
66
61
  // Explicit opt-outs for the rows that pull their own state straight from @rific/feedback-press,
67
62
  // @rific/auto-paper, and @rific/updater's own shared contexts/hooks rather than from anything the
68
63
  // caller passes in - unlike Lock Orientation/Edge Guard above, there's no "value" to omit for
@@ -97,7 +92,7 @@ export interface BaseSettingsDialogProps {
97
92
  // is the seam for whatever isn't shared: a game with its own board/difficulty settings (or a stats
98
93
  // backup flow, or anything else genuinely specific to it) renders those below Appearance, not by
99
94
  // forking this component.
100
- export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, keepAwake, onKeepAwakeChange, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps) {
95
+ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }: BaseSettingsDialogProps) {
101
96
  const { colors } = useAutoPaperTheme()
102
97
  const ambientRotation = useRotation()
103
98
  const rotation = rotationOverride ?? ambientRotation
@@ -113,7 +108,7 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
113
108
  // Dialog's own 32pt padding is simply overhung.
114
109
  const insets = rotateInsets(useSafeAreaInsets(), rotation)
115
110
  const sheetWidth = Math.min(overlayStyles.card.maxWidth, (turned ? window.height : window.width) - 2 * Math.max(insets.left, insets.right, SHEET_GUTTER))
116
- // Also gates the Lock Orientation and Keep Awake rows below (alongside their own props) - true
111
+ // Also gates the Lock Orientation and Keep Awake rows below (alongside their own conditions) - true
117
112
  // unconditionally on native (see the hook's own doc), so this only actually excludes a
118
113
  // desktop/laptop browser, where a mouse-driven window has no physical orientation to lock
119
114
  // against; a resize there would just make the setting silently stop reflowing the layout instead
@@ -121,6 +116,8 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
121
116
  const isTouchPrimary = useIsTouchPrimaryDevice()
122
117
  const { settings: hapticSettings, set: setHapticSettings } = useHapticSettings()
123
118
  const { settings: soundSettings, set: setSoundSettings } = useSoundSettings()
119
+ const { settings: keepAwakeSettings, set: setKeepAwakeSettings } = useKeepAwakeSettings()
120
+ const expoKeepAwake = useExpoKeepAwake()
124
121
  // Sound/Haptics toggle themselves: the ripple's automatic press feedback fires on onPressIn,
125
122
  // before onPress applies the toggle, so it reflects the OLD enabled value - backwards from what
126
123
  // a settings toggle should confirm (turning off would click/buzz, turning on would go silent).
@@ -160,7 +157,10 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
160
157
 
161
158
  const showLockOrientation = isTouchPrimary && lockOrientation !== undefined && onLockOrientationChange !== undefined
162
159
  const showEdgeGuard = Platform.OS === 'ios' && deferBottomEdgeGestures !== undefined && onDeferBottomEdgeGestures !== undefined
163
- const showKeepAwake = isTouchPrimary && keepAwake !== undefined && onKeepAwakeChange !== undefined
160
+ // Only in an app that opted in by handing expo-keep-awake to @rific/core's KeepAwakeProvider:
161
+ // without the module the setting would do nothing. On the same devices as Lock Orientation, since a
162
+ // desktop/laptop browser stays awake on its own while someone plays with its keyboard or mouse.
163
+ const showKeepAwake = isTouchPrimary && expoKeepAwake !== undefined
164
164
  const showHaptics = Platform.OS !== 'web' && !hideHaptics
165
165
  const showSound = !hideSound
166
166
  const showAppearance = !hideAppearance
@@ -243,11 +243,11 @@ export function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverr
243
243
  </TouchableRipple>
244
244
  )}
245
245
 
246
- {/* See the keepAwake prop's own doc: the app does the keeping awake, this only toggles it. */}
246
+ {/* The app's own useKeepAwake('game') does the keeping awake; this only flips the shared setting. */}
247
247
  {showKeepAwake && (
248
- <TouchableRipple onPress={() => onKeepAwakeChange!(!keepAwake)} style={styles.toggleButton} accessibilityLabel={`Keep awake ${keepAwake ? 'on' : 'off'}`}>
248
+ <TouchableRipple onPress={() => setKeepAwakeSettings({ enabled: !keepAwakeSettings.enabled })} style={styles.toggleButton} accessibilityLabel={`Keep awake ${keepAwakeSettings.enabled ? 'on' : 'off'}`}>
249
249
  <View style={styles.toggleContent}>
250
- <SettingIcon source={keepAwake ? 'eye' : 'eye-closed'} color={keepAwake ? colors.tertiary : colors.onSurfaceVariant} containerColor={keepAwake ? colors.tertiaryContainer : colors.surfaceVariant} />
250
+ <SettingIcon source={keepAwakeSettings.enabled ? 'eye' : 'eye-closed'} color={keepAwakeSettings.enabled ? colors.tertiary : colors.onSurfaceVariant} containerColor={keepAwakeSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant} />
251
251
  <View style={styles.flexShrink}>
252
252
  <Text variant='bodyLarge' style={{ color: colors.onSurface }}>
253
253
  Keep Awake
@@ -1,8 +1,11 @@
1
1
  // The fleet-chrome entry point (`@tastic/hud/chrome`): the shared dialogs, stats screen pieces, corner
2
- // buttons and style tokens, reachable without the main barrel, for an app that has none of its heavy
3
- // peers. Hangman is the reason it exists: it has @tastic/core, @rific/updater and the Paper stack, but
4
- // no Skia, no @tastic/profile and no @tastic/split-screen. Everything reachable from this file must stay
5
- // free of those three and of the main barrel; @tastic/achievements may appear only as `import type`.
2
+ // buttons, popover primitives, color picker and style tokens, reachable without the main barrel, for an
3
+ // app that has none of its heavy peers. Hangman is the reason it exists: it has @tastic/core,
4
+ // @rific/updater and the Paper stack, but no Skia, no @tastic/profile and no @tastic/split-screen. The
5
+ // popover pieces (PopoverBody, PressAwayOverlay, usePopoverHost, useAutoAlign) and InlineColorPicker are
6
+ // here for @tastic/profile 0.16+, which imports them from this entry instead of the main barrel so its
7
+ // ProfilePicker and ProfilesScreen work in Hangman. Everything reachable from this file must stay free of
8
+ // those three and of the main barrel; @tastic/achievements may appear only as `import type`.
6
9
  // AchievementUnlockList is left out on purpose because it value-imports @tastic/profile's ProfileChip.
7
10
  // src/__tests__/chromeImports.test.ts walks the real import graph from here and enforces all of it.
8
11
  export { AchievementCatalogSection } from '../AchievementCatalogSection'
@@ -15,12 +18,17 @@ export { ContentGutter } from '../ContentGutter'
15
18
  export { CornerActionButtons } from '../CornerActionButtons'
16
19
  export { COMPACT_DIALOG_HEIGHT, DialogHeader, type DialogHeaderProps, isCompactDialogHeight } from '../DialogHeader'
17
20
  export { MONO_FONT } from '../fonts'
21
+ export { getInlineColorPickerContentSize, InlineColorPicker } from '../InlineColorPicker'
18
22
  export { overlayActionStyles, overlayStyles } from '../overlayCard'
19
23
  export { OverlayBackdrop, type OverlayBackdropProps, OverlayCard, type OverlayCardProps, type OverlayCardThemeColors, useOverlayCardColors } from '../OverlaySurface'
24
+ export { PopoverBody } from '../PopoverBody'
25
+ export { PressAwayOverlay } from '../PressAwayOverlay'
20
26
  export { RotatedFrame, type RotatedFrameProps } from '../RotatedFrame'
21
27
  export { getStaggeredWordDuration, StaggeredWord, type StaggeredWordProps } from '../StaggeredWord'
22
28
  export { StatRow } from '../StatRow'
23
29
  export { StatSection } from '../StatSection'
24
30
  export { UpdateDialog, type UpdateDialogProps } from '../UpdateDialog'
31
+ export { type AlignResult, type PopoverAlign, type PopoverRotation, type PopoverVerticalAlign, useAutoAlign } from '../useAutoAlign'
25
32
  export { useCompactDialog } from '../useCompactDialog'
33
+ export { type PopoverHost, usePopoverHost } from '../usePopoverHost'
26
34
  export { useWellColors, WELL_SHADOW, type WellColors } from '../wellSurface'