@tastic/hud 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -80,6 +80,7 @@ declare function getGuideCardSize(windowWidth: number, windowHeight: number, rot
80
80
  pageWidth: number;
81
81
  maxHeight: number;
82
82
  artHeight: number;
83
+ compact: boolean;
83
84
  };
84
85
  interface HowToPlayDialogProps {
85
86
  visible: boolean;
@@ -87,6 +88,8 @@ interface HowToPlayDialogProps {
87
88
  onFinish: () => void;
88
89
  onSkip: () => void;
89
90
  rotation?: GuideRotation;
91
+ title?: string;
92
+ icon?: string;
90
93
  }
91
94
  declare function HowToPlayDialog({ visible, steps, ...rest }: HowToPlayDialogProps): react.JSX.Element | null;
92
95
 
@@ -80,6 +80,7 @@ declare function getGuideCardSize(windowWidth: number, windowHeight: number, rot
80
80
  pageWidth: number;
81
81
  maxHeight: number;
82
82
  artHeight: number;
83
+ compact: boolean;
83
84
  };
84
85
  interface HowToPlayDialogProps {
85
86
  visible: boolean;
@@ -87,6 +88,8 @@ interface HowToPlayDialogProps {
87
88
  onFinish: () => void;
88
89
  onSkip: () => void;
89
90
  rotation?: GuideRotation;
91
+ title?: string;
92
+ icon?: string;
90
93
  }
91
94
  declare function HowToPlayDialog({ visible, steps, ...rest }: HowToPlayDialogProps): react.JSX.Element | null;
92
95
 
@@ -100,23 +100,65 @@ var styles = import_react_native.StyleSheet.create({
100
100
  var import_react2 = require("react");
101
101
 
102
102
  // src/guide/HowToPlayDialog.tsx
103
- var import_auto_paper3 = require("@rific/auto-paper");
103
+ var import_auto_paper4 = require("@rific/auto-paper");
104
104
  var import_feedback_press = require("@rific/feedback-press");
105
105
  var import_react = require("react");
106
- var import_react_native4 = require("react-native");
107
- var import_react_native_paper2 = require("react-native-paper");
106
+ var import_react_native5 = require("react-native");
107
+ var import_react_native_paper3 = require("react-native-paper");
108
108
  var import_react_native_reanimated = require("react-native-reanimated");
109
109
 
110
- // src/overlayCard.ts
110
+ // src/DialogHeader.tsx
111
+ var import_auto_paper2 = require("@rific/auto-paper");
111
112
  var import_react_native2 = require("react-native");
112
- var overlayStyles = import_react_native2.StyleSheet.create({
113
+ var import_react_native_paper2 = require("react-native-paper");
114
+ var import_jsx_runtime2 = require("react/jsx-runtime");
115
+ var COMPACT_DIALOG_HEIGHT = 528;
116
+ function isCompactDialogHeight(height) {
117
+ return height < COMPACT_DIALOG_HEIGHT;
118
+ }
119
+ function DialogHeader({ icon, title, color, compact = false, style }) {
120
+ const { colors } = (0, import_auto_paper2.useAutoPaperTheme)();
121
+ const accent = color ?? colors.primary;
122
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.View, { style: [compact ? styles2.compact : styles2.full, style], children: [
123
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Icon, { source: icon, size: compact ? COMPACT_ICON_SIZE : ICON_SIZE, color: accent }),
124
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_paper2.Text, { accessibilityRole: "header", variant: compact ? "headlineSmall" : "headlineLarge", style: [styles2.title, compact && styles2.titleCompact, { color: accent }], children: title })
125
+ ] });
126
+ }
127
+ var ICON_SIZE = 64;
128
+ var COMPACT_ICON_SIZE = 32;
129
+ var styles2 = import_react_native2.StyleSheet.create({
130
+ compact: {
131
+ alignItems: "center",
132
+ alignSelf: "stretch",
133
+ flexDirection: "row",
134
+ gap: 12,
135
+ justifyContent: "center"
136
+ },
137
+ full: {
138
+ alignItems: "center",
139
+ alignSelf: "stretch",
140
+ gap: 16
141
+ },
142
+ // textAlign matters once a title wraps: the card centers the Text's block, but each wrapped line
143
+ // still defaults to left-aligned without it.
144
+ title: {
145
+ fontWeight: "bold",
146
+ textAlign: "center"
147
+ },
148
+ titleCompact: {
149
+ flexShrink: 1
150
+ }
151
+ });
152
+
153
+ // src/overlayCard.ts
154
+ var import_react_native3 = require("react-native");
155
+ var overlayStyles = import_react_native3.StyleSheet.create({
113
156
  card: {
114
157
  alignItems: "center",
115
- borderRadius: 20,
116
- borderWidth: 1,
158
+ borderRadius: 28,
117
159
  gap: 16,
118
160
  maxWidth: 360,
119
- padding: 32
161
+ padding: 24
120
162
  },
121
163
  overlay: {
122
164
  alignItems: "center",
@@ -129,7 +171,7 @@ var overlayStyles = import_react_native2.StyleSheet.create({
129
171
  top: 0
130
172
  }
131
173
  });
132
- var overlayActionStyles = import_react_native2.StyleSheet.create({
174
+ var overlayActionStyles = import_react_native3.StyleSheet.create({
133
175
  // minWidth (not flexBasis) is each button's real floor - whenever both fit side by side, flexGrow
134
176
  // still splits any leftover width evenly beyond that floor, same visual result as a plain flex: 1
135
177
  // on a roomy screen, but a button can never be squeezed narrower than 128, only wrap to its own
@@ -172,62 +214,63 @@ var overlayActionStyles = import_react_native2.StyleSheet.create({
172
214
  });
173
215
 
174
216
  // src/OverlaySurface.tsx
175
- var import_auto_paper2 = require("@rific/auto-paper");
176
- var import_react_native3 = require("react-native");
177
- var import_jsx_runtime2 = require("react/jsx-runtime");
217
+ var import_auto_paper3 = require("@rific/auto-paper");
218
+ var import_react_native4 = require("react-native");
219
+ var import_jsx_runtime3 = require("react/jsx-runtime");
178
220
  function useOverlayCardColors() {
179
- const { colors } = (0, import_auto_paper2.useAutoPaperTheme)();
221
+ const { colors } = (0, import_auto_paper3.useAutoPaperTheme)();
180
222
  return { fg: colors.onSurface, fgMuted: colors.onSurfaceVariant, cardBorder: colors.outlineVariant, backdrop: colors.backdrop };
181
223
  }
182
- function OverlayBackdrop({ children, style }) {
224
+ function OverlayBackdrop({ children, style, onLayout }) {
183
225
  const { backdrop } = useOverlayCardColors();
184
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native3.View, { style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
226
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { onLayout, style: [overlayStyles.overlay, { backgroundColor: backdrop }, style], children });
185
227
  }
186
228
  function OverlayCard({ children, style, ...rest }) {
187
- const { cardBorder } = useOverlayCardColors();
188
- const blur = (0, import_auto_paper2.useBlur)();
189
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_auto_paper2.BlurView, { blur, elevation: 3, style: [overlayStyles.card, styles2.card, { borderColor: cardBorder }, style], ...rest, children });
229
+ const { isV3, roundness } = (0, import_auto_paper3.useAutoPaperTheme)();
230
+ const blur = (0, import_auto_paper3.useBlur)();
231
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_auto_paper3.BlurView, { blur, style: [overlayStyles.card, styles3.card, { borderRadius: (isV3 ? 7 : 1) * roundness }, style], ...rest, children });
190
232
  }
191
- var styles2 = import_react_native3.StyleSheet.create({
233
+ var styles3 = import_react_native4.StyleSheet.create({
192
234
  card: { overflow: "hidden" }
193
235
  });
194
236
 
195
237
  // src/guide/HowToPlayDialog.tsx
196
- var import_jsx_runtime3 = require("react/jsx-runtime");
238
+ var import_jsx_runtime4 = require("react/jsx-runtime");
197
239
  var OVERLAY_GUTTER = 24;
198
240
  var CARD_PADDING = 24;
199
241
  var MAX_CARD_WIDTH = 360;
200
242
  var MAX_CARD_WIDTH_TURNED = 520;
201
243
  var ART_HEIGHT = 132;
202
- var COMPACT_BELOW = 480;
203
244
  var ART_HEIGHT_COMPACT = 88;
204
245
  function getGuideCardSize(windowWidth, windowHeight, rotation) {
205
246
  const turned = rotation === 90 || rotation === -90;
206
247
  const availableWidth = (turned ? windowHeight : windowWidth) - OVERLAY_GUTTER * 2;
207
248
  const availableHeight = (turned ? windowWidth : windowHeight) - OVERLAY_GUTTER * 2;
208
249
  const width = Math.min(turned ? MAX_CARD_WIDTH_TURNED : MAX_CARD_WIDTH, availableWidth);
250
+ const compact = isCompactDialogHeight(turned ? windowWidth : windowHeight);
209
251
  return {
210
252
  width,
211
253
  pageWidth: width - CARD_PADDING * 2,
212
254
  maxHeight: availableHeight,
213
- artHeight: availableHeight < COMPACT_BELOW ? ART_HEIGHT_COMPACT : ART_HEIGHT
255
+ artHeight: compact ? ART_HEIGHT_COMPACT : ART_HEIGHT,
256
+ compact
214
257
  };
215
258
  }
216
- function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0 }) {
217
- const { dark, colors } = (0, import_auto_paper3.useAutoPaperTheme)();
218
- const { width: windowWidth, height: windowHeight } = (0, import_react_native4.useWindowDimensions)();
259
+ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0, title = "How to Play", icon = "help-circle-outline" }) {
260
+ const { dark, colors } = (0, import_auto_paper4.useAutoPaperTheme)();
261
+ const { width: windowWidth, height: windowHeight } = (0, import_react_native5.useWindowDimensions)();
219
262
  const reducedMotion = (0, import_react_native_reanimated.useReducedMotion)();
220
263
  const [index, setIndex] = (0, import_react.useState)(0);
221
264
  const scrollRef = (0, import_react.useRef)(null);
222
265
  (0, import_react.useEffect)(() => {
223
- const subscription = import_react_native4.BackHandler.addEventListener("hardwareBackPress", () => {
266
+ const subscription = import_react_native5.BackHandler.addEventListener("hardwareBackPress", () => {
224
267
  onSkip();
225
268
  return true;
226
269
  });
227
270
  return () => subscription.remove();
228
271
  }, [onSkip]);
229
272
  const { fg, fgMuted } = useOverlayCardColors();
230
- const { width: cardWidth, pageWidth, maxHeight, artHeight } = getGuideCardSize(windowWidth, windowHeight, rotation);
273
+ const { width: cardWidth, pageWidth, maxHeight, artHeight, compact } = getGuideCardSize(windowWidth, windowHeight, rotation);
231
274
  const rotationStyle = rotation === 0 ? void 0 : { transform: [{ rotate: `${rotation}deg` }] };
232
275
  const isFirst = index === 0;
233
276
  const isLast = index === steps.length - 1;
@@ -255,24 +298,25 @@ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0 }) {
255
298
  targetRef.current = null;
256
299
  syncToOffset(e.nativeEvent.contentOffset.x);
257
300
  }
258
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper2.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OverlayBackdrop, { style: styles3.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(OverlayCard, { accessibilityViewIsModal: true, style: [styles3.card, { width: cardWidth, maxHeight }, rotationStyle], children: [
259
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.ScrollView, { ref: scrollRef, horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll: handleScroll, scrollEventThrottle: 16, onMomentumScrollEnd: handleMomentumEnd, style: [styles3.pager, { width: pageWidth }], children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.ScrollView, { nestedScrollEnabled: true, showsVerticalScrollIndicator: false, style: { width: pageWidth }, contentContainerStyle: styles3.page, children: [
260
- step.art !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.art, { height: artHeight, backgroundColor: artBackground }], children: step.art }),
261
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper2.Text, { variant: "headlineSmall", style: [styles3.title, { color: fg }], children: step.title }),
262
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native_paper2.Text, { variant: "bodyMedium", style: [styles3.body, { color: fg }], children: step.body })
301
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper3.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(OverlayBackdrop, { style: styles4.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(OverlayCard, { accessibilityViewIsModal: true, style: [styles4.card, { width: cardWidth, maxHeight }, rotationStyle], children: [
302
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DialogHeader, { icon, title, compact }),
303
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.ScrollView, { ref: scrollRef, horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll: handleScroll, scrollEventThrottle: 16, onMomentumScrollEnd: handleMomentumEnd, style: [styles4.pager, { width: pageWidth }], children: steps.map((step, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.ScrollView, { nestedScrollEnabled: true, showsVerticalScrollIndicator: false, style: { width: pageWidth }, contentContainerStyle: [styles4.page, compact && styles4.pageCompact], children: [
304
+ step.art !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: [styles4.art, { height: artHeight, backgroundColor: artBackground }], children: step.art }),
305
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper3.Text, { variant: "headlineSmall", style: [styles4.title, { color: fg }], children: step.title }),
306
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper3.Text, { variant: "bodyMedium", style: [styles4.body, { color: fg }], children: step.body })
263
307
  ] }, i)) }),
264
- steps.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { accessible: true, accessibilityLabel: `Step ${index + 1} of ${steps.length}`, style: styles3.dots, children: steps.map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: i === index ? [styles3.dot, { backgroundColor: colors.primary }] : [styles3.dot, styles3.dotInactive, { backgroundColor: fgMuted }] }, i)) }),
265
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: overlayActionStyles.actions, children: [
266
- !isOnly && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: isFirst ? onSkip : () => goTo(index - 1), style: overlayActionStyles.actionButton, children: isFirst ? "Skip" : "Back" }),
267
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_feedback_press.Button, { mode: "contained", onPress: isLast ? onFinish : () => goTo(index + 1), style: isOnly ? overlayActionStyles.actionButtonSingle : overlayActionStyles.actionButton, buttonColor: colors.primary, textColor: colors.onPrimary, children: isLast ? "Ready" : "Next" })
308
+ steps.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { accessible: true, accessibilityLabel: `Step ${index + 1} of ${steps.length}`, style: styles4.dots, children: steps.map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native5.View, { style: i === index ? [styles4.dot, { backgroundColor: colors.primary }] : [styles4.dot, styles4.dotInactive, { backgroundColor: fgMuted }] }, i)) }),
309
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native5.View, { style: overlayActionStyles.actions, children: [
310
+ !isOnly && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: isFirst ? onSkip : () => goTo(index - 1), style: overlayActionStyles.actionButton, children: isFirst ? "Skip" : "Back" }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.Button, { mode: "contained", onPress: isLast ? onFinish : () => goTo(index + 1), style: isOnly ? overlayActionStyles.actionButtonSingle : overlayActionStyles.actionButton, buttonColor: colors.primary, textColor: colors.onPrimary, children: isLast ? "Ready" : "Next" })
268
312
  ] })
