@tastic/hud 0.24.0 → 0.25.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.
@@ -24,17 +24,18 @@ import {
24
24
  useCompactDialog,
25
25
  usePopoverHost,
26
26
  useWellColors
27
- } from "../chunk-BXG44LIA.mjs";
27
+ } from "../chunk-AJD4FMG5.mjs";
28
28
  import {
29
29
  COMPACT_DIALOG_HEIGHT,
30
30
  DialogHeader,
31
31
  OverlayBackdrop,
32
32
  OverlayCard,
33
+ SecondaryButton,
33
34
  isCompactDialogHeight,
34
35
  overlayActionStyles,
35
36
  overlayStyles,
36
37
  useOverlayCardColors
37
- } from "../chunk-PUF6TABL.mjs";
38
+ } from "../chunk-CBH7GQKI.mjs";
38
39
  export {
39
40
  AchievementCatalogSection,
40
41
  AchievementRow,
@@ -54,6 +55,7 @@ export {
54
55
  PopoverBody,
55
56
  PressAwayOverlay,
56
57
  RotatedFrame,
58
+ SecondaryButton,
57
59
  StaggeredWord,
58
60
  StatRow,
59
61
  StatSection,
@@ -2,11 +2,12 @@ import {
2
2
  DialogHeader,
3
3
  OverlayBackdrop,
4
4
  OverlayCard,
5
+ SecondaryButton,
5
6
  isCompactDialogHeight,
6
7
  overlayActionStyles,
7
8
  overlayStyles,
8
9
  useOverlayCardColors
9
- } from "./chunk-PUF6TABL.mjs";
10
+ } from "./chunk-CBH7GQKI.mjs";
10
11
 
11
12
  // src/wellSurface.ts
12
13
  import { useAutoPaperTheme } from "@rific/auto-paper";
@@ -223,7 +224,7 @@ function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onC
223
224
  /* @__PURE__ */ jsx6(DialogHeader, { icon, title, color: accent, compact }),
224
225
  /* @__PURE__ */ jsx6(Text5, { variant: "bodyLarge", style: [styles5.body, { color: fg }], children: message }),
225
226
  /* @__PURE__ */ jsxs6(View4, { style: overlayActionStyles.actions, children: [
226
- showCancel && /* @__PURE__ */ jsx6(Button, { mode: "outlined", onPress: onCancel, style: overlayActionStyles.actionButton, children: cancelLabel }),
227
+ showCancel && /* @__PURE__ */ jsx6(SecondaryButton, { onPress: onCancel, children: cancelLabel }),
227
228
  /* @__PURE__ */ jsx6(Button, { mode: "contained", onPress: onConfirm, style: showCancel ? overlayActionStyles.actionButton : overlayActionStyles.actionButtonSingle, buttonColor: accent, textColor: onAccent, children: confirmLabel })
228
229
  ] })
229
230
  ] }) }) });
@@ -714,7 +715,7 @@ var styles10 = StyleSheet10.create({
714
715
  });
715
716
 
716
717
  // src/useAutoAlign.ts
717
- import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef3, useState as useState5 } from "react";
718
+ import { useEffect as useEffect2, useRef as useRef3, useState as useState5 } from "react";
718
719
  import { useWindowDimensions as useWindowDimensions4 } from "react-native";
719
720
  var EDGE_MARGIN = 12;
720
721
  function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
@@ -726,7 +727,7 @@ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
726
727
  const [newDx, newDy, newWidth, newHeight] = rotation === 180 ? [-dx, -dy, width, height] : rotation === 90 ? [-dy, dx, height, width] : [dy, -dx, height, width];
727
728
  return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
728
729
  }
729
- function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
730
+ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0, bounds) {
730
731
  const triggerRef = useRef3(null);
731
732
  const { width: windowWidth, height: windowHeight } = useWindowDimensions4();
732
733
  const [align, setAlign] = useState5("center");
@@ -738,26 +739,34 @@ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
738
739
  setPrevOpen(open);
739
740
  if (open) setMeasured(false);
740
741
  }
