@tastic/hud 0.6.0 → 0.7.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/dist/index.js CHANGED
@@ -28,22 +28,22 @@ __export(TriggerGauge_exports, {
28
28
  function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, dashWidth, startDeg = DEFAULT_START_DEG, endDeg = startDeg }) {
29
29
  const totalDurationMs = MOUNT_DURATION_MS + Math.max(0, segments - 1) * MOUNT_STAGGER_MS;
30
30
  const mountProgress = (0, import_react_native_reanimated.useSharedValue)(0);
31
- (0, import_react4.useLayoutEffect)(() => {
31
+ (0, import_react3.useLayoutEffect)(() => {
32
32
  mountProgress.value = (0, import_react_native_reanimated.withTiming)(1, { duration: totalDurationMs, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
33
33
  }, []);
34
34
  const rawSweepDeg = ((endDeg - startDeg) % 360 + 360) % 360;
35
35
  const totalSweepDeg = rawSweepDeg === 0 ? 360 : rawSweepDeg;
36
36
  const step = segments > 0 ? totalSweepDeg / segments : 0;
37
- const centerDeg = (0, import_react4.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
37
+ const centerDeg = (0, import_react3.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
38
38
  const singleSelect = litIndices.length === 1;
39
39
  const angleDeg = (0, import_react_native_reanimated.useSharedValue)(centerDeg(litIndices[0] ?? 0));
40
40
  const litIndicesKey = [...litIndices].sort((a, b) => a - b).join(",");
41
- const [transitionFrom, setTransitionFrom] = (0, import_react4.useState)(litIndices);
41
+ const [transitionFrom, setTransitionFrom] = (0, import_react3.useState)(litIndices);
42
42
  const transitionFromKey = [...transitionFrom].sort((a, b) => a - b).join(",");
43
- const lastKeyRef = (0, import_react4.useRef)(litIndicesKey);
44
- const lastIndicesRef = (0, import_react4.useRef)(litIndices);
43
+ const lastKeyRef = (0, import_react3.useRef)(litIndicesKey);
44
+ const lastIndicesRef = (0, import_react3.useRef)(litIndices);
45
45
  const selectionProgress = (0, import_react_native_reanimated.useSharedValue)(1);
46
- (0, import_react4.useLayoutEffect)(() => {
46
+ (0, import_react3.useLayoutEffect)(() => {
47
47
  if (litIndicesKey !== lastKeyRef.current) {
48
48
  if (singleSelect && lastIndicesRef.current.length === 1) {
49
49
  angleDeg.value = (0, import_react_native_reanimated.withTiming)(centerDeg(litIndices[0]), { duration: SELECTION_TRANSITION_DURATION_MS, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
@@ -72,7 +72,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
72
72
  if (mountProgress.value < 1) {
73
73
  const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
74
74
  const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
75
- local = (0, import_core4.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
75
+ local = (0, import_core3.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
76
76
  }
77
77
  const sweep = dashAngleDeg * local;
78
78
  if (sweep <= 0) continue;
@@ -96,7 +96,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
96
96
  if (!isLitNow) continue;
97
97
  const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
98
98
  const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
99
- local = (0, import_core4.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
99
+ local = (0, import_core3.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
100
100
  } else if (isLitNow === wasLit) {
101
101
  local = 1;
102
102
  } else if (isLitNow) {
@@ -120,21 +120,21 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
120
120
  height: canvasSize,
121
121
  width: canvasSize
122
122
  };
123
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native13.View, { style: [styles10.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
124
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
125
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
123
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [styles7.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
124
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
125
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
126
126
  ] }) });
127
127
  }
128
- var import_react_native_skia, import_core4, import_react4, import_react_native13, import_react_native_reanimated, import_jsx_runtime11, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles10;
128
+ var import_react_native_skia, import_core3, import_react3, import_react_native8, import_react_native_reanimated, import_jsx_runtime7, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles7;
129
129
  var init_TriggerGauge = __esm({
130
130
  "src/TriggerGauge.tsx"() {
131
131
  "use strict";
132
132
  import_react_native_skia = require("@shopify/react-native-skia");
133
- import_core4 = require("@tastic/core");
134
- import_react4 = require("react");
135
- import_react_native13 = require("react-native");
133
+ import_core3 = require("@tastic/core");
134
+ import_react3 = require("react");
135
+ import_react_native8 = require("react-native");
136
136
  import_react_native_reanimated = require("react-native-reanimated");
137
- import_jsx_runtime11 = require("react/jsx-runtime");
137
+ import_jsx_runtime7 = require("react/jsx-runtime");
138
138
  UNLIT_THICKNESS = 3;
139
139
  LIT_THICKNESS = 7;
140
140
  DASH_GAP_PX = 9;
@@ -144,7 +144,7 @@ var init_TriggerGauge = __esm({
144
144
  MOUNT_DURATION_MS = 450;
145
145
  MOUNT_STAGGER_MS = 40;
146
146
  SELECTION_TRANSITION_DURATION_MS = 260;
147
- styles10 = import_react_native13.StyleSheet.create({
147
+ styles7 = import_react_native8.StyleSheet.create({
148
148
  container: {
149
149
  alignItems: "center",
150
150
  justifyContent: "center",
@@ -160,8 +160,11 @@ __export(index_exports, {
160
160
  AchievementRow: () => AchievementRow,
161
161
  BaseSettingsDialog: () => BaseSettingsDialog,
162
162
  BaseStatsScreen: () => BaseStatsScreen,
163
+ ConfirmDialog: () => ConfirmDialog,
163
164
  ContentGutter: () => ContentGutter,
165
+ ControlSchemePicker: () => ControlSchemePicker,
164
166
  CornerActionButtons: () => CornerActionButtons,
167
+ CornerStatusBadges: () => CornerStatusBadges,
165
168
  InlineColorPicker: () => InlineColorPicker,
166
169
  LABELED_DROPDOWN_POPOVER_WIDTH: () => LABELED_DROPDOWN_POPOVER_WIDTH,
167
170
  LOCKED_BADGE_COLOR: () => LOCKED_BADGE_COLOR,
@@ -553,60 +556,103 @@ var styles3 = import_react_native3.StyleSheet.create({
553
556
  }
554
557
  });
555
558
 
556
- // src/ContentGutter.tsx
557
- var import_core2 = require("@tastic/core");
559
+ // src/ConfirmDialog.tsx
560
+ var import_auto_paper4 = require("@rific/auto-paper");
561
+ var import_feedback_press3 = require("@rific/feedback-press");
558
562
  var import_react_native4 = require("react-native");
563
+ var import_react_native_paper4 = require("react-native-paper");
559
564
  var import_jsx_runtime4 = require("react/jsx-runtime");
560
- function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
561
- const { width: windowWidth } = (0, import_react_native4.useWindowDimensions)();
562
- const { contentWidth, gutterWidth } = (0, import_core2.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
563
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: [styles4.row, style], children: [
564
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [styles4.gutter, { width: gutterWidth }], children: leftGutter }),
565
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: { width: contentWidth }, children }),
566
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: [styles4.gutter, { width: gutterWidth }], children: rightGutter })
567
- ] });
565
+ function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
566
+ const { dark, colors } = (0, import_auto_paper4.useAutoPaperTheme)();
567
+ if (!visible) return null;
568
+ const fg = dark ? "#FFFFFF" : "#000000";
569
+ const cardBg = dark ? "#111111" : "#F2F2F2";
570
+ const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
571
+ const accent = destructive ? colors.danger : colors.primary;
572
+ const onAccent = destructive ? colors.onDanger : colors.onPrimary;
573
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style: styles4.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: [styles4.card, { backgroundColor: cardBg, borderColor: cardBorder }, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
574
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Icon, { source: icon, size: 64, color: accent }),
575
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Text, { variant: "headlineLarge", style: [styles4.title, { color: accent }], children: title }),
576
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Text, { variant: "bodyLarge", style: [styles4.body, { color: fg }], children: message }),
577
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native4.View, { style: styles4.actions, children: [
578
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press3.Button, { mode: "outlined", onPress: onCancel, style: styles4.actionButton, children: cancelLabel }),
579
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press3.Button, { mode: "contained", onPress: onConfirm, style: styles4.actionButton, buttonColor: accent, textColor: onAccent, children: confirmLabel })
580
+ ] })
581
+ ] }) }) });
568
582
  }
569
583
  var styles4 = import_react_native4.StyleSheet.create({
570
- // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
571
- // column instead of clipping cleanly at its own real width.
572
- gutter: {
573
- overflow: "hidden"
584
+ actionButton: {
585
+ flex: 1
574
586
  },
575
- row: {
576
- flexDirection: "row"
587
+ actions: {
588
+ flexDirection: "row",
589
+ gap: 12,
590
+ width: "100%"
591
+ },
592
+ body: {
593
+ textAlign: "center"
594
+ },
595
+ card: {
596
+ alignItems: "center",
597
+ borderRadius: 20,
598
+ borderWidth: 1,
599
+ gap: 16,
600
+ maxWidth: 360,
601
+ padding: 32
602
+ },
603
+ overlay: {
604
+ alignItems: "center",
605
+ backgroundColor: "rgba(0,0,0,0.72)",
606
+ bottom: 0,
607
+ justifyContent: "center",
608
+ left: 0,
609
+ position: "absolute",
610
+ right: 0,
611
+ top: 0
612
+ },
613
+ title: {
614
+ fontWeight: "bold"
577
615
  }
578
616
  });
579
617
 
580
- // src/CornerActionButtons.tsx
581
- var import_feedback_press3 = require("@rific/feedback-press");
618
+ // src/ContentGutter.tsx
619
+ var import_core2 = require("@tastic/core");
582
620
  var import_react_native5 = require("react-native");
583
621
  var import_jsx_runtime5 = require("react/jsx-runtime");
584
- function CornerActionButtons({ onBack, onSettings, fg, insets }) {
585
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
586
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, style: [styles5.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: "Back" }),
587
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press3.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles5.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
622
+ function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
623
+ const { width: windowWidth } = (0, import_react_native5.useWindowDimensions)();
624
+ const { contentWidth, gutterWidth } = (0, import_core2.computeContentBounds)(windowWidth, maxContentWidth ?? Infinity);
625
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native5.View, { style: [styles5.row, style], children: [
626
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [styles5.gutter, { width: gutterWidth }], children: leftGutter }),
627
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: { width: contentWidth }, children }),
628
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native5.View, { style: [styles5.gutter, { width: gutterWidth }], children: rightGutter })
588
629
  ] });
589
630
  }
590
631
  var styles5 = import_react_native5.StyleSheet.create({
591
- back: {
592
- position: "absolute"
632
+ // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
633
+ // column instead of clipping cleanly at its own real width.
634
+ gutter: {
635
+ overflow: "hidden"
593
636
  },
594
- topRight: {
595
- position: "absolute"
637
+ row: {
638
+ flexDirection: "row"
596
639
  }
597
640
  });
598
641
 
642
+ // src/ControlSchemePicker.tsx
643
+ var import_core4 = require("@tastic/core");
644
+ var import_react_native11 = require("react-native");
645
+
646
+ // src/SectionedDropdown.tsx
647
+ var import_auto_paper5 = require("@rific/auto-paper");
648
+ var import_feedback_press4 = require("@rific/feedback-press");
649
+ var import_react_native10 = require("react-native");
650
+ var import_react_native_paper5 = require("react-native-paper");
651
+
599
652
  // src/fonts.ts
600
653
  var import_react_native6 = require("react-native");
601
654
  var MONO_FONT = import_react_native6.Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
602
655
 
603
- // src/InlineColorPicker.tsx
604
- var import_auto_paper4 = require("@rific/auto-paper");
605
- var import_feedback_press4 = require("@rific/feedback-press");
606
- var import_core3 = require("@tastic/core");
607
- var import_react_native9 = require("react-native");
608
- var import_react_native_paper4 = require("react-native-paper");
609
-
610
656
  // src/PopoverBody.tsx
611
657
  var import_react_native7 = require("react-native");
612
658
  var import_jsx_runtime6 = require("react/jsx-runtime");
@@ -673,23 +719,38 @@ var styles6 = import_react_native7.StyleSheet.create({
673
719
  }
674
720
  });
675
721
 
722
+ // src/TriggerGaugeHost.tsx
723
+ var import_react4 = require("react");
724
+
725
+ // src/loadSkiaWeb.ts
726
+ function loadSkiaWeb() {
727
+ return Promise.resolve();
728
+ }
729
+
730
+ // src/TriggerGaugeHost.tsx
731
+ var import_jsx_runtime8 = require("react/jsx-runtime");
732
+ var LazyTriggerGauge = (0, import_react4.lazy)(() => loadSkiaWeb().then(() => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((m) => ({ default: m.TriggerGauge }))));
733
+ function TriggerGaugeHost(props) {
734
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react4.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(LazyTriggerGauge, { ...props }) });
735
+ }
736
+
676
737
  // src/useAutoAlign.ts
