@tastic/hud 0.5.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) });
@@ -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_runtime10.jsx)(import_react_native12.View, { style: [styles9.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
124
- /* @__PURE__ */ (0, import_jsx_runtime10.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_runtime10.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_core3, import_react4, import_react_native12, import_react_native_reanimated, import_jsx_runtime10, 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, styles9;
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
133
  import_core3 = require("@tastic/core");
134
- import_react4 = require("react");
135
- import_react_native12 = require("react-native");
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_runtime10 = 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
- styles9 = import_react_native12.StyleSheet.create({
147
+ styles7 = import_react_native8.StyleSheet.create({
148
148
  container: {
149
149
  alignItems: "center",
150
150
  justifyContent: "center",
@@ -160,7 +160,11 @@ __export(index_exports, {
160
160
  AchievementRow: () => AchievementRow,
161
161
  BaseSettingsDialog: () => BaseSettingsDialog,
162
162
  BaseStatsScreen: () => BaseStatsScreen,
163
+ ConfirmDialog: () => ConfirmDialog,
164
+ ContentGutter: () => ContentGutter,
165
+ ControlSchemePicker: () => ControlSchemePicker,
163
166
  CornerActionButtons: () => CornerActionButtons,
167
+ CornerStatusBadges: () => CornerStatusBadges,
164
168
  InlineColorPicker: () => InlineColorPicker,
165
169
  LABELED_DROPDOWN_POPOVER_WIDTH: () => LABELED_DROPDOWN_POPOVER_WIDTH,
166
170
  LOCKED_BADGE_COLOR: () => LOCKED_BADGE_COLOR,
@@ -415,25 +419,25 @@ var styles2 = import_react_native2.StyleSheet.create({
415
419
  sectionLabel: {
416
420
  letterSpacing: 2
417
421
  },
418
- // Negative margin cancels the padding so the icon still lines up with APPEARANCE/SOUND &
419
- // HAPTICS below, while the ripple/hover highlight itself gets room to breathe on both sides
420
- // instead of a flush edge-to-edge slab. overflow: 'hidden' makes sure that highlight actually
421
- // clips to borderRadius instead of drawing as a plain rectangle.
422
+ // Used to carry marginHorizontal: -12 + paddingHorizontal: 12 (netting to the same inset as
423
+ // APPEARANCE/SOUND & HAPTICS below, while giving the ripple/hover highlight room to breathe
424
+ // into the dialog's own gutter beyond that). Removed: this dialog scrolls (Dialog.ScrollArea +
425
+ // ScrollView above), and on web a ScrollView's own content wrapper clips to its own bounds
426
+ // regardless of a child's negative margin - confirmed live, the icon's own rounded-square badge
427
+ // was getting its left edge sliced off by exactly that overhang. No horizontal inset of its own
428
+ // now - it relies purely on the same dialog padding APPEARANCE/every other row already does,
429
+ // which can never overflow because it's never negative.
422
430
  toggleButton: {
423
431
  borderRadius: 12,
424
- marginHorizontal: -12,
425
432
  overflow: "hidden",
426
- paddingHorizontal: 12,
427
433
  paddingVertical: 10
428
434
  },
429
- // Same shape as toggleButton but `flex: 1` instead of its own `marginHorizontal: -12` — two of
430
- // these side by side in toggleRow would otherwise both pull inward and collide in the middle.
431
- // toggleRow carries that edge-alignment margin once, for the row as a whole, instead.
435
+ // Same shape as toggleButton, `flex: 1` instead of its own width - two of these side by side in
436
+ // toggleRow share the row's own edge alignment instead of each carrying their own.
432
437
  toggleButtonInRow: {
433
438
  borderRadius: 12,
434
439
  flex: 1,
435
440
  overflow: "hidden",
436
- paddingHorizontal: 12,
437
441
  paddingVertical: 10
438
442
  },
439
443
  toggleContent: {
@@ -444,10 +448,10 @@ var styles2 = import_react_native2.StyleSheet.create({
444
448
  toggleGroup: {
445
449
  gap: 4
446
450
  },
451
+ // No horizontal margin of its own now either - see toggleButton's identical note.
447
452
  toggleRow: {
448
453
  flexDirection: "row",
449
- gap: 4,
450
- marginHorizontal: -12
454
+ gap: 4
451
455
  }
452
456
  });
453
457
 
@@ -552,61 +556,128 @@ var styles3 = import_react_native3.StyleSheet.create({
552
556
  }
553
557
  });
554
558
 
555
- // src/CornerActionButtons.tsx
559
+ // src/ConfirmDialog.tsx
560
+ var import_auto_paper4 = require("@rific/auto-paper");
556
561
  var import_feedback_press3 = require("@rific/feedback-press");
557
562
  var import_react_native4 = require("react-native");
563
+ var import_react_native_paper4 = require("react-native-paper");
558
564
  var import_jsx_runtime4 = require("react/jsx-runtime");
559
- function CornerActionButtons({ onBack, onSettings, fg, insets }) {
560
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
561
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press3.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, style: [styles4.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: "Back" }),
562
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press3.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles4.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
563
- ] });
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
+ ] }) }) });
564
582
  }
565
583
  var styles4 = import_react_native4.StyleSheet.create({
566
- back: {
567
- position: "absolute"
584
+ actionButton: {
585
+ flex: 1
568
586
  },
569
- topRight: {
570
- position: "absolute"
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"
571
615
  }
572
616
  });
573
617
 
574
- // src/fonts.ts
618
+ // src/ContentGutter.tsx
619
+ var import_core2 = require("@tastic/core");
575
620
  var import_react_native5 = require("react-native");
576
- var MONO_FONT = import_react_native5.Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
621
+ var import_jsx_runtime5 = require("react/jsx-runtime");
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 })
629
+ ] });
630
+ }
631
+ var styles5 = import_react_native5.StyleSheet.create({
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"
636
+ },
637
+ row: {
638
+ flexDirection: "row"
639
+ }
640
+ });
577
641
 