741
- const measure = useCallback3(() => {
742
- triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
742
+ useEffect2(() => {
743
+ if (!open) return;
744
+ const place = (limits) => (rawX, rawY, rawWidth, rawHeight) => {
743
745
  const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
744
746
  const centerX = x + triggerWidth / 2;
745
- const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
746
- const overflowsLeft = centerX - contentWidth / 2 < EDGE_MARGIN;
747
+ const overflowsRight = centerX + contentWidth / 2 > limits.right - EDGE_MARGIN;
748
+ const overflowsLeft = centerX - contentWidth / 2 < limits.left + EDGE_MARGIN;
747
749
  if (overflowsRight && !overflowsLeft) setAlign("right");
748
750
  else if (overflowsLeft && !overflowsRight) setAlign("left");
749
751
  else setAlign("center");
750
- const roomBelow = windowHeight - (y + triggerHeight) - EDGE_MARGIN;
751
- const roomAbove = y - EDGE_MARGIN;
752
+ const roomBelow = limits.bottom - (y + triggerHeight) - EDGE_MARGIN;
753
+ const roomAbove = y - limits.top - EDGE_MARGIN;
752
754
  const above = contentHeight > roomBelow && roomAbove > roomBelow;
753
755
  setVerticalAlign(above ? "above" : "below");
754
756
  setMaxHeight(Math.max(above ? roomAbove : roomBelow, 0));
755
757
  setMeasured(true);
758
+ };
759
+ const screen = { left: 0, top: 0, right: windowWidth, bottom: windowHeight };
760
+ const boundsView = bounds?.current;
761
+ if (!boundsView) {
762
+ triggerRef.current?.measureInWindow(place(screen));
763
+ return;
764
+ }
765
+ boundsView.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
766
+ const b = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
767
+ triggerRef.current?.measureInWindow(place({ left: Math.max(b.x, 0), top: Math.max(b.y, 0), right: Math.min(b.x + b.width, windowWidth), bottom: Math.min(b.y + b.height, windowHeight) }));
756
768
  });
757
- }, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
758
- useEffect2(() => {
759
- if (open) measure();
760
- }, [open, measure]);
769
+ }, [open, contentWidth, contentHeight, windowWidth, windowHeight, rotation, bounds]);
761
770
  return { align, maxHeight, measured, triggerRef, verticalAlign };
762
771
  }
763
772
 
@@ -790,6 +799,7 @@ import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
790
799
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
791
800
  var DEFAULT_SIZE = 48;
792
801
  var SWATCH_SIZE = 28;
802
+ var SWATCH_RING_WIDTH = 2;
793
803
  var SWATCHES_PADDING = 8;
794
804
  var SWATCHES_GAP = 6;
795
805
  var SWATCHES_BORDER_WIDTH = 2;
@@ -807,14 +817,17 @@ function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
807
817
  const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
808
818
  return { width, height };
809
819
  }
810
- function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
820
+ function SwatchDrawing({ size, children }) {
821
+ return /* @__PURE__ */ jsx13(View11, { style: [styles12.drawing, { borderRadius: size / 2, height: size, width: size }], children });
822
+ }
823
+ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE, renderSwatch, bounds }) {
811
824
  const ambientRotation = useRotation4();
812
825
  const rotation = rotationOverride ?? ambientRotation;
813
826
  const menuBg = dark ? "#000000" : "#FFFFFF";
814
827
  const { width: windowWidth } = useWindowDimensions5();
815
828
  const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
816
829
  const open = host.openId === id;
817
- const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
830
+ const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation, bounds);
818
831
  const placement = alignOverride ?? auto;
819
832
  const { maxHeight, measured, triggerRef, verticalAlign } = placement;
820
833
  const align = forcedAlign ?? placement.align;
@@ -822,13 +835,21 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
822
835
  const displayValue = displayFor(value);
823
836
  const contrastColor = getContrastColor(displayValue);