269
313
  ] }) }) });
270
314
  }
271
315
  function HowToPlayDialog({ visible, steps, ...rest }) {
272
316
  if (!visible || steps.length === 0) return null;
273
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(HowToPlayCard, { steps, ...rest });
317
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HowToPlayCard, { steps, ...rest });
274
318
  }
275
- var styles3 = import_react_native4.StyleSheet.create({
319
+ var styles4 = import_react_native5.StyleSheet.create({
276
320
  art: {
277
321
  alignItems: "center",
278
322
  borderRadius: 12,
@@ -283,8 +327,7 @@ var styles3 = import_react_native4.StyleSheet.create({
283
327
  body: {
284
328
  textAlign: "center"
285
329
  },
286
- // Additive on top of overlayCard's own shared `card` shape - its default 32px padding is tighter
287
- // here (a paged card wants more width for its art) and the shared 16px gap is right.
330
+ // overlayCard's shared `card` padding, restated: the page width above is computed from it.
288
331
  card: {
289
332
  padding: CARD_PADDING
290
333
  },
@@ -307,6 +350,11 @@ var styles3 = import_react_native4.StyleSheet.create({
307
350
  alignItems: "center",
308
351
  gap: 12
309
352
  },
353
+ // The 8pt this saves is what the compact dialog header cost a page on a 402pt-tall window (a
354
+ // Pro-size iPhone held sideways, measured on web): without it the body's second line scrolled.
355
+ pageCompact: {
356
+ gap: 8
357
+ },
310
358
  pager: {
311
359
  flexShrink: 1
312
360
  },
@@ -317,7 +365,7 @@ var styles3 = import_react_native4.StyleSheet.create({
317
365
  });
318
366
 
319
367
  // src/guide/GuideProvider.tsx
320
- var import_jsx_runtime4 = require("react/jsx-runtime");
368
+ var import_jsx_runtime5 = require("react/jsx-runtime");
321
369
  var noop = () => {
322
370
  };
323
371
  var GuideContext = (0, import_react2.createContext)({ isOpen: false, open: noop, close: noop, requestAutoShow: noop });
@@ -336,9 +384,9 @@ function GuideProvider({ steps, currentVersion, seenVersion, onSeen, rotation, c
336
384
  setIsOpen(true);
337
385
  }, [unseen]);
338
386
  const value = (0, import_react2.useMemo)(() => ({ isOpen, open, close, requestAutoShow }), [isOpen, open, close, requestAutoShow]);
339
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(GuideContext.Provider, { value, children: [
387
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(GuideContext.Provider, { value, children: [
340
388
  children,
341
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HowToPlayDialog, { visible: isOpen, steps, onFinish: close, onSkip: close, rotation })
389
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HowToPlayDialog, { visible: isOpen, steps, onFinish: close, onSkip: close, rotation })
342
390
  ] });
343
391
  }
344
392
  function useGuide() {
@@ -391,27 +439,27 @@ function createReturningPlayerMigrate(storage, legacyKeys) {
391
439
  }
392
440
 
393
441
  // src/guide/SeatDevicesHint.tsx
394
- var import_auto_paper4 = require("@rific/auto-paper");
395
- var import_react_native5 = require("react-native");
396
- var import_react_native_paper3 = require("react-native-paper");
397
- var import_jsx_runtime5 = require("react/jsx-runtime");
442
+ var import_auto_paper5 = require("@rific/auto-paper");
443
+ var import_react_native6 = require("react-native");
444
+ var import_react_native_paper4 = require("react-native-paper");
445
+ var import_jsx_runtime6 = require("react/jsx-runtime");
398
446
  var ICON = {
399
447
  keyboard: { source: "keyboard-outline", size: 56 },
400
448
  mouse: { source: "mouse-outline", size: 44 }
401
449
  };
402
450
  var ORDER = ["keyboard", "mouse"];
403
451
  function SeatDevicesHint({ devices, seatColors }) {
404
- const { colors } = (0, import_auto_paper4.useAutoPaperTheme)();
452
+ const { colors } = (0, import_auto_paper5.useAutoPaperTheme)();
405
453
  const tints = seatColors ?? [colors.primary, colors.secondary];
406
454
  const accessibilityLabel = devices.map((device, i) => `Player ${i + 1} uses the ${device}`).join(", ");
407
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { accessible: true, accessibilityLabel, style: styles4.row, children: ORDER.map((device) => {
455
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.View, { accessible: true, accessibilityLabel, style: styles5.row, children: ORDER.map((device) => {
408
456
  const seats = devices.flatMap((d, i) => d === device ? [i] : []);
409
457
  if (seats.length === 0) return null;
410
458
  const color = seats.length === 1 ? tints[seats[0]] ?? colors.onSurface : colors.onSurface;
411
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Icon, { source: ICON[device].source, size: ICON[device].size, color }, device);
459
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Icon, { source: ICON[device].source, size: ICON[device].size, color }, device);
412
460
  }) });
413
461
  }
414
- var styles4 = import_react_native5.StyleSheet.create({
462
+ var styles5 = import_react_native6.StyleSheet.create({
415
463
  row: {
416
464
  alignItems: "center",
417
465
  flexDirection: "row",
@@ -420,28 +468,28 @@ var styles4 = import_react_native5.StyleSheet.create({
420
468
  });
421
469
 
422
470
  // src/guide/SeatDiagram.tsx
423
- var import_auto_paper5 = require("@rific/auto-paper");
424
- var import_react_native6 = require("react-native");
425
- var import_react_native_paper4 = require("react-native-paper");
426
- var import_jsx_runtime6 = require("react/jsx-runtime");
471
+ var import_auto_paper6 = require("@rific/auto-paper");
472
+ var import_react_native7 = require("react-native");
473
+ var import_react_native_paper5 = require("react-native-paper");
474
+ var import_jsx_runtime7 = require("react/jsx-runtime");
427
475
  var DEVICE_WIDTH = 88;
428
476
  var DEVICE_HEIGHT = 120;
429
477
  function SeatDiagram({ topColor, bottomColor, topLabel = "P2", bottomLabel = "P1" }) {
430
- const { colors } = (0, import_auto_paper5.useAutoPaperTheme)();
478
+ const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
431
479
  const top = topColor ?? colors.secondary;
432
480
  const bottom = bottomColor ?? colors.primary;
433
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { accessible: true, accessibilityLabel: `${bottomLabel} plays the bottom half, ${topLabel} plays the top half`, style: [styles5.device, { borderColor: colors.onSurface }], children: [
434
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: [styles5.half, { borderColor: top }], children: [
435
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.View, { style: [import_react_native6.StyleSheet.absoluteFill, styles5.tint, { backgroundColor: top }] }),
436
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Text, { variant: "titleMedium", style: [styles5.label, styles5.flipped, { color: top }], children: topLabel })
481
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { accessible: true, accessibilityLabel: `${bottomLabel} plays the bottom half, ${topLabel} plays the top half`, style: [styles6.device, { borderColor: colors.onSurface }], children: [
482
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: [styles6.half, { borderColor: top }], children: [
483
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: [import_react_native7.StyleSheet.absoluteFill, styles6.tint, { backgroundColor: top }] }),
484
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { variant: "titleMedium", style: [styles6.label, styles6.flipped, { color: top }], children: topLabel })
437
485
  ] }),
438
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native6.View, { style: [styles5.half, styles5.bottomHalf, { borderColor: bottom }], children: [
439
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.View, { style: [import_react_native6.StyleSheet.absoluteFill, styles5.tint, { backgroundColor: bottom }] }),
440
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Text, { variant: "titleMedium", style: [styles5.label, { color: bottom }], children: bottomLabel })
486
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { style: [styles6.half, styles6.bottomHalf, { borderColor: bottom }], children: [
487
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: [import_react_native7.StyleSheet.absoluteFill, styles6.tint, { backgroundColor: bottom }] }),
488
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { variant: "titleMedium", style: [styles6.label, { color: bottom }], children: bottomLabel })
441
489
  ] })
442
490
  ] });
443
491
  }
444
- var styles5 = import_react_native6.StyleSheet.create({
492
+ var styles6 = import_react_native7.StyleSheet.create({
445
493
  bottomHalf: {
446
494
  borderTopWidth: 0
447
495
  },
@@ -472,12 +520,12 @@ var styles5 = import_react_native6.StyleSheet.create({
472
520
  });
473
521
 
474
522
  // src/guide/SwipeHint.tsx
475
- var import_auto_paper6 = require("@rific/auto-paper");
523
+ var import_auto_paper7 = require("@rific/auto-paper");
476
524
  var import_react3 = require("react");
477
- var import_react_native7 = require("react-native");
478
- var import_react_native_paper5 = require("react-native-paper");
525
+ var import_react_native8 = require("react-native");
526
+ var import_react_native_paper6 = require("react-native-paper");
479
527
  var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
480
- var import_jsx_runtime7 = require("react/jsx-runtime");
528
+ var import_jsx_runtime8 = require("react/jsx-runtime");
481
529
  var DOT_COUNT = 7;
482
530
  var FINGER_SIZE = 28;
483
531
  var MOUSE_SIZE = 30;
@@ -485,7 +533,7 @@ var SWEEP_MS = 900;
485
533
  var PAUSE_MS = 500;
486
534
  var ARROW_ICON = { up: "arrow-up", down: "arrow-down", left: "arrow-left", right: "arrow-right" };
487
535
  function SwipeHint({ direction = "right", pointer = "finger", color, length = 96 }) {
488
- const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
536
+ const { colors } = (0, import_auto_paper7.useAutoPaperTheme)();
489
537
  const tint = color ?? colors.primary;
490
538
  const reducedMotion = (0, import_react_native_reanimated2.useReducedMotion)();
491
539
  const progress = (0, import_react_native_reanimated2.useSharedValue)(0.5);
@@ -507,13 +555,13 @@ function SwipeHint({ direction = "right", pointer = "finger", color, length = 96
507
555
  };
508
556
  });
509
557
  const axis = horizontal ? sign > 0 ? "row" : "row-reverse" : sign > 0 ? "column" : "column-reverse";
510
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native7.View, { accessibilityLabel: `${pointer === "mouse" ? "Drag" : "Swipe"} ${direction}`, accessible: true, style: [styles6.path, { flexDirection: axis }], children: [
511
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: [styles6.dots, { flexDirection: axis, [horizontal ? "width" : "height"]: length }], children: Array.from({ length: DOT_COUNT }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native7.View, { style: [styles6.dot, { backgroundColor: tint, opacity: 0.35 + 0.65 * i / (DOT_COUNT - 1) }] }, i)) }),
512
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Icon, { source: ARROW_ICON[direction], size: 28, color: tint }),
513
- pointer === "mouse" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_reanimated2.default.View, { style: [styles6.mouse, fingerStyle], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Icon, { source: "mouse", size: MOUSE_SIZE, color: tint }) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_reanimated2.default.View, { style: [styles6.finger, { borderColor: tint }, fingerStyle] })
558
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native8.View, { accessibilityLabel: `${pointer === "mouse" ? "Drag" : "Swipe"} ${direction}`, accessible: true, style: [styles7.path, { flexDirection: axis }], children: [
559
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { style: [styles7.dots, { flexDirection: axis, [horizontal ? "width" : "height"]: length }], children: Array.from({ length: DOT_COUNT }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native8.View, { style: [styles7.dot, { backgroundColor: tint, opacity: 0.35 + 0.65 * i / (DOT_COUNT - 1) }] }, i)) }),
560
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Icon, { source: ARROW_ICON[direction], size: 28, color: tint }),
561
+ pointer === "mouse" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_reanimated2.default.View, { style: [styles7.mouse, fingerStyle], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper6.Icon, { source: "mouse", size: MOUSE_SIZE, color: tint }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_reanimated2.default.View, { style: [styles7.finger, { borderColor: tint }, fingerStyle] })
514
562
  ] });
515
563
  }
516
- var styles6 = import_react_native7.StyleSheet.create({
564
+ var styles7 = import_react_native8.StyleSheet.create({
517
565
  dot: {
518
566
  borderRadius: 3,
519
567
  height: 6,
@@ -1,9 +1,11 @@
1
1
  import {
2
+ DialogHeader,
2
3
  OverlayBackdrop,
3
4
  OverlayCard,
5
+ isCompactDialogHeight,
4
6
  overlayActionStyles,
5
7
  useOverlayCardColors
6
- } from "../chunk-AX4GC5KU.mjs";
8
+ } from "../chunk-PUF6TABL.mjs";
7
9
 
8
10
  // src/guide/DirectionKeysHint.tsx
9
11
  import { useAutoPaperTheme } from "@rific/auto-paper";
@@ -73,21 +75,22 @@ var CARD_PADDING = 24;
73
75
  var MAX_CARD_WIDTH = 360;
74
76
  var MAX_CARD_WIDTH_TURNED = 520;
75
77
  var ART_HEIGHT = 132;
76
- var COMPACT_BELOW = 480;
77
78
  var ART_HEIGHT_COMPACT = 88;
78
79
  function getGuideCardSize(windowWidth, windowHeight, rotation) {
79
80
  const turned = rotation === 90 || rotation === -90;
80
81
  const availableWidth = (turned ? windowHeight : windowWidth) - OVERLAY_GUTTER * 2;
81
82
  const availableHeight = (turned ? windowWidth : windowHeight) - OVERLAY_GUTTER * 2;
82
83
  const width = Math.min(turned ? MAX_CARD_WIDTH_TURNED : MAX_CARD_WIDTH, availableWidth);
84
+ const compact = isCompactDialogHeight(turned ? windowWidth : windowHeight);
83
85
  return {
84
86
  width,
85
87
  pageWidth: width - CARD_PADDING * 2,
86
88
  maxHeight: availableHeight,
87
- artHeight: availableHeight < COMPACT_BELOW ? ART_HEIGHT_COMPACT : ART_HEIGHT
89
+ artHeight: compact ? ART_HEIGHT_COMPACT : ART_HEIGHT,
90
+ compact
88
91
  };
89
92
  }
90
- function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0 }) {
93
+ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0, title = "How to Play", icon = "help-circle-outline" }) {
91
94
  const { dark, colors } = useAutoPaperTheme2();
92
95
  const { width: windowWidth, height: windowHeight } = useWindowDimensions();
93
96
  const reducedMotion = useReducedMotion();
@@ -101,7 +104,7 @@ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0 }) {
101
104
  return () => subscription.remove();
102
105
  }, [onSkip]);