578
- // src/InlineColorPicker.tsx
579
- var import_auto_paper4 = require("@rific/auto-paper");
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");
580
648
  var import_feedback_press4 = require("@rific/feedback-press");
581
- var import_core2 = require("@tastic/core");
582
- var import_react_native8 = require("react-native");
583
- var import_react_native_paper4 = require("react-native-paper");
649
+ var import_react_native10 = require("react-native");
650
+ var import_react_native_paper5 = require("react-native-paper");
584
651
 
585
- // src/PopoverBody.tsx
652
+ // src/fonts.ts
586
653
  var import_react_native6 = require("react-native");
587
- var import_jsx_runtime5 = require("react/jsx-runtime");
654
+ var MONO_FONT = import_react_native6.Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
655
+
656
+ // src/PopoverBody.tsx
657
+ var import_react_native7 = require("react-native");
658
+ var import_jsx_runtime6 = require("react/jsx-runtime");
588
659
  var CARET_SIZE = 7;
589
660
  var CARET_RING_OFFSET = 2;
590
661
  var CARET_DIP = 1;
591
662
  function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
592
663
  if (!visible) return null;
593
664
  const above = verticalAlign === "above";
594
- const alignStyle = align === "left" ? styles5.contentLeft : align === "right" ? styles5.contentRight : styles5.contentCenter;
595
- const verticalStyle = above ? styles5.contentAbove : styles5.contentBelow;
665
+ const alignStyle = align === "left" ? styles6.contentLeft : align === "right" ? styles6.contentRight : styles6.contentCenter;
666
+ const verticalStyle = above ? styles6.contentAbove : styles6.contentBelow;
596
667
  const ringSize = CARET_SIZE + caretBorderWidth;
597
668
  const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