824
837
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
838
+ const triggerDrawing = renderSwatch?.(displayValue, size, "trigger") ?? null;
825
839
  return /* @__PURE__ */ jsxs12(View11, { style: [styles12.anchor, open && styles12.anchorOpen], children: [
826
- /* @__PURE__ */ jsx13(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles12.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx13(View11, { ref: triggerRef, collapsable: false, style: styles12.triggerMeasure, children: tag ? /* @__PURE__ */ jsx13(Text8, { style: [styles12.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx13(Icon3, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
840
+ /* @__PURE__ */ jsx13(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles12.trigger, triggerDrawing === null && { backgroundColor: displayValue }, { borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsxs12(View11, { ref: triggerRef, collapsable: false, style: styles12.triggerMeasure, children: [
841
+ triggerDrawing !== null && /* @__PURE__ */ jsx13(SwatchDrawing, { size, children: triggerDrawing }),
842
+ tag ? /* @__PURE__ */ jsx13(Text8, { style: [styles12.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx13(Icon3, { source: icon, size: size * 0.6, color: contrastColor })
843
+ ] }) }),
827
844
  /* @__PURE__ */ jsx13(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx13(ScrollView, { style: [styles12.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles12.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
828
845
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
829
846
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
830
847
  const swappable = taken && allowSwapTaken;
831
848
  const swatchDisplay = displayFor(swatch.value);
849
+ const contrast = getContrastColor(swatchDisplay);
850
+ const drawnSize = selected ? SWATCH_SIZE - 2 * SWATCH_RING_WIDTH : SWATCH_SIZE;
851
+ const drawing = renderSwatch?.(swatchDisplay, drawnSize, "swatch") ?? null;
852
+ const mark = selected ? /* @__PURE__ */ jsx13(Icon3, { source: "check", size: 16, color: contrast }) : swappable ? /* @__PURE__ */ jsx13(Icon3, { source: "swap-horizontal", size: 16, color: contrast }) : taken ? /* @__PURE__ */ jsx13(Icon3, { source: "close", size: 16, color: contrast }) : /* @__PURE__ */ jsx13(View11, {});
832
853
  return /* @__PURE__ */ jsx13(
833
854
  TouchableRipple2,
834
855
  {
@@ -838,8 +859,11 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
838
859
  if (autoDismiss) host.close();
839
860
  },
840
861
  borderless: true,
841
- style: [styles12.swatch, { backgroundColor: swatchDisplay }, selected && styles12.swatchSelected, taken && !swappable && styles12.swatchTaken],
842
- children: selected ? /* @__PURE__ */ jsx13(Icon3, { source: "check", size: 16, color: getContrastColor(swatchDisplay) }) : swappable ? /* @__PURE__ */ jsx13(Icon3, { source: "swap-horizontal", size: 16, color: getContrastColor(swatchDisplay) }) : taken ? /* @__PURE__ */ jsx13(Icon3, { source: "close", size: 16, color: getContrastColor(swatchDisplay) }) : /* @__PURE__ */ jsx13(View11, {})
862
+ style: [styles12.swatch, drawing === null && { backgroundColor: swatchDisplay }, selected && styles12.swatchSelected, taken && !swappable && styles12.swatchTaken],
863
+ children: drawing !== null ? /* @__PURE__ */ jsxs12(View11, { style: styles12.swatchFace, children: [
864
+ /* @__PURE__ */ jsx13(SwatchDrawing, { size: drawnSize, children: drawing }),
865
+ mark
866
+ ] }) : mark
843
867
  },
844
868
  swatch.value
845
869
  );
@@ -856,6 +880,14 @@ var styles12 = StyleSheet12.create({
856
880
  anchorOpen: {
857
881
  zIndex: 100
858
882
  },
883
+ // A renderSwatch drawing (see SwatchDrawing).
884
+ drawing: {
885
+ left: 0,
886
+ overflow: "hidden",
887
+ pointerEvents: "none",
888
+ position: "absolute",
889
+ top: 0
890
+ },
859
891
  swatch: {
860
892
  alignItems: "center",
861
893
  borderRadius: SWATCH_SIZE / 2,
@@ -863,9 +895,19 @@ var styles12 = StyleSheet12.create({
863
895
  justifyContent: "center",
864
896
  width: SWATCH_SIZE
865
897
  },
898
+ // A drawn swatch (see SwatchDrawing) and its mark: the whole circle inside the selected one's ring.
899
+ swatchFace: {
900
+ alignItems: "center",
901
+ bottom: 0,
902
+ justifyContent: "center",
903
+ left: 0,
904
+ position: "absolute",
905
+ right: 0,
906
+ top: 0
907
+ },
866
908
  swatchSelected: {
867
909
  borderColor: "#ffffff",
868
- borderWidth: 2
910
+ borderWidth: SWATCH_RING_WIDTH
869
911
  },
870
912
  swatchTaken: {
871
913
  opacity: 0.35
@@ -918,13 +960,13 @@ var styles12 = StyleSheet12.create({
918
960
  });
919
961
 
920
962
  // src/usePopoverHost.ts
921
- import { useCallback as useCallback4, useState as useState6 } from "react";
963
+ import { useCallback as useCallback3, useState as useState6 } from "react";
922
964
  function usePopoverHost() {
923
965
  const [openId, setOpenId] = useState6(null);
924
- const toggle = useCallback4((id) => {
966
+ const toggle = useCallback3((id) => {
925
967
  setOpenId((prev) => prev === id ? null : id);
926
968
  }, []);
927
- const close = useCallback4(() => setOpenId(null), []);
969
+ const close = useCallback3(() => setOpenId(null), []);
928
970
  return { openId, toggle, close };
929
971
  }
930
972
 
@@ -125,6 +125,14 @@ var styles2 = StyleSheet3.create({
125
125
  card: { overflow: "hidden" }
126
126
  });
127
127
 
128
+ // src/SecondaryButton.tsx
129
+ import { Button } from "@rific/feedback-press";
130
+ import { jsx as jsx3 } from "react/jsx-runtime";
131
+ function SecondaryButton({ style, ...props }) {
132
+ const { fg } = useOverlayCardColors();
133
+ return /* @__PURE__ */ jsx3(Button, { mode: "outlined", textColor: fg, ...props, style: [overlayActionStyles.actionButton, style] });
134
+ }
135
+
128
136
  export {
129
137
  COMPACT_DIALOG_HEIGHT,
130
138
  isCompactDialogHeight,
@@ -133,5 +141,6 @@ export {
133
141
  overlayActionStyles,
134
142
  useOverlayCardColors,
135
143
  OverlayBackdrop,
136
- OverlayCard
144
+ OverlayCard,
145
+ SecondaryButton
137
146
  };
@@ -101,7 +101,7 @@ var import_react2 = require("react");
101
101
 
102
102
  // src/guide/HowToPlayDialog.tsx
103
103
  var import_auto_paper4 = require("@rific/auto-paper");
104
- var import_feedback_press = require("@rific/feedback-press");
104
+ var import_feedback_press2 = require("@rific/feedback-press");
105
105
  var import_react = require("react");
106
106
  var import_react_native5 = require("react-native");
107
107
  var import_react_native_paper3 = require("react-native-paper");
@@ -234,8 +234,16 @@ var styles3 = import_react_native4.StyleSheet.create({
234
234
  card: { overflow: "hidden" }
235
235
  });
236
236
 
237
- // src/guide/HowToPlayDialog.tsx
237
+ // src/SecondaryButton.tsx
238
+ var import_feedback_press = require("@rific/feedback-press");
238
239
  var import_jsx_runtime4 = require("react/jsx-runtime");
240
+ function SecondaryButton({ style, ...props }) {
241
+ const { fg } = useOverlayCardColors();
242
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press.Button, { mode: "outlined", textColor: fg, ...props, style: [overlayActionStyles.actionButton, style] });
243
+ }
244
+
245
+ // src/guide/HowToPlayDialog.tsx
246
+ var import_jsx_runtime5 = require("react/jsx-runtime");
239
247
  var OVERLAY_GUTTER = 24;
240
248
  var CARD_PADDING = 24;
241
249
  var MAX_CARD_WIDTH = 360;
@@ -298,23 +306,23 @@ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0, title = "How to
298
306
  targetRef.current = null;
299
307
  syncToOffset(e.nativeEvent.contentOffset.x);
300
308
  }
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 })
309
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OverlayBackdrop, { style: styles4.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(OverlayCard, { accessibilityViewIsModal: true, style: [styles4.card, { width: cardWidth, maxHeight }, rotationStyle], children: [
310
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DialogHeader, { icon, title, compact }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.jsxs)(import_react_native5.ScrollView, { nestedScrollEnabled: true, showsVerticalScrollIndicator: false, style: { width: pageWidth }, contentContainerStyle: [styles4.page, compact && styles4.pageCompact], children: [
312
+ step.art !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [styles4.art, { height: artHeight, backgroundColor: artBackground }], children: step.art }),
313
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { variant: "headlineSmall", style: [styles4.title, { color: fg }], children: step.title }),
314
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { variant: "bodyMedium", style: [styles4.body, { color: fg }], children: step.body })
307
315
  ] }, i)) }),
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" })
316
+ steps.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.jsx)(import_react_native5.View, { style: i === index ? [styles4.dot, { backgroundColor: colors.primary }] : [styles4.dot, styles4.dotInactive, { backgroundColor: fgMuted }] }, i)) }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: overlayActionStyles.actions, children: [
318
+ !isOnly && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SecondaryButton, { onPress: isFirst ? onSkip : () => goTo(index - 1), children: isFirst ? "Skip" : "Back" }),
319
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press2.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" })
312
320
  ] })
313
321
  ] }) }) });
314
322
  }
315
323
  function HowToPlayDialog({ visible, steps, ...rest }) {
316
324
  if (!visible || steps.length === 0) return null;
317
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(HowToPlayCard, { steps, ...rest });
325
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HowToPlayCard, { steps, ...rest });
318
326
  }
319
327
  var styles4 = import_react_native5.StyleSheet.create({
320
328
  art: {
@@ -365,7 +373,7 @@ var styles4 = import_react_native5.StyleSheet.create({
365
373
  });
366
374
 
367
375
  // src/guide/GuideProvider.tsx
368
- var import_jsx_runtime5 = require("react/jsx-runtime");
376
+ var import_jsx_runtime6 = require("react/jsx-runtime");
369
377
  var noop = () => {
370
378
  };
371
379
  var GuideContext = (0, import_react2.createContext)({ isOpen: false, open: noop, close: noop, requestAutoShow: noop });
@@ -384,9 +392,9 @@ function GuideProvider({ steps, currentVersion, seenVersion, onSeen, rotation, c
384
392
  setIsOpen(true);
385
393
  }, [unseen]);
386
394
  const value = (0, import_react2.useMemo)(() => ({ isOpen, open, close, requestAutoShow }), [isOpen, open, close, requestAutoShow]);
387
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(GuideContext.Provider, { value, children: [
395
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(GuideContext.Provider, { value, children: [
388
396
  children,
389
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(HowToPlayDialog, { visible: isOpen, steps, onFinish: close, onSkip: close, rotation })
397
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(HowToPlayDialog, { visible: isOpen, steps, onFinish: close, onSkip: close, rotation })
390
398
  ] });
391
399
  }
392
400
  function useGuide() {
@@ -442,7 +450,7 @@ function createReturningPlayerMigrate(storage, legacyKeys) {
442
450
  var import_auto_paper5 = require("@rific/auto-paper");
443
451
  var import_react_native6 = require("react-native");
444
452
  var import_react_native_paper4 = require("react-native-paper");
445
- var import_jsx_runtime6 = require("react/jsx-runtime");
453
+ var import_jsx_runtime7 = require("react/jsx-runtime");
446
454
  var ICON = {
447
455
  keyboard: { source: "keyboard-outline", size: 56 },
448
456
  mouse: { source: "mouse-outline", size: 44 }
@@ -452,11 +460,11 @@ function SeatDevicesHint({ devices, seatColors }) {
452
460
  const { colors } = (0, import_auto_paper5.useAutoPaperTheme)();
453
461
  const tints = seatColors ?? [colors.primary, colors.secondary];
454
462
  const accessibilityLabel = devices.map((device, i) => `Player ${i + 1} uses the ${device}`).join(", ");
455
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native6.View, { accessible: true, accessibilityLabel, style: styles5.row, children: ORDER.map((device) => {
463
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native6.View, { accessible: true, accessibilityLabel, style: styles5.row, children: ORDER.map((device) => {
456
464
  const seats = devices.flatMap((d, i) => d === device ? [i] : []);
457
465
  if (seats.length === 0) return null;
458
466
  const color = seats.length === 1 ? tints[seats[0]] ?? colors.onSurface : colors.onSurface;
459
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Icon, { source: ICON[device].source, size: ICON[device].size, color }, device);
467
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: ICON[device].source, size: ICON[device].size, color }, device);
460
468
  }) });
461
469
  }
462
470
  var styles5 = import_react_native6.StyleSheet.create({
@@ -471,21 +479,21 @@ var styles5 = import_react_native6.StyleSheet.create({
471
479
  var import_auto_paper6 = require("@rific/auto-paper");
472
480
  var import_react_native7 = require("react-native");
473
481
  var import_react_native_paper5 = require("react-native-paper");
474
- var import_jsx_runtime7 = require("react/jsx-runtime");
482
+ var import_jsx_runtime8 = require("react/jsx-runtime");
475
483
  var DEVICE_WIDTH = 88;
476
484
  var DEVICE_HEIGHT = 120;
477
485
  function SeatDiagram({ topColor, bottomColor, topLabel = "P2", bottomLabel = "P1" }) {
478
486
  const { colors } = (0, import_auto_paper6.useAutoPaperTheme)();
479
487
  const top = topColor ?? colors.secondary;
480
488
  const bottom = bottomColor ?? colors.primary;
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 })
489
+ return /* @__PURE__ */ (0, import_jsx_runtime8.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: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: [styles6.half, { borderColor: top }], children: [
491
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: [import_react_native7.StyleSheet.absoluteFill, styles6.tint, { backgroundColor: top }] }),
492
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper5.Text, { variant: "titleMedium", style: [styles6.label, styles6.flipped, { color: top }], children: topLabel })
485
493
  ] }),
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 })
494
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native7.View, { style: [styles6.half, styles6.bottomHalf, { borderColor: bottom }], children: [
495
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native7.View, { style: [import_react_native7.StyleSheet.absoluteFill, styles6.tint, { backgroundColor: bottom }] }),
496
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper5.Text, { variant: "titleMedium", style: [styles6.label, { color: bottom }], children: bottomLabel })
489
497
  ] })
490
498
  ] });