677
- var import_react3 = require("react");
678
- var import_react_native8 = require("react-native");
738
+ var import_react5 = require("react");
739
+ var import_react_native9 = require("react-native");
679
740
  var EDGE_MARGIN = 12;
680
741
  function useAutoAlign(open, contentWidth, contentHeight) {
681
- const triggerRef = (0, import_react3.useRef)(null);
682
- const { width: windowWidth, height: windowHeight } = (0, import_react_native8.useWindowDimensions)();
683
- const [align, setAlign] = (0, import_react3.useState)("center");
684
- const [verticalAlign, setVerticalAlign] = (0, import_react3.useState)("below");
685
- const [maxHeight, setMaxHeight] = (0, import_react3.useState)(contentHeight);
686
- const [measured, setMeasured] = (0, import_react3.useState)(false);
687
- const [prevOpen, setPrevOpen] = (0, import_react3.useState)(open);
742
+ const triggerRef = (0, import_react5.useRef)(null);
743
+ const { width: windowWidth, height: windowHeight } = (0, import_react_native9.useWindowDimensions)();
744
+ const [align, setAlign] = (0, import_react5.useState)("center");
745
+ const [verticalAlign, setVerticalAlign] = (0, import_react5.useState)("below");
746
+ const [maxHeight, setMaxHeight] = (0, import_react5.useState)(contentHeight);
747
+ const [measured, setMeasured] = (0, import_react5.useState)(false);
748
+ const [prevOpen, setPrevOpen] = (0, import_react5.useState)(open);
688
749
  if (open !== prevOpen) {
689
750
  setPrevOpen(open);
690
751
  if (open) setMeasured(false);
691
752
  }
692
- const measure = (0, import_react3.useCallback)(() => {
753
+ const measure = (0, import_react5.useCallback)(() => {
693
754
  triggerRef.current?.measureInWindow((x, y, triggerWidth, triggerHeight) => {
694
755
  const centerX = x + triggerWidth / 2;
695
756
  const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
@@ -705,14 +766,272 @@ function useAutoAlign(open, contentWidth, contentHeight) {
705
766
  setMeasured(true);
706
767
  });
707
768
  }, [contentWidth, contentHeight, windowWidth, windowHeight]);
708
- (0, import_react3.useEffect)(() => {
769
+ (0, import_react5.useEffect)(() => {
709
770
  if (open) measure();
710
771
  }, [open, measure]);
711
772
  return { align, maxHeight, measured, triggerRef, verticalAlign };
712
773
  }
713
774
 
775
+ // src/SectionedDropdown.tsx
776
+ var import_jsx_runtime9 = require("react/jsx-runtime");
777
+ var MENU_BORDER_WIDTH = 1;
778
+ var TRIGGER_SIZE = 44;
779
+ var MENU_MIN_WIDTH = 200;
780
+ var MENU_MAX_WIDTH = 220;
781
+ var MENU_ITEM_ICON_SIZE = 18;
782
+ var MENU_ITEM_LABEL_MAX_WIDTH = 150;
783
+ var MENU_ITEM_HEIGHT = 40;
784
+ var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
785
+ var MENU_DIVIDER_HEIGHT = 9;
786
+ var MENU_VERTICAL_PADDING = 12;
787
+ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
788
+ const menuBg = dark ? "#000000" : "#FFFFFF";
789
+ const menuBorderColor = (0, import_auto_paper5.getBlendedColor)(mutedColor, menuBg, 0.5);
790
+ const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper5.getColorRoles)(accentColor, menuBg).onColor;
791
+ const fg = dark ? "#FFFFFF" : "#000000";
792
+ const open = host.openId === id;
793
+ const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
794
+ const rows = section.options.reduce((rowSum, option) => rowSum + (option.description ? MENU_ITEM_HEIGHT_WITH_DESCRIPTION : MENU_ITEM_HEIGHT), 0);
795
+ const footer = section.kind === "multi" && section.allClear ? MENU_ITEM_HEIGHT : 0;
796
+ const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
797
+ return sum + rows + footer + divider;
798
+ }, 0);
799
+ const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight);
800
+ const align = alignOverride ?? autoAlign;
801
+ const onlySection = sections.length === 1 ? sections[0] : null;
802
+ const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
803
+ const triggerIcon = selectedOption?.icon ?? icon;
804
+ const triggerIconSize = selectedOption?.iconSize ?? 22;
805
+ const hasMultiSection = sections.some((s) => s.kind === "multi");
806
+ const anyMultiSelected = sections.some((s) => s.kind === "multi" && s.value.length > 0);
807
+ const triggerIconColor = hasMultiSection ? anyMultiSelected ? accentColor : fg : fg;
808
+ const gaugeSegments = sections.reduce((sum, section) => sum + section.options.length, 0);
809
+ const gaugeLitIndices = [];
810
+ let gaugeOffset = 0;
811
+ for (const section of sections) {
812
+ if (section.kind === "single") {
813
+ const index = section.options.findIndex((o) => o.value === section.value);
814
+ if (index >= 0) gaugeLitIndices.push(gaugeOffset + index);
815
+ } else {
816
+ section.options.forEach((o, i) => {
817
+ if (section.value.includes(o.value)) gaugeLitIndices.push(gaugeOffset + i);
818
+ });
819
+ }
820
+ gaugeOffset += section.options.length;
821
+ }
822
+ const anchorStyle = [styles8.anchor, open && styles8.anchorOpen];
823
+ const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
824
+ const dividerStyle = { backgroundColor: menuBorderColor };
825
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: anchorStyle, children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { ref: triggerRef, collapsable: false, style: styles8.triggerBox, children: [
827
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
828
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press4.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
829
+ ] }),
830
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.ScrollView, { style: [styles8.menu, menuStyle], contentContainerStyle: styles8.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { children: [
831
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native10.View, { style: [styles8.divider, dividerStyle] }),
832
+ section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
833
+ SingleSection,
834
+ {
835
+ section,
836
+ accentColor,
837
+ onAccentColor: resolvedOnAccentColor,
838
+ mutedColor,
839
+ labelFontFamily,
840
+ onSelect: (value) => {
841
+ section.onChange(value);
842
+ if (autoDismiss) host.close();
843
+ }
844
+ }
845
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
846
+ ] }, section.id)) }) })
847
+ ] });
848
+ }
849
+ function SingleSection({
850
+ section,
851
+ accentColor,
852
+ onAccentColor,
853
+ mutedColor,
854
+ labelFontFamily,
855
+ onSelect
856
+ }) {
857
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: section.options.map((option) => {
858
+ const selected = option.value === section.value;
859
+ const taken = !selected && option.value === section.takenValue;
860
+ const rowColor = selected ? onAccentColor : mutedColor;
861
+ const itemStyle = [styles8.item, selected && { backgroundColor: accentColor }, taken && styles8.itemTaken];
862
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
863
+ const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
864
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press4.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.itemRow, children: [
865
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper5.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
866
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.itemLabelColumn, children: [
867
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper5.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
868
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper5.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
869
+ ] })
870
+ ] }) }, option.value);
871
+ }) });
872
+ }
873
+ function MultiSection({
874
+ section,
875
+ accentColor,
876
+ onAccentColor,
877
+ mutedColor,
878
+ labelFontFamily,
879
+ allClearLabels
880
+ }) {
881
+ const allSelected = section.value.length === section.options.length;
882
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
883
+ section.options.map((option, i) => {
884
+ const selected = section.value.includes(option.value);
885
+ const rowColor = selected ? onAccentColor : mutedColor;
886
+ const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
887
+ const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
888
+ const itemStyle = [styles8.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
889
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
890
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native10.View, { style: styles8.itemRow, children: [
891
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper5.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
892
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper5.Text, { variant: "labelLarge", style: [styles8.itemLabelFlex, labelStyle], children: option.label })
893
+ ] }) }, option.value);
894
+ }),
895
+ section.allClear && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles8.item, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper5.Text, { variant: "labelLarge", style: [styles8.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
896
+ ] });
897
+ }
898
+ var styles8 = import_react_native10.StyleSheet.create({
899
+ allClearLabel: {
900
+ fontWeight: "bold",
901
+ textAlign: "center"
902
+ },
903
+ anchor: {
904
+ position: "relative"
905
+ },
906
+ // React Native Web gives every position:'relative' view an explicit zIndex (0, not 'auto'),
907
+ // which makes each one its own stacking context — so a zIndex set only on the popover content
908
+ // below only wins comparisons within this anchor's own box, not against this anchor's own later
909
+ // siblings (e.g. a Ready button), which are otherwise painted on top by DOM-order tiebreak.
910
+ // Elevating the anchor itself, only while its popover is open, fixes that at the right level.
911
+ anchorOpen: {
912
+ zIndex: 100
913
+ },
914
+ divider: {
915
+ height: import_react_native10.StyleSheet.hairlineWidth,
916
+ marginVertical: 4
917
+ },
918
+ item: {
919
+ borderRadius: 8,
920
+ paddingHorizontal: 12,
921
+ paddingVertical: 8
922
+ },
923
+ itemLabelColumn: {
924
+ maxWidth: MENU_ITEM_LABEL_MAX_WIDTH
925
+ },
926
+ itemLabelFlex: {
927
+ flex: 1
928
+ },
929
+ itemRow: {
930
+ alignItems: "center",
931
+ flexDirection: "row",
932
+ gap: 8
933
+ },
934
+ // Same opacity as ProfilePicker's rowDisabled / InlineColorPicker's swatchTaken — the fleet's
935
+ // established "shown, not removed" treatment for another seat's own current pick.
936
+ itemTaken: {
937
+ opacity: 0.35
938
+ },
939
+ menu: {
940
+ borderRadius: 12,
941
+ borderWidth: MENU_BORDER_WIDTH,
942
+ elevation: 8,
943
+ maxWidth: MENU_MAX_WIDTH,
944
+ minWidth: MENU_MIN_WIDTH,
945
+ shadowColor: "#000000",
946
+ shadowOffset: { height: 2, width: 0 },
947
+ shadowOpacity: 0.3,
948
+ shadowRadius: 8
949
+ },
950
+ // Separate from `menu` itself — a ScrollView's own style sets the scrolling frame's bounds
951
+ // (including the maxHeight that actually caps it), while padding/gap belong to its
952
+ // contentContainerStyle, which sizes to the *unclamped* content instead of the frame.
953
+ menuContent: {
954
+ gap: 4,
955
+ padding: 6
956
+ },
957
+ // Fixed hit-area regardless of the current option's iconSize, so a small-vs-large trigger icon
958
+ // doesn't shift this picker's position within its row.
959
+ triggerBox: {
960
+ alignItems: "center",
961
+ height: TRIGGER_SIZE,
962
+ justifyContent: "center",
963
+ width: TRIGGER_SIZE
964
+ }
965
+ });
966
+
967
+ // src/ControlSchemePicker.tsx
968
+ var import_jsx_runtime10 = require("react/jsx-runtime");
969
+ function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, labelFontFamily }) {
970
+ const isTouchPrimary = (0, import_core4.useIsTouchPrimaryDevice)();
971
+ if (import_react_native11.Platform.OS !== "web" || isTouchPrimary) return null;
972
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, labelFontFamily });
973
+ }
974
+
975
+ // src/CornerActionButtons.tsx
976
+ var import_feedback_press5 = require("@rific/feedback-press");
977
+ var import_react_native12 = require("react-native");
978
+ var import_jsx_runtime11 = require("react/jsx-runtime");
979
+ function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
980
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
981
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press5.IconButton, { icon: backIcon, iconColor: fg, size: 24, style: [styles9.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
982
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press5.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles9.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
983
+ ] });
984
+ }
985
+ var styles9 = import_react_native12.StyleSheet.create({
986
+ back: {
987
+ position: "absolute"
988
+ },
989
+ topRight: {
990
+ position: "absolute"
991
+ }
992
+ });
993
+
994
+ // src/CornerStatusBadges.tsx
995
+ var import_react_native13 = require("react-native");
996
+ var import_react_native_paper6 = require("react-native-paper");
997
+ var import_jsx_runtime12 = require("react/jsx-runtime");
998
+ var BADGE_SIZE = 30;
999
+ function StatusBadge({ icon }) {
1000
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: styles10.badge, children: icon && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper6.Icon, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
1001
+ }
1002
+ function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
1003
+ const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
1004
+ const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
1005
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1006
+ p1 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { pointerEvents: "none", style: p1OnRightSide ? styles10.bottomRight : styles10.bottomLeft, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(StatusBadge, { icon: p1.icon }) }),
1007
+ p2 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { pointerEvents: "none", style: p2OnLeftSide ? styles10.topLeft : styles10.topRight, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(StatusBadge, { icon: p2.icon }) })
1008
+ ] });
1009
+ }
1010
+ var styles10 = import_react_native13.StyleSheet.create({
1011
+ badge: {
1012
+ alignItems: "center",
1013
+ backgroundColor: "rgba(0,0,0,0.28)",
1014
+ borderColor: "rgba(255,255,255,0.18)",
1015
+ borderRadius: BADGE_SIZE / 2,
1016
+ borderWidth: 1,
1017
+ height: BADGE_SIZE,
1018
+ justifyContent: "center",
1019
+ opacity: 0.7,
1020
+ width: BADGE_SIZE
1021
+ },
1022
+ bottomLeft: { bottom: 12, left: 12, position: "absolute" },
1023
+ bottomRight: { bottom: 12, position: "absolute", right: 12 },
1024
+ topLeft: { left: 12, position: "absolute", top: 12 },
1025
+ topRight: { position: "absolute", right: 12, top: 12 }
1026
+ });
1027
+
714
1028
  // src/InlineColorPicker.tsx