103
106
  const { fg, fgMuted } = useOverlayCardColors();
104
- const { width: cardWidth, pageWidth, maxHeight, artHeight } = getGuideCardSize(windowWidth, windowHeight, rotation);
107
+ const { width: cardWidth, pageWidth, maxHeight, artHeight, compact } = getGuideCardSize(windowWidth, windowHeight, rotation);
105
108
  const rotationStyle = rotation === 0 ? void 0 : { transform: [{ rotate: `${rotation}deg` }] };
106
109
  const isFirst = index === 0;
107
110
  const isLast = index === steps.length - 1;
@@ -130,7 +133,8 @@ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0 }) {
130
133
  syncToOffset(e.nativeEvent.contentOffset.x);
131
134
  }
132
135
  return /* @__PURE__ */ jsx2(Portal, { children: /* @__PURE__ */ jsx2(OverlayBackdrop, { style: styles2.overlay, children: /* @__PURE__ */ jsxs2(OverlayCard, { accessibilityViewIsModal: true, style: [styles2.card, { width: cardWidth, maxHeight }, rotationStyle], children: [
133
- /* @__PURE__ */ jsx2(ScrollView, { ref: scrollRef, horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll: handleScroll, scrollEventThrottle: 16, onMomentumScrollEnd: handleMomentumEnd, style: [styles2.pager, { width: pageWidth }], children: steps.map((step, i) => /* @__PURE__ */ jsxs2(ScrollView, { nestedScrollEnabled: true, showsVerticalScrollIndicator: false, style: { width: pageWidth }, contentContainerStyle: styles2.page, children: [
136
+ /* @__PURE__ */ jsx2(DialogHeader, { icon, title, compact }),
137
+ /* @__PURE__ */ jsx2(ScrollView, { ref: scrollRef, horizontal: true, pagingEnabled: true, showsHorizontalScrollIndicator: false, onScroll: handleScroll, scrollEventThrottle: 16, onMomentumScrollEnd: handleMomentumEnd, style: [styles2.pager, { width: pageWidth }], children: steps.map((step, i) => /* @__PURE__ */ jsxs2(ScrollView, { nestedScrollEnabled: true, showsVerticalScrollIndicator: false, style: { width: pageWidth }, contentContainerStyle: [styles2.page, compact && styles2.pageCompact], children: [
134
138
  step.art !== void 0 && /* @__PURE__ */ jsx2(View2, { style: [styles2.art, { height: artHeight, backgroundColor: artBackground }], children: step.art }),
135
139
  /* @__PURE__ */ jsx2(Text2, { variant: "headlineSmall", style: [styles2.title, { color: fg }], children: step.title }),
136
140
  /* @__PURE__ */ jsx2(Text2, { variant: "bodyMedium", style: [styles2.body, { color: fg }], children: step.body })
@@ -157,8 +161,7 @@ var styles2 = StyleSheet2.create({
157
161
  body: {
158
162
  textAlign: "center"
159
163
  },
160
- // Additive on top of overlayCard's own shared `card` shape - its default 32px padding is tighter
161
- // here (a paged card wants more width for its art) and the shared 16px gap is right.
164
+ // overlayCard's shared `card` padding, restated: the page width above is computed from it.
162
165
  card: {
163
166
  padding: CARD_PADDING
164
167
  },
@@ -181,6 +184,11 @@ var styles2 = StyleSheet2.create({
181
184
  alignItems: "center",
182
185
  gap: 12
183
186
  },
187
+ // The 8pt this saves is what the compact dialog header cost a page on a 402pt-tall window (a
188
+ // Pro-size iPhone held sideways, measured on web): without it the body's second line scrolled.
189
+ pageCompact: {
190
+ gap: 8
191
+ },
184
192
  pager: {
185
193
  flexShrink: 1
186
194
  },
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardColors, OverlayCardProps, OverlayCardThemeColors, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, getOverlayCardColors, getStaggeredWordDuration, overlayActionStyles, overlayStyles, useOverlayCardColors } from './chrome/index.mjs';
1
+ export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors } from './chrome/index.mjs';
2
2
  import * as react from 'react';
3
3
  import { RefObject, ReactNode } from 'react';
4
4
  import { AchievementTier } from '@tastic/achievements';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardColors, OverlayCardProps, OverlayCardThemeColors, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, getOverlayCardColors, getStaggeredWordDuration, overlayActionStyles, overlayStyles, useOverlayCardColors } from './chrome/index.js';
1
+ export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors } from './chrome/index.js';
2
2
  import * as react from 'react';
3
3
  import { RefObject, ReactNode } from 'react';
4
4
  import { AchievementTier } from '@tastic/achievements';