491
499
  }
@@ -525,7 +533,7 @@ var import_react3 = require("react");
525
533
  var import_react_native8 = require("react-native");
526
534
  var import_react_native_paper6 = require("react-native-paper");
527
535
  var import_react_native_reanimated2 = __toESM(require("react-native-reanimated"));
528
- var import_jsx_runtime8 = require("react/jsx-runtime");
536
+ var import_jsx_runtime9 = require("react/jsx-runtime");
529
537
  var DOT_COUNT = 7;
530
538
  var FINGER_SIZE = 28;
531
539
  var MOUSE_SIZE = 30;
@@ -555,10 +563,10 @@ function SwipeHint({ direction = "right", pointer = "finger", color, length = 96
555
563
  };
556
564
  });
557
565
  const axis = horizontal ? sign > 0 ? "row" : "row-reverse" : sign > 0 ? "column" : "column-reverse";
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] })
566
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native8.View, { accessibilityLabel: `${pointer === "mouse" ? "Drag" : "Swipe"} ${direction}`, accessible: true, style: [styles7.path, { flexDirection: axis }], children: [
567
+ /* @__PURE__ */ (0, import_jsx_runtime9.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_runtime9.jsx)(import_react_native8.View, { style: [styles7.dot, { backgroundColor: tint, opacity: 0.35 + 0.65 * i / (DOT_COUNT - 1) }] }, i)) }),
568
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper6.Icon, { source: ARROW_ICON[direction], size: 28, color: tint }),
569
+ pointer === "mouse" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated2.default.View, { style: [styles7.mouse, fingerStyle], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper6.Icon, { source: "mouse", size: MOUSE_SIZE, color: tint }) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_reanimated2.default.View, { style: [styles7.finger, { borderColor: tint }, fingerStyle] })
562
570
  ] });