598
669
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
599
670
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
600
671
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
601
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native6.View, { style: [styles5.content, alignStyle, verticalStyle], children: [
672
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native7.View, { style: [styles6.content, alignStyle, verticalStyle], children: [
602
673
  children,
603
- caretColor && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: [styles5.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
605
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native6.View, { style: [styles5.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
674
+ caretColor && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
675
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: [styles6.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
676
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native7.View, { style: [styles6.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
606
677
  ] })
607
678
  ] });
608
679
  }
609
- var styles5 = import_react_native6.StyleSheet.create({
680
+ var styles6 = import_react_native7.StyleSheet.create({
610
681
  caret: {
611
682
  borderLeftColor: "transparent",
612
683
  borderRightColor: "transparent",
@@ -648,23 +719,38 @@ var styles5 = import_react_native6.StyleSheet.create({
648
719
  }
649
720
  });
650
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
+
651
737
  // src/useAutoAlign.ts
652
- var import_react3 = require("react");
653
- var import_react_native7 = require("react-native");
738
+ var import_react5 = require("react");
739
+ var import_react_native9 = require("react-native");
654
740
  var EDGE_MARGIN = 12;
655
741
  function useAutoAlign(open, contentWidth, contentHeight) {
656
- const triggerRef = (0, import_react3.useRef)(null);
657
- const { width: windowWidth, height: windowHeight } = (0, import_react_native7.useWindowDimensions)();
658
- const [align, setAlign] = (0, import_react3.useState)("center");
659
- const [verticalAlign, setVerticalAlign] = (0, import_react3.useState)("below");
660
- const [maxHeight, setMaxHeight] = (0, import_react3.useState)(contentHeight);
661
- const [measured, setMeasured] = (0, import_react3.useState)(false);
662
- 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);
663
749
  if (open !== prevOpen) {
664
750
  setPrevOpen(open);
665
751
  if (open) setMeasured(false);
666
752
  }
667
- const measure = (0, import_react3.useCallback)(() => {
753
+ const measure = (0, import_react5.useCallback)(() => {
668
754
  triggerRef.current?.measureInWindow((x, y, triggerWidth, triggerHeight) => {
669
755
  const centerX = x + triggerWidth / 2;
670
756
  const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
@@ -680,14 +766,272 @@ function useAutoAlign(open, contentWidth, contentHeight) {
680
766
  setMeasured(true);
681
767
  });
682
768
  }, [contentWidth, contentHeight, windowWidth, windowHeight]);
683
- (0, import_react3.useEffect)(() => {
769
+ (0, import_react5.useEffect)(() => {
684
770
  if (open) measure();
685
771
  }, [open, measure]);
686
772
  return { align, maxHeight, measured, triggerRef, verticalAlign };
687
773
  }
688
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
+
689
1028
  // src/InlineColorPicker.tsx
690
- var import_jsx_runtime6 = 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");
691
1035
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
692
1036
  var DEFAULT_SIZE = 48;
693
1037
  var SWATCH_SIZE = 28;
@@ -700,10 +1044,10 @@ var SCREEN_MARGIN = 40;
700
1044
  function widthForColumns(columns) {
701
1045
  return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
702
1046
  }
703
- function InlineColorPicker({ id, host, value, onChange, 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 }) {
704
1048
  const menuBg = dark ? "#000000" : "#FFFFFF";
705
- const { width: windowWidth } = (0, import_react_native8.useWindowDimensions)();
706
- const autoColumns = (0, import_core2.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);
707
1051
  const resolvedColumns = columns ?? autoColumns;
708
1052
  const swatchesWidth = widthForColumns(resolvedColumns);
709
1053
  const swatchRows = Math.ceil(swatches.length / resolvedColumns);
@@ -711,16 +1055,19 @@ function InlineColorPicker({ id, host, value, onChange, swatches = import_auto_p
711
1055
  const open = host.openId === id;
712
1056
  const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, swatchesWidth, swatchesHeight);
713
1057
  const align = alignOverride ?? autoAlign;
714
- const contrastColor = (0, import_auto_paper4.getContrastColor)(value);
1058
+ const displayFor = previewValue ?? ((hex) => hex);
1059
+ const displayValue = displayFor(value);
1060
+ const contrastColor = (0, import_auto_paper6.getContrastColor)(displayValue);
715
1061
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
716
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react_native8.View, { style: [styles6.anchor, open && styles6.anchorOpen], children: [
717
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles6.trigger, { backgroundColor: value, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native8.View, { ref: triggerRef, collapsable: false, style: styles6.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Text, { style: [styles6.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
718
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: value, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native8.ScrollView, { style: [styles6.swatches, { backgroundColor: menuBg, borderColor: value, width: swatchesWidth, maxHeight }], contentContainerStyle: styles6.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) => {
719
1065
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
720
1066
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
721
1067
  const swappable = taken && allowSwapTaken;
722
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
723
- import_feedback_press4.TouchableRipple,
1068
+ const swatchDisplay = displayFor(swatch.value);
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1070
+ import_feedback_press6.TouchableRipple,
724
1071
  {
725
1072
  disabled: taken && !swappable,
726
1073
  onPress: () => {
@@ -728,15 +1075,15 @@ function InlineColorPicker({ id, host, value, onChange, swatches = import_auto_p
728
1075
  if (autoDismiss) host.close();
729
1076
  },
730
1077
  borderless: true,
731
- style: [styles6.swatch, { backgroundColor: swatch.value }, selected && styles6.swatchSelected, taken && !swappable && styles6.swatchTaken],
732
- children: selected ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Icon, { source: "check", size: 16, color: (0, import_auto_paper4.getContrastColor)(swatch.value) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper4.getContrastColor)(swatch.value) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native_paper4.Icon, { source: "close", size: 16, color: (0, import_auto_paper4.getContrastColor)(swatch.value) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native8.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, {})
733
1080
  },
734
1081
  swatch.value
735
1082
  );
736
1083
  }) }) })
737
1084
  ] });
738
1085
  }
739
- var styles6 = import_react_native8.StyleSheet.create({
1086
+ var styles11 = import_react_native14.StyleSheet.create({
740
1087
  anchor: {
741
1088
  position: "relative"
742
1089
  },
@@ -782,6 +1129,10 @@ var styles6 = import_react_native8.StyleSheet.create({
782
1129
  gap: SWATCHES_GAP,
783
1130
  padding: SWATCHES_PADDING
784
1131
  },
1132
+ tagLabel: {
1133
+ fontWeight: "700",
1134
+ letterSpacing: 0.5
1135
+ },
785
1136
  // borderRadius/height/width come from the `size` prop instead (see render-site override) — no
786
1137
  // fixed default here, since this style object is shared by every caller regardless of size.
787
1138
  trigger: {
@@ -800,19 +1151,15 @@ var styles6 = import_react_native8.StyleSheet.create({
800
1151
  justifyContent: "center",
801
1152
  paddingHorizontal: 4,
802
1153
  width: "100%"
803
- },
804
- tagLabel: {
805
- fontWeight: "700",
806
- letterSpacing: 0.5
807
1154
  }
808
1155
  });
809
1156
 
810
1157
  // src/LabeledDropdown.tsx
811
- var import_auto_paper5 = require("@rific/auto-paper");
812
- var import_feedback_press5 = require("@rific/feedback-press");
813
- var import_react_native9 = require("react-native");
814
- var import_react_native_paper5 = require("react-native-paper");
815
- var import_jsx_runtime7 = 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");
816
1163
  var TRIGGER_HEIGHT = 28;
817
1164
  var POPOVER_WIDTH = 180;
818
1165
  var ROW_HEIGHT = 36;
@@ -835,22 +1182,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
835
1182
  onChange(option.value);
836
1183
  host.close();
837
1184
  };
838
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: [styles7.anchor, open && styles7.anchorOpen], children: [
839
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press5.TouchableRipple, { onPress: () => host.toggle(id), style: styles7.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { ref: triggerRef, collapsable: false, style: styles7.triggerInner, children: [
840
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { style: [styles7.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
841
- /* @__PURE__ */ (0, import_jsx_runtime7.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 })
842
1189
  ] }) }),
843
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.ScrollView, { style: [styles7.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles7.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) => {
844
1191
  const isSelected = option.value === value;
845
- const onColor = (0, import_auto_paper5.getContrastColor)(color);
846
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press5.TouchableRipple, { onPress: () => handleSelect(option), style: [styles7.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: styles7.rowInner, children: [
847
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
848
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper5.Text, { style: [styles7.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 })
849
1196
  ] }) }, option.value);
850
1197
  }) }) })
851
1198
  ] });
852
1199
  }
853
- var styles7 = import_react_native9.StyleSheet.create({
1200
+ var styles12 = import_react_native15.StyleSheet.create({
854
1201
  anchor: {
855
1202
  position: "relative"
856
1203
  },
@@ -902,31 +1249,26 @@ var styles7 = import_react_native9.StyleSheet.create({
902
1249
  }
903
1250
  });
904
1251
 
905
- // src/loadSkiaWeb.ts
906
- function loadSkiaWeb() {
907
- return Promise.resolve();
908
- }
909
-
910
1252
  // src/PressAwayOverlay.tsx
911
- var import_react_native10 = require("react-native");
912
- var import_jsx_runtime8 = require("react/jsx-runtime");
1253
+ var import_react_native16 = require("react-native");
1254
+ var import_jsx_runtime15 = require("react/jsx-runtime");
913
1255
  function PressAwayOverlay({ active, onPress, style }) {
914
1256
  if (!active) return null;
915
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native10.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] });
916
1258
  }
917
1259
 
918
1260
  // src/ReadyButton.tsx
919
- var import_feedback_press6 = require("@rific/feedback-press");
920
- var import_react_native11 = require("react-native");
921
- var import_react_native_paper6 = require("react-native-paper");
922
- var import_jsx_runtime9 = 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");
923
1265
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
924
- const readyButtonStyle = [styles8.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1266
+ const readyButtonStyle = [styles13.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
925
1267
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
926
1268
  const labelColorStyle = { color: ready ? "#000000" : color };
927
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_feedback_press6.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime9.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?" }) });
928
1270
  }
929
- var styles8 = import_react_native11.StyleSheet.create({
1271
+ var styles13 = import_react_native17.StyleSheet.create({
930
1272
  readyButton: {
931
1273
  alignItems: "center",
932
1274
  borderRadius: 12,
@@ -938,222 +1280,22 @@ var styles8 = import_react_native11.StyleSheet.create({
938
1280
  }
939
1281
  });
940
1282
 
941
- // src/SectionedDropdown.tsx
942
- var import_auto_paper6 = require("@rific/auto-paper");
943
- var import_feedback_press7 = require("@rific/feedback-press");
944
- var import_react_native13 = require("react-native");
945
- var import_react_native_paper7 = require("react-native-paper");
946
-
947
- // src/TriggerGaugeHost.tsx
948
- var import_react5 = require("react");
949
- var import_jsx_runtime11 = require("react/jsx-runtime");
950
- var LazyTriggerGauge = (0, import_react5.lazy)(() => loadSkiaWeb().then(() => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((m) => ({ default: m.TriggerGauge }))));
951
- function TriggerGaugeHost(props) {
952
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react5.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(LazyTriggerGauge, { ...props }) });
953
- }
954
-
955
- // src/SectionedDropdown.tsx
956
- var import_jsx_runtime12 = require("react/jsx-runtime");
957
- var MENU_BORDER_WIDTH = 1;
958
- var TRIGGER_SIZE = 44;
959
- var MENU_MIN_WIDTH = 200;
960
- var MENU_MAX_WIDTH = 220;
961
- var MENU_ITEM_ICON_SIZE = 18;
962
- var MENU_ITEM_LABEL_MAX_WIDTH = 150;
963
- var MENU_ITEM_HEIGHT = 40;
964
- var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
965
- var MENU_DIVIDER_HEIGHT = 9;
966
- var MENU_VERTICAL_PADDING = 12;
967
- function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
968
- const menuBg = dark ? "#000000" : "#FFFFFF";
969
- const menuBorderColor = (0, import_auto_paper6.getBlendedColor)(mutedColor, menuBg, 0.5);
970
- const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper6.getColorRoles)(accentColor, menuBg).onColor;
971
- const fg = dark ? "#FFFFFF" : "#000000";
972
- const open = host.openId === id;
973
- const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
974
- const rows = section.options.reduce((rowSum, option) => rowSum + (option.description ? MENU_ITEM_HEIGHT_WITH_DESCRIPTION : MENU_ITEM_HEIGHT), 0);
975
- const footer = section.kind === "multi" && section.allClear ? MENU_ITEM_HEIGHT : 0;
976
- const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
977
- return sum + rows + footer + divider;
978
- }, 0);
979
- const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight);
980
- const align = alignOverride ?? autoAlign;
981
- const onlySection = sections.length === 1 ? sections[0] : null;
982
- const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
983
- const triggerIcon = selectedOption?.icon ?? icon;
984
- const triggerIconSize = selectedOption?.iconSize ?? 22;
985
- const hasMultiSection = sections.some((s) => s.kind === "multi");
986
- const anyMultiSelected = sections.some((s) => s.kind === "multi" && s.value.length > 0);
987
- const triggerIconColor = hasMultiSection ? anyMultiSelected ? accentColor : fg : fg;
988
- const gaugeSegments = sections.reduce((sum, section) => sum + section.options.length, 0);
989
- const gaugeLitIndices = [];
990
- let gaugeOffset = 0;
991
- for (const section of sections) {
992
- if (section.kind === "single") {
993
- const index = section.options.findIndex((o) => o.value === section.value);
994
- if (index >= 0) gaugeLitIndices.push(gaugeOffset + index);
995
- } else {
996
- section.options.forEach((o, i) => {
997
- if (section.value.includes(o.value)) gaugeLitIndices.push(gaugeOffset + i);
998
- });
999
- }
1000
- gaugeOffset += section.options.length;
1001
- }
1002
- const anchorStyle = [styles10.anchor, open && styles10.anchorOpen];
1003
- const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
1004
- const dividerStyle = { backgroundColor: menuBorderColor };
1005
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: anchorStyle, children: [
1006
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { ref: triggerRef, collapsable: false, style: styles10.triggerBox, children: [
1007
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
1008
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press7.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
1009
- ] }),
1010
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.ScrollView, { style: [styles10.menu, menuStyle], contentContainerStyle: styles10.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { children: [
1011
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native13.View, { style: [styles10.divider, dividerStyle] }),
1012
- section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1013
- SingleSection,
1014
- {
1015
- section,
1016
- accentColor,
1017
- onAccentColor: resolvedOnAccentColor,
1018
- mutedColor,
1019
- labelFontFamily,
1020
- onSelect: (value) => {
1021
- section.onChange(value);
1022
- if (autoDismiss) host.close();
1023
- }
1024
- }
1025
- ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
1026
- ] }, section.id)) }) })
1027
- ] });
1028
- }
1029
- function SingleSection({
1030
- section,
1031
- accentColor,
1032
- onAccentColor,
1033
- mutedColor,
1034
- labelFontFamily,
1035
- onSelect
1036
- }) {
1037
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: section.options.map((option) => {
1038
- const selected = option.value === section.value;
1039
- const rowColor = selected ? onAccentColor : mutedColor;
1040
- const itemStyle = [styles10.item, selected && { backgroundColor: accentColor }];
1041
- const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1042
- const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
1043
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: styles10.itemRow, children: [
1044
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper7.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1045
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_react_native13.View, { style: styles10.itemLabelColumn, children: [
1046
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper7.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
1047
- option.description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper7.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
1048
- ] })
1049
- ] }) }, option.value);
1050
- }) });
1051
- }
1052
- function MultiSection({
1053
- section,
1054
- accentColor,
1055
- onAccentColor,
1056
- mutedColor,
1057
- labelFontFamily,
1058
- allClearLabels
1059
- }) {
1060
- const allSelected = section.value.length === section.options.length;
1061
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1062
- section.options.map((option, i) => {
1063
- const selected = section.value.includes(option.value);
1064
- const rowColor = selected ? onAccentColor : mutedColor;
1065
- const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
1066
- const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
1067
- const itemStyle = [styles10.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
1068
- const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
1069
- return /* @__PURE__ */ (0, import_jsx_runtime12.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_runtime12.jsxs)(import_react_native13.View, { style: styles10.itemRow, children: [
1070
- option.icon && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper7.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
1071
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper7.Text, { variant: "labelLarge", style: [styles10.itemLabelFlex, labelStyle], children: option.label })
1072
- ] }) }, option.value);
1073
- }),
1074
- section.allClear && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_feedback_press7.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles10.item, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper7.Text, { variant: "labelLarge", style: [styles10.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
1075
- ] });
1076
- }
1077
- var styles10 = import_react_native13.StyleSheet.create({
1078
- allClearLabel: {
1079
- fontWeight: "bold",
1080
- textAlign: "center"
1081
- },
1082
- anchor: {
1083
- position: "relative"
1084
- },
1085
- // React Native Web gives every position:'relative' view an explicit zIndex (0, not 'auto'),
1086
- // which makes each one its own stacking context — so a zIndex set only on the popover content
1087
- // below only wins comparisons within this anchor's own box, not against this anchor's own later
1088
- // siblings (e.g. a Ready button), which are otherwise painted on top by DOM-order tiebreak.
1089
- // Elevating the anchor itself, only while its popover is open, fixes that at the right level.
1090
- anchorOpen: {
1091
- zIndex: 100
1092
- },
1093
- divider: {
1094
- height: import_react_native13.StyleSheet.hairlineWidth,
1095
- marginVertical: 4
1096
- },
1097
- item: {
1098
- borderRadius: 8,
1099
- paddingHorizontal: 12,
1100
- paddingVertical: 8
1101
- },
1102
- itemLabelColumn: {
1103
- maxWidth: MENU_ITEM_LABEL_MAX_WIDTH
1104
- },
1105
- itemLabelFlex: {
1106
- flex: 1
1107
- },
1108
- itemRow: {
1109
- alignItems: "center",
1110
- flexDirection: "row",
1111
- gap: 8
1112
- },
1113
- menu: {
1114
- borderRadius: 12,
1115
- borderWidth: MENU_BORDER_WIDTH,
1116
- elevation: 8,
1117
- maxWidth: MENU_MAX_WIDTH,
1118
- minWidth: MENU_MIN_WIDTH,
1119
- shadowColor: "#000000",
1120
- shadowOffset: { height: 2, width: 0 },
1121
- shadowOpacity: 0.3,
1122
- shadowRadius: 8
1123
- },
1124
- // Separate from `menu` itself — a ScrollView's own style sets the scrolling frame's bounds
1125
- // (including the maxHeight that actually caps it), while padding/gap belong to its
1126
- // contentContainerStyle, which sizes to the *unclamped* content instead of the frame.
1127
- menuContent: {
1128
- gap: 4,
1129
- padding: 6
1130
- },
1131
- // Fixed hit-area regardless of the current option's iconSize, so a small-vs-large trigger icon
1132
- // doesn't shift this picker's position within its row.
1133
- triggerBox: {
1134
- alignItems: "center",
1135
- height: TRIGGER_SIZE,
1136
- justifyContent: "center",
1137
- width: TRIGGER_SIZE
1138
- }
1139
- });
1140
-
1141
1283
  // src/SharedActionBand.tsx