715
- var import_jsx_runtime7 = require("react/jsx-runtime");
1029
+ var import_auto_paper6 = require("@rific/auto-paper");
1030
+ var import_feedback_press6 = require("@rific/feedback-press");
1031
+ var import_core5 = require("@tastic/core");
1032
+ var import_react_native14 = require("react-native");
1033
+ var import_react_native_paper7 = require("react-native-paper");
1034
+ var import_jsx_runtime13 = require("react/jsx-runtime");
716
1035
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
717
1036
  var DEFAULT_SIZE = 48;
718
1037
  var SWATCH_SIZE = 28;
@@ -725,10 +1044,10 @@ var SCREEN_MARGIN = 40;
725
1044
  function widthForColumns(columns) {
726
1045
  return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
727
1046
  }
728
- function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper4.defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
1047
+ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = import_auto_paper6.defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
729
1048
  const menuBg = dark ? "#000000" : "#FFFFFF";
730
- const { width: windowWidth } = (0, import_react_native9.useWindowDimensions)();
731
- const autoColumns = (0, import_core3.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
1049
+ const { width: windowWidth } = (0, import_react_native14.useWindowDimensions)();
1050
+ const autoColumns = (0, import_core5.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
732
1051
  const resolvedColumns = columns ?? autoColumns;
733
1052
  const swatchesWidth = widthForColumns(resolvedColumns);
734
1053
  const swatchRows = Math.ceil(swatches.length / resolvedColumns);
@@ -738,17 +1057,17 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
738
1057
  const align = alignOverride ?? autoAlign;
739
1058
  const displayFor = previewValue ?? ((hex) => hex);
740
1059
  const displayValue = displayFor(value);
741
- const contrastColor = (0, import_auto_paper4.getContrastColor)(displayValue);
1060
+ const contrastColor = (0, import_auto_paper6.getContrastColor)(displayValue);
742
1061
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
743
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: [styles7.anchor, open && styles7.anchorOpen], children: [
744
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles7.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.View, { ref: triggerRef, collapsable: false, style: styles7.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Text, { style: [styles7.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
745
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.ScrollView, { style: [styles7.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles7.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
1062
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: [styles11.anchor, open && styles11.anchorOpen], children: [
1063
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles11.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, { ref: triggerRef, collapsable: false, style: styles11.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Text, { style: [styles11.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
1064
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.ScrollView, { style: [styles11.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles11.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
746
1065
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
747
1066
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
748
1067
  const swappable = taken && allowSwapTaken;
749
1068
  const swatchDisplay = displayFor(swatch.value);
750
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
751
- import_feedback_press4.TouchableRipple,
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1070
+ import_feedback_press6.TouchableRipple,
752
1071
  {
753
1072
  disabled: taken && !swappable,
754
1073
  onPress: () => {
@@ -756,15 +1075,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
756
1075
  if (autoDismiss) host.close();
757
1076
  },
758
1077
  borderless: true,
759
- style: [styles7.swatch, { backgroundColor: swatchDisplay }, selected && styles7.swatchSelected, taken && !swappable && styles7.swatchTaken],
760
- children: selected ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: "check", size: 16, color: (0, import_auto_paper4.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper4.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Icon, { source: "close", size: 16, color: (0, import_auto_paper4.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.View, {})
1078
+ style: [styles11.swatch, { backgroundColor: swatchDisplay }, selected && styles11.swatchSelected, taken && !swappable && styles11.swatchTaken],
1079
+ children: selected ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Icon, { source: "check", size: 16, color: (0, import_auto_paper6.getContrastColor)(swatchDisplay) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper6.getContrastColor)(swatchDisplay) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Icon, { source: "close", size: 16, color: (0, import_auto_paper6.getContrastColor)(swatchDisplay) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, {})
761
1080
  },
762
1081
  swatch.value
763
1082
  );
764
1083
  }) }) })
765
1084
  ] });
766
1085
  }
767
- var styles7 = import_react_native9.StyleSheet.create({
1086
+ var styles11 = import_react_native14.StyleSheet.create({
768
1087
  anchor: {
769
1088
  position: "relative"
770
1089
  },
@@ -836,11 +1155,11 @@ var styles7 = import_react_native9.StyleSheet.create({
836
1155
  });
837
1156
 
838
1157
  // src/LabeledDropdown.tsx
839
- var import_auto_paper5 = require("@rific/auto-paper");
840
- var import_feedback_press5 = require("@rific/feedback-press");
841
- var import_react_native10 = require("react-native");
842
- var import_react_native_paper5 = require("react-native-paper");
843
- var import_jsx_runtime8 = require("react/jsx-runtime");
1158
+ var import_auto_paper7 = require("@rific/auto-paper");
1159
+ var import_feedback_press7 = require("@rific/feedback-press");
1160
+ var import_react_native15 = require("react-native");
1161
+ var import_react_native_paper8 = require("react-native-paper");
1162
+ var import_jsx_runtime14 = require("react/jsx-runtime");
844
1163
  var TRIGGER_HEIGHT = 28;
845
1164
  var POPOVER_WIDTH = 180;
846
1165
  var ROW_HEIGHT = 36;
@@ -863,22 +1182,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
863
1182
  onChange(option.value);
864
1183
  host.close();
865
1184
  };
866
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native10.View, { style: [styles8.anchor, open && styles8.anchorOpen], children: [
867
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press5.TouchableRipple, { onPress: () => host.toggle(id), style: styles8.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native10.View, { ref: triggerRef, collapsable: false, style: styles8.triggerInner, children: [
868
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper5.Text, { style: [styles8.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
869
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper5.Icon, { source: "menu-down", size: 16, color })
1185
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native15.View, { style: [styles12.anchor, open && styles12.anchorOpen], children: [
1186
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => host.toggle(id), style: styles12.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native15.View, { ref: triggerRef, collapsable: false, style: styles12.triggerInner, children: [
1187
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { style: [styles12.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1188
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Icon, { source: "menu-down", size: 16, color })
870
1189
  ] }) }),
871
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.ScrollView, { style: [styles8.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles8.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1190
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native15.ScrollView, { style: [styles12.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles12.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
872
1191
  const isSelected = option.value === value;
873
- const onColor = (0, import_auto_paper5.getContrastColor)(color);
874
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_feedback_press5.TouchableRipple, { onPress: () => handleSelect(option), style: [styles8.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native10.View, { style: styles8.rowInner, children: [
875
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper5.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
876
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper5.Text, { style: [styles8.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1192
+ const onColor = (0, import_auto_paper7.getContrastColor)(color);
1193
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => handleSelect(option), style: [styles12.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native15.View, { style: styles12.rowInner, children: [
1194
+ option.icon && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1195
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { style: [styles12.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
877
1196
  ] }) }, option.value);
878
1197
  }) }) })
879
1198
  ] });
880
1199
  }
881
- var styles8 = import_react_native10.StyleSheet.create({
1200
+ var styles12 = import_react_native15.StyleSheet.create({
882
1201
  anchor: {
883
1202
  position: "relative"
884
1203
  },
@@ -930,31 +1249,26 @@ var styles8 = import_react_native10.StyleSheet.create({
930
1249
  }
931
1250
  });
932
1251
 
933
- // src/loadSkiaWeb.ts
934
- function loadSkiaWeb() {
935
- return Promise.resolve();
936
- }
937
-
938
1252
  // src/PressAwayOverlay.tsx
939
- var import_react_native11 = require("react-native");
940
- var import_jsx_runtime9 = require("react/jsx-runtime");
1253
+ var import_react_native16 = require("react-native");
1254
+ var import_jsx_runtime15 = require("react/jsx-runtime");
941
1255
  function PressAwayOverlay({ active, onPress, style }) {
942
1256
  if (!active) return null;
943
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native11.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native11.StyleSheet.absoluteFill, style] });
1257
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native16.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native16.StyleSheet.absoluteFill, style] });
944
1258
  }
945
1259
 
946
1260
  // src/ReadyButton.tsx
947
- var import_feedback_press6 = require("@rific/feedback-press");
948
- var import_react_native12 = require("react-native");
949
- var import_react_native_paper6 = require("react-native-paper");
950
- var import_jsx_runtime10 = require("react/jsx-runtime");
1261
+ var import_feedback_press8 = require("@rific/feedback-press");
1262
+ var import_react_native17 = require("react-native");
1263
+ var import_react_native_paper9 = require("react-native-paper");
1264
+ var import_jsx_runtime16 = require("react/jsx-runtime");
951
1265
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
952
- const readyButtonStyle = [styles9.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1266
+ const readyButtonStyle = [styles13.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
953
1267
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
954
1268
  const labelColorStyle = { color: ready ? "#000000" : color };
955
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press6.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper6.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1269
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_feedback_press8.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper9.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
956
1270
  }
957
- var styles9 = import_react_native12.StyleSheet.create({
1271
+ var styles13 = import_react_native17.StyleSheet.create({
958
1272
  readyButton: {
959
1273
  alignItems: "center",
960
1274
  borderRadius: 12,
@@ -966,228 +1280,22 @@ var styles9 = import_react_native12.StyleSheet.create({
966
1280
  }
967
1281
  });
968
1282
 
969
- // src/SectionedDropdown.tsx
970
- var import_auto_paper6 = require("@rific/auto-paper");
971
- var import_feedback_press7 = require("@rific/feedback-press");
972
- var import_react_native14 = require("react-native");
973
- var import_react_native_paper7 = require("react-native-paper");
974
-
975
- // src/TriggerGaugeHost.tsx
976
- var import_react5 = require("react");
977
- var import_jsx_runtime12 = require("react/jsx-runtime");
978
- var LazyTriggerGauge = (0, import_react5.lazy)(() => loadSkiaWeb().then(() => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((m) => ({ default: m.TriggerGauge }))));
979
- function TriggerGaugeHost(props) {
980
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react5.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(LazyTriggerGauge, { ...props }) });
981
- }
982
-
983
- // src/SectionedDropdown.tsx
984
- var import_jsx_runtime13 = require("react/jsx-runtime");
985
- var MENU_BORDER_WIDTH = 1;
986
- var TRIGGER_SIZE = 44;
987
- var MENU_MIN_WIDTH = 200;
988
- var MENU_MAX_WIDTH = 220;
989
- var MENU_ITEM_ICON_SIZE = 18;
990
- var MENU_ITEM_LABEL_MAX_WIDTH = 150;
991
- var MENU_ITEM_HEIGHT = 40;
992
- var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
993
- var MENU_DIVIDER_HEIGHT = 9;
994
- var MENU_VERTICAL_PADDING = 12;
995
- function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
996
- const menuBg = dark ? "#000000" : "#FFFFFF";
997
- const menuBorderColor = (0, import_auto_paper6.getBlendedColor)(mutedColor, menuBg, 0.5);
998
- const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper6.getColorRoles)(accentColor, menuBg).onColor;
999
- const fg = dark ? "#FFFFFF" : "#000000";
1000
- const open = host.openId === id;
1001
- const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
1002
- const rows = section.options.reduce((rowSum, option) => rowSum + (option.description ? MENU_ITEM_HEIGHT_WITH_DESCRIPTION : MENU_ITEM_HEIGHT), 0);
1003
- const footer = section.kind === "multi" && section.allClear ? MENU_ITEM_HEIGHT : 0;
1004
- const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
1005
- return sum + rows + footer + divider;
1006
- }, 0);
1007
- const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight);
1008
- const align = alignOverride ?? autoAlign;
1009
- const onlySection = sections.length === 1 ? sections[0] : null;
1010
- const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
1011
- const triggerIcon = selectedOption?.icon ?? icon;
1012
- const triggerIconSize = selectedOption?.iconSize ?? 22;
1013
- const hasMultiSection = sections.some((s) => s.kind === "multi");
1014
- const anyMultiSelected = sections.some((s) => s.kind === "multi" && s.value.length > 0);
1015
- const triggerIconColor = hasMultiSection ? anyMultiSelected ? accentColor : fg : fg;
1016
- const gaugeSegments = sections.reduce((sum, section) => sum + section.options.length, 0);
1017
- const gaugeLitIndices = [];
1018
- let gaugeOffset = 0;
1019
- for (const section of sections) {
1020
- if (section.kind === "single") {
1021
- const index = section.options.findIndex((o) => o.value === section.value);
1022
- if (index >= 0) gaugeLitIndices.push(gaugeOffset + index);
1023
- } else {
1024
- section.options.forEach((o, i) => {
1025
- if (section.value.includes(o.value)) gaugeLitIndices.push(gaugeOffset + i);
1026
- });
1027
- }
1028
- gaugeOffset += section.options.length;
1029
- }
1030
- const anchorStyle = [styles11.anchor, open && styles11.anchorOpen];
1031
- const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
1032
- const dividerStyle = { backgroundColor: menuBorderColor };
1033
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: anchorStyle, children: [
1034
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { ref: triggerRef, collapsable: false, style: styles11.triggerBox, children: [
1035
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1036
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press7.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1037
- ] }),
1038
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.ScrollView, { style: [styles11.menu, menuStyle], contentContainerStyle: styles11.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { children: [
1039
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native14.View, { style: [styles11.divider, dividerStyle] }),
1040
- section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1041
- SingleSection,
1042
- {
1043
- section,
1044
- accentColor,
1045
- onAccentColor: resolvedOnAccentColor,
1046
- mutedColor,
1047
- labelFontFamily,
1048
- onSelect: (value) => {
1049
- section.onChange(value);
1050
- if (autoDismiss) host.close();
1051
- }
1052
- }
1053
- ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1054
- ] }, section.id)) }) })
1055
- ] });
1056
- }
1057
- function SingleSection({
1058
- section,
1059
- accentColor,
1060
- onAccentColor,
1061
- mutedColor,
1062
- labelFontFamily,
1063
- onSelect
1064
- }) {
1065
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: section.options.map((option) => {
1066
- const selected = option.value === section.value;
1067
- const taken = !selected && option.value === section.takenValue;
1068
- const rowColor = selected ? onAccentColor : mutedColor;
1069
- const itemStyle = [styles11.item, selected && { backgroundColor: accentColor }, taken && styles11.itemTaken];
1070
- const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1071
- const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
1072
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press7.TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: styles11.itemRow, children: [
1073
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1074
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: styles11.itemLabelColumn, children: [
1075
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1076
- option.description && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1077
- ] })
1078
- ] }) }, option.value);
1079
- }) });
1080
- }
1081
- function MultiSection({
1082
- section,
1083
- accentColor,
1084
- onAccentColor,
1085
- mutedColor,
1086
- labelFontFamily,
1087
- allClearLabels
1088
- }) {
1089
- const allSelected = section.value.length === section.options.length;
1090
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1091
- section.options.map((option, i) => {
1092
- const selected = section.value.includes(option.value);
1093
- const rowColor = selected ? onAccentColor : mutedColor;
1094
- const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
1095
- const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
1096
- const itemStyle = [styles11.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1097
- const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1098
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: styles11.itemRow, children: [
1099
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1100
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Text, { variant: "labelLarge", style: [styles11.itemLabelFlex, labelStyle], children: option.label })
1101
- ] }) }, option.value);
1102
- }),
1103
- section.allClear && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles11.item, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper7.Text, { variant: "labelLarge", style: [styles11.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1104
- ] });
1105
- }
1106
- var styles11 = import_react_native14.StyleSheet.create({
1107
- allClearLabel: {
1108
- fontWeight: "bold",
1109
- textAlign: "center"
1110
- },
1111
- anchor: {
1112
- position: "relative"
1113
- },
1114
- // React Native Web gives every position:'relative' view an explicit zIndex (0, not 'auto'),
1115
- // which makes each one its own stacking context — so a zIndex set only on the popover content
1116
- // below only wins comparisons within this anchor's own box, not against this anchor's own later
1117
- // siblings (e.g. a Ready button), which are otherwise painted on top by DOM-order tiebreak.
1118
- // Elevating the anchor itself, only while its popover is open, fixes that at the right level.
1119
- anchorOpen: {
1120
- zIndex: 100
1121
- },
1122
- divider: {
1123
- height: import_react_native14.StyleSheet.hairlineWidth,
1124
- marginVertical: 4
1125
- },
1126
- item: {
1127
- borderRadius: 8,
1128
- paddingHorizontal: 12,
1129
- paddingVertical: 8
1130
- },
1131
- itemLabelColumn: {
1132
- maxWidth: MENU_ITEM_LABEL_MAX_WIDTH
1133
- },
1134
- itemLabelFlex: {
1135
- flex: 1
1136
- },
1137
- itemRow: {
1138
- alignItems: "center",
1139
- flexDirection: "row",
1140
- gap: 8
1141
- },
1142
- // Same opacity as ProfilePicker's rowDisabled / InlineColorPicker's swatchTaken — the fleet's
1143
- // established "shown, not removed" treatment for another seat's own current pick.
1144
- itemTaken: {
1145
- opacity: 0.35
1146
- },
1147
- menu: {
1148
- borderRadius: 12,
1149
- borderWidth: MENU_BORDER_WIDTH,
1150
- elevation: 8,
1151
- maxWidth: MENU_MAX_WIDTH,
1152
- minWidth: MENU_MIN_WIDTH,
1153
- shadowColor: "#000000",
1154
- shadowOffset: { height: 2, width: 0 },
1155
- shadowOpacity: 0.3,
1156
- shadowRadius: 8
1157
- },
1158
- // Separate from `menu` itself — a ScrollView's own style sets the scrolling frame's bounds
1159
- // (including the maxHeight that actually caps it), while padding/gap belong to its
1160
- // contentContainerStyle, which sizes to the *unclamped* content instead of the frame.
1161
- menuContent: {
1162
- gap: 4,
1163
- padding: 6
1164
- },
1165
- // Fixed hit-area regardless of the current option's iconSize, so a small-vs-large trigger icon
1166
- // doesn't shift this picker's position within its row.
1167
- triggerBox: {
1168
- alignItems: "center",
1169
- height: TRIGGER_SIZE,
1170
- justifyContent: "center",
1171
- width: TRIGGER_SIZE
1172
- }
1173
- });
1174
-
1175
1283
  // src/SharedActionBand.tsx