563
571
  }
564
572
  var styles7 = import_react_native8.StyleSheet.create({
@@ -2,10 +2,11 @@ import {
2
2
  DialogHeader,
3
3
  OverlayBackdrop,
4
4
  OverlayCard,
5
+ SecondaryButton,
5
6
  isCompactDialogHeight,
6
7
  overlayActionStyles,
7
8
  useOverlayCardColors
8
- } from "../chunk-PUF6TABL.mjs";
9
+ } from "../chunk-CBH7GQKI.mjs";
9
10
 
10
11
  // src/guide/DirectionKeysHint.tsx
11
12
  import { useAutoPaperTheme } from "@rific/auto-paper";
@@ -141,7 +142,7 @@ function HowToPlayCard({ steps, onFinish, onSkip, rotation = 0, title = "How to
141
142
  ] }, i)) }),
142
143
  steps.length > 1 && /* @__PURE__ */ jsx2(View2, { accessible: true, accessibilityLabel: `Step ${index + 1} of ${steps.length}`, style: styles2.dots, children: steps.map((_, i) => /* @__PURE__ */ jsx2(View2, { style: i === index ? [styles2.dot, { backgroundColor: colors.primary }] : [styles2.dot, styles2.dotInactive, { backgroundColor: fgMuted }] }, i)) }),