1142
- var import_feedback_press8 = require("@rific/feedback-press");
1143
- var import_react_native14 = require("react-native");
1144
- var import_jsx_runtime13 = 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");
1145
1287
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
1146
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: [styles11.column, popoverOpen && styles11.columnOpen], children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_react_native14.View, { style: styles11.actionsRow, children: [
1148
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press8.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1149
- onRandomize && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press8.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1150
- onReset && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_feedback_press8.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1151
- /* @__PURE__ */ (0, import_jsx_runtime13.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" })
1152
1294
  ] }),
1153
1295
  children
1154
1296
  ] });
1155
1297
  }
1156
- var styles11 = import_react_native14.StyleSheet.create({
1298
+ var styles14 = import_react_native18.StyleSheet.create({
1157
1299
  actionsRow: {
1158
1300
  alignItems: "center",
1159
1301
  flexDirection: "row",
@@ -1169,20 +1311,20 @@ var styles11 = import_react_native14.StyleSheet.create({
1169
1311
  });
1170
1312
 
1171
1313
  // src/StatRow.tsx
1172
- var import_auto_paper7 = require("@rific/auto-paper");
1173
- var import_react_native15 = require("react-native");
1174
- var import_react_native_paper8 = require("react-native-paper");
1175
- var import_jsx_runtime14 = 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");
1176
1318
  function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
1177
- const { dark } = (0, import_auto_paper7.useAutoPaperTheme)();
1319
+ const { dark } = (0, import_auto_paper8.useAutoPaperTheme)();
1178
1320
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1179
1321
  const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
1180
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_react_native15.View, { style: styles12.row, children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
1182
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper8.Text, { variant: "bodyMedium", style: [styles12.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 })
1183
1325
  ] });
1184
1326
  }
1185
- var styles12 = import_react_native15.StyleSheet.create({
1327
+ var styles15 = import_react_native19.StyleSheet.create({
1186
1328
  row: {
1187
1329
  alignItems: "center",
1188
1330
  flexDirection: "row",
@@ -1194,20 +1336,20 @@ var styles12 = import_react_native15.StyleSheet.create({
1194
1336
  });
1195
1337
 
1196
1338
  // src/StatSection.tsx
1197
- var import_auto_paper8 = require("@rific/auto-paper");
1198
- var import_react_native16 = require("react-native");
1199
- var import_react_native_paper9 = require("react-native-paper");
1200
- var import_jsx_runtime15 = 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");
1201
1343
  function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
1202
- const { dark } = (0, import_auto_paper8.useAutoPaperTheme)();
1344
+ const { dark } = (0, import_auto_paper9.useAutoPaperTheme)();
1203
1345
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1204
1346
  const sectionBg = sectionBgOverride ?? (dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)");
1205
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native16.View, { style: [styles13.section, { backgroundColor: sectionBg }], children: [
1206
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper9.Text, { variant: "labelMedium", style: [styles13.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 }),
1207
1349
  children
1208
1350
  ] });
1209
1351
  }
1210
- var styles13 = import_react_native16.StyleSheet.create({
1352
+ var styles16 = import_react_native20.StyleSheet.create({
1211
1353
  // Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
1212
1354
  // same visual weight as StatRow's own row labels below it (both used the identical muted color;
1213
1355
  // letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
@@ -1238,7 +1380,11 @@ function usePopoverHost() {
1238
1380
  AchievementRow,
1239
1381
  BaseSettingsDialog,
1240
1382
  BaseStatsScreen,
1383
+ ConfirmDialog,
1384
+ ContentGutter,
1385
+ ControlSchemePicker,
1241
1386
  CornerActionButtons,
1387
+ CornerStatusBadges,
1242
1388
  InlineColorPicker,
1243
1389
  LABELED_DROPDOWN_POPOVER_WIDTH,
1244
1390
  LOCKED_BADGE_COLOR,