1176
- var import_feedback_press8 = require("@rific/feedback-press");
1177
- var import_react_native15 = require("react-native");
1178
- var import_jsx_runtime14 = require("react/jsx-runtime");
1284
+ var import_feedback_press9 = require("@rific/feedback-press");
1285
+ var import_react_native18 = require("react-native");
1286
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1179
1287
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
1180
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native15.View, { style: [styles12.column, popoverOpen && styles12.columnOpen], children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native15.View, { style: styles12.actionsRow, children: [
1182
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press8.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1183
- onRandomize && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press8.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1184
- onReset && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press8.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1185
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_feedback_press8.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native18.View, { style: [styles14.column, popoverOpen && styles14.columnOpen], children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react_native18.View, { style: styles14.actionsRow, children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press9.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1291
+ onRandomize && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press9.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1292
+ onReset && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press9.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1293
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_feedback_press9.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1186
1294
  ] }),
1187
1295
  children
1188
1296
  ] });
1189
1297
  }
1190
- var styles12 = import_react_native15.StyleSheet.create({
1298
+ var styles14 = import_react_native18.StyleSheet.create({
1191
1299
  actionsRow: {
1192
1300
  alignItems: "center",
1193
1301
  flexDirection: "row",
@@ -1203,20 +1311,20 @@ var styles12 = import_react_native15.StyleSheet.create({
1203
1311
  });
1204
1312
 
1205
1313
  // src/StatRow.tsx
1206
- var import_auto_paper7 = require("@rific/auto-paper");
1207
- var import_react_native16 = require("react-native");
1208
- var import_react_native_paper8 = require("react-native-paper");
1209
- var import_jsx_runtime15 = require("react/jsx-runtime");
1314
+ var import_auto_paper8 = require("@rific/auto-paper");
1315
+ var import_react_native19 = require("react-native");
1316
+ var import_react_native_paper10 = require("react-native-paper");
1317
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1210
1318
  function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
1211
- const { dark } = (0, import_auto_paper7.useAutoPaperTheme)();
1319
+ const { dark } = (0, import_auto_paper8.useAutoPaperTheme)();
1212
1320
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1213
1321
  const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
1214
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native16.View, { style: styles13.row, children: [
1215
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper8.Text, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
1216
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper8.Text, { variant: "bodyMedium", style: [styles13.value, { color: fg }], children: value })
1322
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react_native19.View, { style: styles15.row, children: [
1323
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Text, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
1324
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper10.Text, { variant: "bodyMedium", style: [styles15.value, { color: fg }], children: value })
1217
1325
  ] });
1218
1326
  }
1219
- var styles13 = import_react_native16.StyleSheet.create({
1327
+ var styles15 = import_react_native19.StyleSheet.create({
1220
1328
  row: {
1221
1329
  alignItems: "center",
1222
1330
  flexDirection: "row",
@@ -1228,20 +1336,20 @@ var styles13 = import_react_native16.StyleSheet.create({
1228
1336
  });
1229
1337
 
1230
1338
  // src/StatSection.tsx
1231
- var import_auto_paper8 = require("@rific/auto-paper");
1232
- var import_react_native17 = require("react-native");
1233
- var import_react_native_paper9 = require("react-native-paper");
1234
- var import_jsx_runtime16 = require("react/jsx-runtime");
1339
+ var import_auto_paper9 = require("@rific/auto-paper");
1340
+ var import_react_native20 = require("react-native");
1341
+ var import_react_native_paper11 = require("react-native-paper");
1342
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1235
1343
  function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
1236
- const { dark } = (0, import_auto_paper8.useAutoPaperTheme)();
1344
+ const { dark } = (0, import_auto_paper9.useAutoPaperTheme)();
1237
1345
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1238
1346
  const sectionBg = sectionBgOverride ?? (dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)");
1239
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_react_native17.View, { style: [styles14.section, { backgroundColor: sectionBg }], children: [
1240
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper9.Text, { variant: "labelMedium", style: [styles14.label, { color: fg }], children: label }),
1347
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_native20.View, { style: [styles16.section, { backgroundColor: sectionBg }], children: [
1348
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native_paper11.Text, { variant: "labelMedium", style: [styles16.label, { color: fg }], children: label }),
1241
1349
  children
1242
1350
  ] });
1243
1351
  }
1244
- var styles14 = import_react_native17.StyleSheet.create({
1352
+ var styles16 = import_react_native20.StyleSheet.create({
1245
1353
  // Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
1246
1354
  // same visual weight as StatRow's own row labels below it (both used the identical muted color;
1247
1355
  // letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
@@ -1272,8 +1380,11 @@ function usePopoverHost() {
1272
1380
  AchievementRow,
1273
1381
  BaseSettingsDialog,
1274
1382
  BaseStatsScreen,
1383
+ ConfirmDialog,
1275
1384
  ContentGutter,
1385
+ ControlSchemePicker,
1276
1386
  CornerActionButtons,
1387
+ CornerStatusBadges,
1277
1388
  InlineColorPicker,
1278
1389
  LABELED_DROPDOWN_POPOVER_WIDTH,
1279
1390
  LOCKED_BADGE_COLOR,