143
144
  /* @__PURE__ */ jsxs2(View2, { style: overlayActionStyles.actions, children: [
144
- !isOnly && /* @__PURE__ */ jsx2(Button, { mode: "outlined", onPress: isFirst ? onSkip : () => goTo(index - 1), style: overlayActionStyles.actionButton, children: isFirst ? "Skip" : "Back" }),
145
+ !isOnly && /* @__PURE__ */ jsx2(SecondaryButton, { onPress: isFirst ? onSkip : () => goTo(index - 1), children: isFirst ? "Skip" : "Back" }),
145
146
  /* @__PURE__ */ jsx2(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" })
146
147
  ] })
147
148
  ] }) }) });
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PopoverHost, AlignResult, PopoverRotation, useAutoAlign } from './chrome/index.mjs';
2
- export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, InlineColorPicker, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, PopoverAlign, PopoverBody, PopoverVerticalAlign, PressAwayOverlay, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, WELL_SHADOW, WellColors, getInlineColorPickerContentSize, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors, usePopoverHost, useWellColors } from './chrome/index.mjs';
2
+ export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, InlineColorPicker, InlineColorPickerSwatchPlace, InlineColorPickerSwatchRenderer, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, PopoverAlign, PopoverBody, PopoverVerticalAlign, PressAwayOverlay, RotatedFrame, RotatedFrameProps, SecondaryButton, SecondaryButtonProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, ViewInstance, WELL_SHADOW, WellColors, getInlineColorPickerContentSize, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors, usePopoverHost, useWellColors } from './chrome/index.mjs';
3
3
  import * as react from 'react';
4
4
  import { ReactNode } from 'react';
5
5
  import { AchievementTier } from '@tastic/achievements';
@@ -8,6 +8,7 @@ import { ViewStyle, StyleProp } from 'react-native';
8
8
  export { loadSkiaWeb, locateSkiaWebFile } from './skia/index.mjs';
9
9
  import { SeedColor } from '@rific/auto-paper';
10
10
  import '@tastic/core';
11
+ import '@rific/feedback-press';
11
12
 
12
13
  interface UnlockedAchievement {
13
14
  id: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PopoverHost, AlignResult, PopoverRotation, useAutoAlign } from './chrome/index.js';
2
- export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, InlineColorPicker, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, PopoverAlign, PopoverBody, PopoverVerticalAlign, PressAwayOverlay, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, WELL_SHADOW, WellColors, getInlineColorPickerContentSize, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors, usePopoverHost, useWellColors } from './chrome/index.js';
2
+ export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, InlineColorPicker, InlineColorPickerSwatchPlace, InlineColorPickerSwatchRenderer, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, PopoverAlign, PopoverBody, PopoverVerticalAlign, PressAwayOverlay, RotatedFrame, RotatedFrameProps, SecondaryButton, SecondaryButtonProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, ViewInstance, WELL_SHADOW, WellColors, getInlineColorPickerContentSize, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors, usePopoverHost, useWellColors } from './chrome/index.js';
3
3
  import * as react from 'react';
4
4
  import { ReactNode } from 'react';
5
5
  import { AchievementTier } from '@tastic/achievements';
@@ -8,6 +8,7 @@ import { ViewStyle, StyleProp } from 'react-native';
8
8
  export { loadSkiaWeb, locateSkiaWebFile } from './skia/index.js';
9
9
  import { SeedColor } from '@rific/auto-paper';
10
10
  import '@tastic/core';
11
+ import '@rific/feedback-press';
11
12
 
12
13
  interface UnlockedAchievement {
13
14
  id: string;