@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.mjs CHANGED
@@ -369,20 +369,79 @@ var styles3 = StyleSheet3.create({
369
369
  }
370
370
  });
371
371
 
372
+ // src/ConfirmDialog.tsx
373
+ import { useAutoPaperTheme as useAutoPaperTheme4 } from "@rific/auto-paper";
374
+ import { Button as Button3 } from "@rific/feedback-press";
375
+ import { StyleSheet as StyleSheet4, View as View4 } from "react-native";
376
+ import { Icon as Icon4, Portal as Portal3, Text as Text4 } from "react-native-paper";
377
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
378
+ function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
379
+ const { dark, colors } = useAutoPaperTheme4();
380
+ if (!visible) return null;
381
+ const fg = dark ? "#FFFFFF" : "#000000";
382
+ const cardBg = dark ? "#111111" : "#F2F2F2";
383
+ const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
384
+ const accent = destructive ? colors.danger : colors.primary;
385
+ const onAccent = destructive ? colors.onDanger : colors.onPrimary;
386
+ return /* @__PURE__ */ jsx4(Portal3, { children: /* @__PURE__ */ jsx4(View4, { style: styles4.overlay, children: /* @__PURE__ */ jsxs4(View4, { style: [styles4.card, { backgroundColor: cardBg, borderColor: cardBorder }, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
387
+ /* @__PURE__ */ jsx4(Icon4, { source: icon, size: 64, color: accent }),
388
+ /* @__PURE__ */ jsx4(Text4, { variant: "headlineLarge", style: [styles4.title, { color: accent }], children: title }),
389
+ /* @__PURE__ */ jsx4(Text4, { variant: "bodyLarge", style: [styles4.body, { color: fg }], children: message }),
390
+ /* @__PURE__ */ jsxs4(View4, { style: styles4.actions, children: [
391
+ /* @__PURE__ */ jsx4(Button3, { mode: "outlined", onPress: onCancel, style: styles4.actionButton, children: cancelLabel }),
392
+ /* @__PURE__ */ jsx4(Button3, { mode: "contained", onPress: onConfirm, style: styles4.actionButton, buttonColor: accent, textColor: onAccent, children: confirmLabel })
393
+ ] })
394
+ ] }) }) });
395
+ }
396
+ var styles4 = StyleSheet4.create({
397
+ actionButton: {
398
+ flex: 1
399
+ },
400
+ actions: {
401
+ flexDirection: "row",
402
+ gap: 12,
403
+ width: "100%"
404
+ },
405
+ body: {
406
+ textAlign: "center"
407
+ },
408
+ card: {
409
+ alignItems: "center",
410
+ borderRadius: 20,
411
+ borderWidth: 1,
412
+ gap: 16,
413
+ maxWidth: 360,
414
+ padding: 32
415
+ },
416
+ overlay: {
417
+ alignItems: "center",
418
+ backgroundColor: "rgba(0,0,0,0.72)",
419
+ bottom: 0,
420
+ justifyContent: "center",
421
+ left: 0,
422
+ position: "absolute",
423
+ right: 0,
424
+ top: 0
425
+ },
426
+ title: {
427
+ fontWeight: "bold"
428
+ }
429
+ });
430
+
372
431
  // src/ContentGutter.tsx
373
432
  import { computeContentBounds } from "@tastic/core";
374
- import { StyleSheet as StyleSheet4, useWindowDimensions, View as View4 } from "react-native";
375
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
433
+ import { StyleSheet as StyleSheet5, useWindowDimensions, View as View5 } from "react-native";
434
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
376
435
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
377
436
  const { width: windowWidth } = useWindowDimensions();
378
437
  const { contentWidth, gutterWidth } = computeContentBounds(windowWidth, maxContentWidth ?? Infinity);
379
- return /* @__PURE__ */ jsxs4(View4, { style: [styles4.row, style], children: [
380
- /* @__PURE__ */ jsx4(View4, { style: [styles4.gutter, { width: gutterWidth }], children: leftGutter }),
381
- /* @__PURE__ */ jsx4(View4, { style: { width: contentWidth }, children }),
382
- /* @__PURE__ */ jsx4(View4, { style: [styles4.gutter, { width: gutterWidth }], children: rightGutter })
438
+ return /* @__PURE__ */ jsxs5(View5, { style: [styles5.row, style], children: [
439
+ /* @__PURE__ */ jsx5(View5, { style: [styles5.gutter, { width: gutterWidth }], children: leftGutter }),
440
+ /* @__PURE__ */ jsx5(View5, { style: { width: contentWidth }, children }),
441
+ /* @__PURE__ */ jsx5(View5, { style: [styles5.gutter, { width: gutterWidth }], children: rightGutter })
383
442
  ] });
384
443
  }
385
- var styles4 = StyleSheet4.create({
444
+ var styles5 = StyleSheet5.create({
386
445
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
387
446
  // column instead of clipping cleanly at its own real width.
388
447
  gutter: {
@@ -393,39 +452,23 @@ var styles4 = StyleSheet4.create({
393
452
  }
394
453
  });
395
454
 
396
- // src/CornerActionButtons.tsx
397
- import { IconButton as IconButton2 } from "@rific/feedback-press";
398
- import { StyleSheet as StyleSheet5 } from "react-native";
399
- import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
400
- function CornerActionButtons({ onBack, onSettings, fg, insets }) {
401
- return /* @__PURE__ */ jsxs5(Fragment2, { children: [
402
- /* @__PURE__ */ jsx5(IconButton2, { icon: "arrow-left", iconColor: fg, size: 24, style: [styles5.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: "Back" }),
403
- /* @__PURE__ */ jsx5(IconButton2, { icon: "cog", iconColor: fg, size: 24, style: [styles5.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
404
- ] });
405
- }
406
- var styles5 = StyleSheet5.create({
407
- back: {
408
- position: "absolute"
409
- },
410
- topRight: {
411
- position: "absolute"
412
- }
413
- });
455
+ // src/ControlSchemePicker.tsx
456
+ import { useIsTouchPrimaryDevice as useIsTouchPrimaryDevice2 } from "@tastic/core";
457
+ import { Platform as Platform3 } from "react-native";
458
+
459
+ // src/SectionedDropdown.tsx
460
+ import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
461
+ import { IconButton as IconButton2, TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
462
+ import { ScrollView as ScrollView3, StyleSheet as StyleSheet7, View as View8 } from "react-native";
463
+ import { Icon as Icon5, Text as Text5 } from "react-native-paper";
414
464
 
415
465
  // src/fonts.ts
416
466
  import { Platform as Platform2 } from "react-native";
417
467
  var MONO_FONT = Platform2.select({ ios: "Menlo", android: "monospace", default: "monospace" });
418
468
 
419
- // src/InlineColorPicker.tsx
420
- import { defaultColors, getContrastColor } from "@rific/auto-paper";
421
- import { TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
422
- import { clamp } from "@tastic/core";
423
- import { ScrollView as ScrollView3, StyleSheet as StyleSheet7, useWindowDimensions as useWindowDimensions3, View as View7 } from "react-native";
424
- import { Icon as Icon4, Text as Text4 } from "react-native-paper";
425
-
426
469
  // src/PopoverBody.tsx
427
- import { StyleSheet as StyleSheet6, View as View5 } from "react-native";
428
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
470
+ import { StyleSheet as StyleSheet6, View as View6 } from "react-native";
471
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
429
472
  var CARET_SIZE = 7;
430
473
  var CARET_RING_OFFSET = 2;
431
474
  var CARET_DIP = 1;
@@ -439,11 +482,11 @@ function PopoverBody({ visible, children, align = "center", verticalAlign = "bel
439
482
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
440
483
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
441
484
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
442
- return /* @__PURE__ */ jsxs6(View5, { style: [styles6.content, alignStyle, verticalStyle], children: [
485
+ return /* @__PURE__ */ jsxs6(View6, { style: [styles6.content, alignStyle, verticalStyle], children: [
443
486
  children,
444
- caretColor && /* @__PURE__ */ jsxs6(Fragment3, { children: [
445
- /* @__PURE__ */ jsx6(View5, { style: [styles6.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
446
- /* @__PURE__ */ jsx6(View5, { style: [styles6.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
487
+ caretColor && /* @__PURE__ */ jsxs6(Fragment2, { children: [
488
+ /* @__PURE__ */ jsx6(View6, { style: [styles6.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
489
+ /* @__PURE__ */ jsx6(View6, { style: [styles6.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
447
490
  ] })
448
491
  ] });
449
492
  }
@@ -489,6 +532,21 @@ var styles6 = StyleSheet6.create({
489
532
  }
490
533
  });
491
534
 
535
+ // src/TriggerGaugeHost.tsx
536
+ import { lazy, Suspense } from "react";
537
+
538
+ // src/loadSkiaWeb.ts
539
+ function loadSkiaWeb() {
540
+ return Promise.resolve();
541
+ }
542
+
543
+ // src/TriggerGaugeHost.tsx
544
+ import { jsx as jsx7 } from "react/jsx-runtime";
545
+ var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-2OJOOF6I.mjs").then((m) => ({ default: m.TriggerGauge }))));
546
+ function TriggerGaugeHost(props) {
547
+ return /* @__PURE__ */ jsx7(Suspense, { fallback: null, children: /* @__PURE__ */ jsx7(LazyTriggerGauge, { ...props }) });
548
+ }
549
+
492
550
  // src/useAutoAlign.ts
493
551
  import { useCallback, useEffect, useRef, useState as useState3 } from "react";
494
552
  import { useWindowDimensions as useWindowDimensions2 } from "react-native";
@@ -527,8 +585,266 @@ function useAutoAlign(open, contentWidth, contentHeight) {
527
585
  return { align, maxHeight, measured, triggerRef, verticalAlign };
528
586
  }
529
587
 
588
+ // src/SectionedDropdown.tsx
589
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
590
+ var MENU_BORDER_WIDTH = 1;
591
+ var TRIGGER_SIZE = 44;
592
+ var MENU_MIN_WIDTH = 200;
593
+ var MENU_MAX_WIDTH = 220;
594
+ var MENU_ITEM_ICON_SIZE = 18;
595
+ var MENU_ITEM_LABEL_MAX_WIDTH = 150;
596
+ var MENU_ITEM_HEIGHT = 40;
597
+ var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
598
+ var MENU_DIVIDER_HEIGHT = 9;
599
+ var MENU_VERTICAL_PADDING = 12;
600
+ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
601
+ const menuBg = dark ? "#000000" : "#FFFFFF";
602
+ const menuBorderColor = getBlendedColor(mutedColor, menuBg, 0.5);
603
+ const resolvedOnAccentColor = onAccentColor ?? getColorRoles(accentColor, menuBg).onColor;
604
+ const fg = dark ? "#FFFFFF" : "#000000";
605
+ const open = host.openId === id;
606
+ const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
607
+ const rows = section.options.reduce((rowSum, option) => rowSum + (option.description ? MENU_ITEM_HEIGHT_WITH_DESCRIPTION : MENU_ITEM_HEIGHT), 0);
608
+ const footer = section.kind === "multi" && section.allClear ? MENU_ITEM_HEIGHT : 0;
609
+ const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
610
+ return sum + rows + footer + divider;
611
+ }, 0);
612
+ const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight);
613
+ const align = alignOverride ?? autoAlign;
614
+ const onlySection = sections.length === 1 ? sections[0] : null;
615
+ const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
616
+ const triggerIcon = selectedOption?.icon ?? icon;
617
+ const triggerIconSize = selectedOption?.iconSize ?? 22;
618
+ const hasMultiSection = sections.some((s) => s.kind === "multi");
619
+ const anyMultiSelected = sections.some((s) => s.kind === "multi" && s.value.length > 0);
620
+ const triggerIconColor = hasMultiSection ? anyMultiSelected ? accentColor : fg : fg;
621
+ const gaugeSegments = sections.reduce((sum, section) => sum + section.options.length, 0);
622
+ const gaugeLitIndices = [];
623
+ let gaugeOffset = 0;
624
+ for (const section of sections) {
625
+ if (section.kind === "single") {
626
+ const index = section.options.findIndex((o) => o.value === section.value);
627
+ if (index >= 0) gaugeLitIndices.push(gaugeOffset + index);
628
+ } else {
629
+ section.options.forEach((o, i) => {
630
+ if (section.value.includes(o.value)) gaugeLitIndices.push(gaugeOffset + i);
631
+ });
632
+ }
633
+ gaugeOffset += section.options.length;
634
+ }
635
+ const anchorStyle = [styles7.anchor, open && styles7.anchorOpen];
636
+ const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
637
+ const dividerStyle = { backgroundColor: menuBorderColor };
638
+ return /* @__PURE__ */ jsxs7(View8, { style: anchorStyle, children: [
639
+ /* @__PURE__ */ jsxs7(View8, { ref: triggerRef, collapsable: false, style: styles7.triggerBox, children: [
640
+ /* @__PURE__ */ jsx8(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
641
+ /* @__PURE__ */ jsx8(IconButton2, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
642
+ ] }),
643
+ /* @__PURE__ */ jsx8(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx8(ScrollView3, { style: [styles7.menu, menuStyle], contentContainerStyle: styles7.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs7(View8, { children: [
644
+ sectionIndex > 0 && /* @__PURE__ */ jsx8(View8, { style: [styles7.divider, dividerStyle] }),
645
+ section.kind === "single" ? /* @__PURE__ */ jsx8(
646
+ SingleSection,
647
+ {
648
+ section,
649
+ accentColor,
650
+ onAccentColor: resolvedOnAccentColor,
651
+ mutedColor,
652
+ labelFontFamily,
653
+ onSelect: (value) => {
654
+ section.onChange(value);
655
+ if (autoDismiss) host.close();
656
+ }
657
+ }
658
+ ) : /* @__PURE__ */ jsx8(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
659
+ ] }, section.id)) }) })
660
+ ] });
661
+ }
662
+ function SingleSection({
663
+ section,
664
+ accentColor,
665
+ onAccentColor,
666
+ mutedColor,
667
+ labelFontFamily,
668
+ onSelect
669
+ }) {
670
+ return /* @__PURE__ */ jsx8(Fragment3, { children: section.options.map((option) => {
671
+ const selected = option.value === section.value;
672
+ const taken = !selected && option.value === section.takenValue;
673
+ const rowColor = selected ? onAccentColor : mutedColor;
674
+ const itemStyle = [styles7.item, selected && { backgroundColor: accentColor }, taken && styles7.itemTaken];
675
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
676
+ const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
677
+ return /* @__PURE__ */ jsx8(TouchableRipple2, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs7(View8, { style: styles7.itemRow, children: [
678
+ option.icon && /* @__PURE__ */ jsx8(Icon5, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
679
+ /* @__PURE__ */ jsxs7(View8, { style: styles7.itemLabelColumn, children: [
680
+ /* @__PURE__ */ jsx8(Text5, { variant: "labelLarge", style: labelStyle, children: option.label }),
681
+ option.description && /* @__PURE__ */ jsx8(Text5, { variant: "labelSmall", style: descriptionStyle, children: option.description })
682
+ ] })
683
+ ] }) }, option.value);
684
+ }) });
685
+ }
686
+ function MultiSection({
687
+ section,
688
+ accentColor,
689
+ onAccentColor,
690
+ mutedColor,
691
+ labelFontFamily,
692
+ allClearLabels
693
+ }) {
694
+ const allSelected = section.value.length === section.options.length;
695
+ return /* @__PURE__ */ jsxs7(Fragment3, { children: [
696
+ section.options.map((option, i) => {
697
+ const selected = section.value.includes(option.value);
698
+ const rowColor = selected ? onAccentColor : mutedColor;
699
+ const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
700
+ const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
701
+ const itemStyle = [styles7.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
702
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
703
+ return /* @__PURE__ */ jsx8(TouchableRipple2, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs7(View8, { style: styles7.itemRow, children: [
704
+ option.icon && /* @__PURE__ */ jsx8(Icon5, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
705
+ /* @__PURE__ */ jsx8(Text5, { variant: "labelLarge", style: [styles7.itemLabelFlex, labelStyle], children: option.label })
706
+ ] }) }, option.value);
707
+ }),
708
+ section.allClear && /* @__PURE__ */ jsx8(TouchableRipple2, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles7.item, children: /* @__PURE__ */ jsx8(Text5, { variant: "labelLarge", style: [styles7.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
709
+ ] });
710
+ }
711
+ var styles7 = StyleSheet7.create({
712
+ allClearLabel: {
713
+ fontWeight: "bold",
714
+ textAlign: "center"
715
+ },
716
+ anchor: {
717
+ position: "relative"
718
+ },
719
+ // React Native Web gives every position:'relative' view an explicit zIndex (0, not 'auto'),
720
+ // which makes each one its own stacking context — so a zIndex set only on the popover content
721
+ // below only wins comparisons within this anchor's own box, not against this anchor's own later
722
+ // siblings (e.g. a Ready button), which are otherwise painted on top by DOM-order tiebreak.
723
+ // Elevating the anchor itself, only while its popover is open, fixes that at the right level.
724
+ anchorOpen: {
725
+ zIndex: 100
726
+ },
727
+ divider: {
728
+ height: StyleSheet7.hairlineWidth,
729
+ marginVertical: 4
730
+ },
731
+ item: {
732
+ borderRadius: 8,
733
+ paddingHorizontal: 12,
734
+ paddingVertical: 8
735
+ },
736
+ itemLabelColumn: {
737
+ maxWidth: MENU_ITEM_LABEL_MAX_WIDTH
738
+ },
739
+ itemLabelFlex: {
740
+ flex: 1
741
+ },
742
+ itemRow: {
743
+ alignItems: "center",
744
+ flexDirection: "row",
745
+ gap: 8
746
+ },
747
+ // Same opacity as ProfilePicker's rowDisabled / InlineColorPicker's swatchTaken — the fleet's
748
+ // established "shown, not removed" treatment for another seat's own current pick.
749
+ itemTaken: {
750
+ opacity: 0.35
751
+ },
752
+ menu: {
753
+ borderRadius: 12,
754
+ borderWidth: MENU_BORDER_WIDTH,
755
+ elevation: 8,
756
+ maxWidth: MENU_MAX_WIDTH,
757
+ minWidth: MENU_MIN_WIDTH,
758
+ shadowColor: "#000000",
759
+ shadowOffset: { height: 2, width: 0 },
760
+ shadowOpacity: 0.3,
761
+ shadowRadius: 8
762
+ },
763
+ // Separate from `menu` itself — a ScrollView's own style sets the scrolling frame's bounds
764
+ // (including the maxHeight that actually caps it), while padding/gap belong to its
765
+ // contentContainerStyle, which sizes to the *unclamped* content instead of the frame.
766
+ menuContent: {
767
+ gap: 4,
768
+ padding: 6
769
+ },
770
+ // Fixed hit-area regardless of the current option's iconSize, so a small-vs-large trigger icon
771
+ // doesn't shift this picker's position within its row.
772
+ triggerBox: {
773
+ alignItems: "center",
774
+ height: TRIGGER_SIZE,
775
+ justifyContent: "center",
776
+ width: TRIGGER_SIZE
777
+ }
778
+ });
779
+
780
+ // src/ControlSchemePicker.tsx
781
+ import { jsx as jsx9 } from "react/jsx-runtime";
782
+ function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, labelFontFamily }) {
783
+ const isTouchPrimary = useIsTouchPrimaryDevice2();
784
+ if (Platform3.OS !== "web" || isTouchPrimary) return null;
785
+ return /* @__PURE__ */ jsx9(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, labelFontFamily });
786
+ }
787
+
788
+ // src/CornerActionButtons.tsx
789
+ import { IconButton as IconButton3 } from "@rific/feedback-press";
790
+ import { StyleSheet as StyleSheet8 } from "react-native";
791
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
792
+ function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
793
+ return /* @__PURE__ */ jsxs8(Fragment4, { children: [
794
+ /* @__PURE__ */ jsx10(IconButton3, { icon: backIcon, iconColor: fg, size: 24, style: [styles8.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
795
+ /* @__PURE__ */ jsx10(IconButton3, { icon: "cog", iconColor: fg, size: 24, style: [styles8.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
796
+ ] });
797
+ }
798
+ var styles8 = StyleSheet8.create({
799
+ back: {
800
+ position: "absolute"
801
+ },
802
+ topRight: {
803
+ position: "absolute"
804
+ }
805
+ });
806
+
807
+ // src/CornerStatusBadges.tsx
808
+ import { StyleSheet as StyleSheet9, View as View9 } from "react-native";
809
+ import { Icon as Icon6 } from "react-native-paper";
810
+ import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
811
+ var BADGE_SIZE = 30;
812
+ function StatusBadge({ icon }) {
813
+ return /* @__PURE__ */ jsx11(View9, { style: styles9.badge, children: icon && /* @__PURE__ */ jsx11(Icon6, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
814
+ }
815
+ function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
816
+ const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
817
+ const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
818
+ return /* @__PURE__ */ jsxs9(Fragment5, { children: [
819
+ p1 && /* @__PURE__ */ jsx11(View9, { pointerEvents: "none", style: p1OnRightSide ? styles9.bottomRight : styles9.bottomLeft, children: /* @__PURE__ */ jsx11(StatusBadge, { icon: p1.icon }) }),
820
+ p2 && /* @__PURE__ */ jsx11(View9, { pointerEvents: "none", style: p2OnLeftSide ? styles9.topLeft : styles9.topRight, children: /* @__PURE__ */ jsx11(StatusBadge, { icon: p2.icon }) })
821
+ ] });
822
+ }
823
+ var styles9 = StyleSheet9.create({
824
+ badge: {
825
+ alignItems: "center",
826
+ backgroundColor: "rgba(0,0,0,0.28)",
827
+ borderColor: "rgba(255,255,255,0.18)",
828
+ borderRadius: BADGE_SIZE / 2,
829
+ borderWidth: 1,
830
+ height: BADGE_SIZE,
831
+ justifyContent: "center",
832
+ opacity: 0.7,
833
+ width: BADGE_SIZE
834
+ },
835
+ bottomLeft: { bottom: 12, left: 12, position: "absolute" },
836
+ bottomRight: { bottom: 12, position: "absolute", right: 12 },
837
+ topLeft: { left: 12, position: "absolute", top: 12 },
838
+ topRight: { position: "absolute", right: 12, top: 12 }
839
+ });
840
+
530
841
  // src/InlineColorPicker.tsx
531
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
842
+ import { defaultColors, getContrastColor } from "@rific/auto-paper";
843
+ import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
844
+ import { clamp } from "@tastic/core";
845
+ import { ScrollView as ScrollView4, StyleSheet as StyleSheet10, useWindowDimensions as useWindowDimensions3, View as View10 } from "react-native";
846
+ import { Icon as Icon7, Text as Text6 } from "react-native-paper";
847
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
532
848
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
533
849
  var DEFAULT_SIZE = 48;
534
850
  var SWATCH_SIZE = 28;
@@ -556,15 +872,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
556
872
  const displayValue = displayFor(value);
557
873
  const contrastColor = getContrastColor(displayValue);
558
874
  const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
559
- return /* @__PURE__ */ jsxs7(View7, { style: [styles7.anchor, open && styles7.anchorOpen], children: [
560
- /* @__PURE__ */ jsx7(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles7.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx7(View7, { ref: triggerRef, collapsable: false, style: styles7.triggerMeasure, children: tag ? /* @__PURE__ */ jsx7(Text4, { style: [styles7.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx7(Icon4, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
561
- /* @__PURE__ */ jsx7(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx7(ScrollView3, { style: [styles7.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles7.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
875
+ return /* @__PURE__ */ jsxs10(View10, { style: [styles10.anchor, open && styles10.anchorOpen], children: [
876
+ /* @__PURE__ */ jsx12(TouchableRipple3, { onPress: () => host.toggle(id), borderless: true, style: [styles10.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx12(View10, { ref: triggerRef, collapsable: false, style: styles10.triggerMeasure, children: tag ? /* @__PURE__ */ jsx12(Text6, { style: [styles10.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx12(Icon7, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
877
+ /* @__PURE__ */ jsx12(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx12(ScrollView4, { style: [styles10.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles10.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
562
878
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
563
879
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
564
880
  const swappable = taken && allowSwapTaken;
565
881
  const swatchDisplay = displayFor(swatch.value);
566
- return /* @__PURE__ */ jsx7(
567
- TouchableRipple2,
882
+ return /* @__PURE__ */ jsx12(
883
+ TouchableRipple3,
568
884
  {
569
885
  disabled: taken && !swappable,
570
886
  onPress: () => {
@@ -572,15 +888,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
572
888
  if (autoDismiss) host.close();
573
889
  },
574
890
  borderless: true,
575
- style: [styles7.swatch, { backgroundColor: swatchDisplay }, selected && styles7.swatchSelected, taken && !swappable && styles7.swatchTaken],
576
- children: selected ? /* @__PURE__ */ jsx7(Icon4, { source: "check", size: 16, color: getContrastColor(swatchDisplay) }) : swappable ? /* @__PURE__ */ jsx7(Icon4, { source: "swap-horizontal", size: 16, color: getContrastColor(swatchDisplay) }) : taken ? /* @__PURE__ */ jsx7(Icon4, { source: "close", size: 16, color: getContrastColor(swatchDisplay) }) : /* @__PURE__ */ jsx7(View7, {})
891
+ style: [styles10.swatch, { backgroundColor: swatchDisplay }, selected && styles10.swatchSelected, taken && !swappable && styles10.swatchTaken],
892
+ children: selected ? /* @__PURE__ */ jsx12(Icon7, { source: "check", size: 16, color: getContrastColor(swatchDisplay) }) : swappable ? /* @__PURE__ */ jsx12(Icon7, { source: "swap-horizontal", size: 16, color: getContrastColor(swatchDisplay) }) : taken ? /* @__PURE__ */ jsx12(Icon7, { source: "close", size: 16, color: getContrastColor(swatchDisplay) }) : /* @__PURE__ */ jsx12(View10, {})
577
893
  },
578
894
  swatch.value
579
895
  );
580
896
  }) }) })
581
897
  ] });
582
898
  }
583
- var styles7 = StyleSheet7.create({
899
+ var styles10 = StyleSheet10.create({
584
900
  anchor: {
585
901
  position: "relative"
586
902
  },
@@ -653,10 +969,10 @@ var styles7 = StyleSheet7.create({
653
969
 
654
970
  // src/LabeledDropdown.tsx
655
971
  import { getContrastColor as getContrastColor2 } from "@rific/auto-paper";
656
- import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
657
- import { ScrollView as ScrollView4, StyleSheet as StyleSheet8, View as View8 } from "react-native";
658
- import { Icon as Icon5, Text as Text5 } from "react-native-paper";
659
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
972
+ import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
973
+ import { ScrollView as ScrollView5, StyleSheet as StyleSheet11, View as View11 } from "react-native";
974
+ import { Icon as Icon8, Text as Text7 } from "react-native-paper";
975
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
660
976
  var TRIGGER_HEIGHT = 28;
661
977
  var POPOVER_WIDTH = 180;
662
978
  var ROW_HEIGHT = 36;
@@ -679,22 +995,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
679
995
  onChange(option.value);
680
996
  host.close();
681
997
  };
682
- return /* @__PURE__ */ jsxs8(View8, { style: [styles8.anchor, open && styles8.anchorOpen], children: [
683
- /* @__PURE__ */ jsx8(TouchableRipple3, { onPress: () => host.toggle(id), style: styles8.trigger, children: /* @__PURE__ */ jsxs8(View8, { ref: triggerRef, collapsable: false, style: styles8.triggerInner, children: [
684
- /* @__PURE__ */ jsx8(Text5, { style: [styles8.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
685
- /* @__PURE__ */ jsx8(Icon5, { source: "menu-down", size: 16, color })
998
+ return /* @__PURE__ */ jsxs11(View11, { style: [styles11.anchor, open && styles11.anchorOpen], children: [
999
+ /* @__PURE__ */ jsx13(TouchableRipple4, { onPress: () => host.toggle(id), style: styles11.trigger, children: /* @__PURE__ */ jsxs11(View11, { ref: triggerRef, collapsable: false, style: styles11.triggerInner, children: [
1000
+ /* @__PURE__ */ jsx13(Text7, { style: [styles11.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1001
+ /* @__PURE__ */ jsx13(Icon8, { source: "menu-down", size: 16, color })
686
1002
  ] }) }),
687
- /* @__PURE__ */ jsx8(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx8(ScrollView4, { style: [styles8.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles8.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
1003
+ /* @__PURE__ */ jsx13(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx13(ScrollView5, { style: [styles11.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles11.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
688
1004
  const isSelected = option.value === value;
689
1005
  const onColor = getContrastColor2(color);
690
- return /* @__PURE__ */ jsx8(TouchableRipple3, { onPress: () => handleSelect(option), style: [styles8.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs8(View8, { style: styles8.rowInner, children: [
691
- option.icon && /* @__PURE__ */ jsx8(Icon5, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
692
- /* @__PURE__ */ jsx8(Text5, { style: [styles8.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
1006
+ return /* @__PURE__ */ jsx13(TouchableRipple4, { onPress: () => handleSelect(option), style: [styles11.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs11(View11, { style: styles11.rowInner, children: [
1007
+ option.icon && /* @__PURE__ */ jsx13(Icon8, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1008
+ /* @__PURE__ */ jsx13(Text7, { style: [styles11.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
693
1009
  ] }) }, option.value);
694
1010
  }) }) })
695
1011
  ] });
696
1012
  }
697
- var styles8 = StyleSheet8.create({
1013
+ var styles11 = StyleSheet11.create({
698
1014
  anchor: {
699
1015
  position: "relative"
700
1016
  },
@@ -746,31 +1062,26 @@ var styles8 = StyleSheet8.create({
746
1062
  }
747
1063
  });
748
1064
 
749
- // src/loadSkiaWeb.ts
750
- function loadSkiaWeb() {
751
- return Promise.resolve();
752
- }
753
-
754
1065
  // src/PressAwayOverlay.tsx
755
- import { Pressable, StyleSheet as StyleSheet9 } from "react-native";
756
- import { jsx as jsx9 } from "react/jsx-runtime";
1066
+ import { Pressable, StyleSheet as StyleSheet12 } from "react-native";
1067
+ import { jsx as jsx14 } from "react/jsx-runtime";
757
1068
  function PressAwayOverlay({ active, onPress, style }) {
758
1069
  if (!active) return null;
759
- return /* @__PURE__ */ jsx9(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet9.absoluteFill, style] });
1070
+ return /* @__PURE__ */ jsx14(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet12.absoluteFill, style] });
760
1071
  }
761
1072
 
762
1073
  // src/ReadyButton.tsx
763
- import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
764
- import { StyleSheet as StyleSheet10 } from "react-native";
765
- import { Text as Text6 } from "react-native-paper";
766
- import { jsx as jsx10 } from "react/jsx-runtime";
1074
+ import { TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
1075
+ import { StyleSheet as StyleSheet13 } from "react-native";
1076
+ import { Text as Text8 } from "react-native-paper";
1077
+ import { jsx as jsx15 } from "react/jsx-runtime";
767
1078
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
768
- const readyButtonStyle = [styles9.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1079
+ const readyButtonStyle = [styles12.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
769
1080
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
770
1081
  const labelColorStyle = { color: ready ? "#000000" : color };
771
- return /* @__PURE__ */ jsx10(TouchableRipple4, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx10(Text6, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
1082
+ return /* @__PURE__ */ jsx15(TouchableRipple5, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx15(Text8, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
772
1083
  }
773
- var styles9 = StyleSheet10.create({
1084
+ var styles12 = StyleSheet13.create({
774
1085
  readyButton: {
775
1086
  alignItems: "center",
776
1087
  borderRadius: 12,
@@ -782,228 +1093,22 @@ var styles9 = StyleSheet10.create({
782
1093
  }
783
1094
  });
784
1095
 
785
- // src/SectionedDropdown.tsx
786
- import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
787
- import { IconButton as IconButton3, TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
788
- import { ScrollView as ScrollView5, StyleSheet as StyleSheet11, View as View9 } from "react-native";
789
- import { Icon as Icon6, Text as Text7 } from "react-native-paper";
790
-
791
- // src/TriggerGaugeHost.tsx
792
- import { lazy, Suspense } from "react";
793
- import { jsx as jsx11 } from "react/jsx-runtime";
794
- var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-2OJOOF6I.mjs").then((m) => ({ default: m.TriggerGauge }))));
795
- function TriggerGaugeHost(props) {
796
- return /* @__PURE__ */ jsx11(Suspense, { fallback: null, children: /* @__PURE__ */ jsx11(LazyTriggerGauge, { ...props }) });
797
- }
798
-
799
- // src/SectionedDropdown.tsx
800
- import { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
801
- var MENU_BORDER_WIDTH = 1;
802
- var TRIGGER_SIZE = 44;
803
- var MENU_MIN_WIDTH = 200;
804
- var MENU_MAX_WIDTH = 220;
805
- var MENU_ITEM_ICON_SIZE = 18;
806
- var MENU_ITEM_LABEL_MAX_WIDTH = 150;
807
- var MENU_ITEM_HEIGHT = 40;
808
- var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
809
- var MENU_DIVIDER_HEIGHT = 9;
810
- var MENU_VERTICAL_PADDING = 12;
811
- function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
812
- const menuBg = dark ? "#000000" : "#FFFFFF";
813
- const menuBorderColor = getBlendedColor(mutedColor, menuBg, 0.5);
814
- const resolvedOnAccentColor = onAccentColor ?? getColorRoles(accentColor, menuBg).onColor;
815
- const fg = dark ? "#FFFFFF" : "#000000";
816
- const open = host.openId === id;
817
- const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
818
- const rows = section.options.reduce((rowSum, option) => rowSum + (option.description ? MENU_ITEM_HEIGHT_WITH_DESCRIPTION : MENU_ITEM_HEIGHT), 0);
819
- const footer = section.kind === "multi" && section.allClear ? MENU_ITEM_HEIGHT : 0;
820
- const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
821
- return sum + rows + footer + divider;
822
- }, 0);
823
- const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight);
824
- const align = alignOverride ?? autoAlign;
825
- const onlySection = sections.length === 1 ? sections[0] : null;
826
- const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
827
- const triggerIcon = selectedOption?.icon ?? icon;
828
- const triggerIconSize = selectedOption?.iconSize ?? 22;
829
- const hasMultiSection = sections.some((s) => s.kind === "multi");
830
- const anyMultiSelected = sections.some((s) => s.kind === "multi" && s.value.length > 0);
831
- const triggerIconColor = hasMultiSection ? anyMultiSelected ? accentColor : fg : fg;
832
- const gaugeSegments = sections.reduce((sum, section) => sum + section.options.length, 0);
833
- const gaugeLitIndices = [];
834
- let gaugeOffset = 0;
835
- for (const section of sections) {
836
- if (section.kind === "single") {
837
- const index = section.options.findIndex((o) => o.value === section.value);
838
- if (index >= 0) gaugeLitIndices.push(gaugeOffset + index);
839
- } else {
840
- section.options.forEach((o, i) => {
841
- if (section.value.includes(o.value)) gaugeLitIndices.push(gaugeOffset + i);
842
- });
843
- }
844
- gaugeOffset += section.options.length;
845
- }
846
- const anchorStyle = [styles10.anchor, open && styles10.anchorOpen];
847
- const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
848
- const dividerStyle = { backgroundColor: menuBorderColor };
849
- return /* @__PURE__ */ jsxs9(View9, { style: anchorStyle, children: [
850
- /* @__PURE__ */ jsxs9(View9, { ref: triggerRef, collapsable: false, style: styles10.triggerBox, children: [
851
- /* @__PURE__ */ jsx12(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
852
- /* @__PURE__ */ jsx12(IconButton3, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
853
- ] }),
854
- /* @__PURE__ */ jsx12(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx12(ScrollView5, { style: [styles10.menu, menuStyle], contentContainerStyle: styles10.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs9(View9, { children: [
855
- sectionIndex > 0 && /* @__PURE__ */ jsx12(View9, { style: [styles10.divider, dividerStyle] }),
856
- section.kind === "single" ? /* @__PURE__ */ jsx12(
857
- SingleSection,
858
- {
859
- section,
860
- accentColor,
861
- onAccentColor: resolvedOnAccentColor,
862
- mutedColor,
863
- labelFontFamily,
864
- onSelect: (value) => {
865
- section.onChange(value);
866
- if (autoDismiss) host.close();
867
- }
868
- }
869
- ) : /* @__PURE__ */ jsx12(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
870
- ] }, section.id)) }) })
871
- ] });
872
- }
873
- function SingleSection({
874
- section,
875
- accentColor,
876
- onAccentColor,
877
- mutedColor,
878
- labelFontFamily,
879
- onSelect
880
- }) {
881
- return /* @__PURE__ */ jsx12(Fragment4, { children: section.options.map((option) => {
882
- const selected = option.value === section.value;
883
- const taken = !selected && option.value === section.takenValue;
884
- const rowColor = selected ? onAccentColor : mutedColor;
885
- const itemStyle = [styles10.item, selected && { backgroundColor: accentColor }, taken && styles10.itemTaken];
886
- const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
887
- const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
888
- return /* @__PURE__ */ jsx12(TouchableRipple5, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs9(View9, { style: styles10.itemRow, children: [
889
- option.icon && /* @__PURE__ */ jsx12(Icon6, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
890
- /* @__PURE__ */ jsxs9(View9, { style: styles10.itemLabelColumn, children: [
891
- /* @__PURE__ */ jsx12(Text7, { variant: "labelLarge", style: labelStyle, children: option.label }),
892
- option.description && /* @__PURE__ */ jsx12(Text7, { variant: "labelSmall", style: descriptionStyle, children: option.description })
893
- ] })
894
- ] }) }, option.value);
895
- }) });
896
- }
897
- function MultiSection({
898
- section,
899
- accentColor,
900
- onAccentColor,
901
- mutedColor,
902
- labelFontFamily,
903
- allClearLabels
904
- }) {
905
- const allSelected = section.value.length === section.options.length;
906
- return /* @__PURE__ */ jsxs9(Fragment4, { children: [
907
- section.options.map((option, i) => {
908
- const selected = section.value.includes(option.value);
909
- const rowColor = selected ? onAccentColor : mutedColor;
910
- const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
911
- const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
912
- const itemStyle = [styles10.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
913
- const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
914
- return /* @__PURE__ */ jsx12(TouchableRipple5, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs9(View9, { style: styles10.itemRow, children: [
915
- option.icon && /* @__PURE__ */ jsx12(Icon6, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
916
- /* @__PURE__ */ jsx12(Text7, { variant: "labelLarge", style: [styles10.itemLabelFlex, labelStyle], children: option.label })
917
- ] }) }, option.value);
918
- }),
919
- section.allClear && /* @__PURE__ */ jsx12(TouchableRipple5, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles10.item, children: /* @__PURE__ */ jsx12(Text7, { variant: "labelLarge", style: [styles10.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
920
- ] });
921
- }
922
- var styles10 = StyleSheet11.create({
923
- allClearLabel: {
924
- fontWeight: "bold",
925
- textAlign: "center"
926
- },
927
- anchor: {
928
- position: "relative"
929
- },
930
- // React Native Web gives every position:'relative' view an explicit zIndex (0, not 'auto'),
931
- // which makes each one its own stacking context — so a zIndex set only on the popover content
932
- // below only wins comparisons within this anchor's own box, not against this anchor's own later
933
- // siblings (e.g. a Ready button), which are otherwise painted on top by DOM-order tiebreak.
934
- // Elevating the anchor itself, only while its popover is open, fixes that at the right level.
935
- anchorOpen: {
936
- zIndex: 100
937
- },
938
- divider: {
939
- height: StyleSheet11.hairlineWidth,
940
- marginVertical: 4
941
- },
942
- item: {
943
- borderRadius: 8,
944
- paddingHorizontal: 12,
945
- paddingVertical: 8
946
- },
947
- itemLabelColumn: {
948
- maxWidth: MENU_ITEM_LABEL_MAX_WIDTH
949
- },
950
- itemLabelFlex: {
951
- flex: 1
952
- },
953
- itemRow: {
954
- alignItems: "center",
955
- flexDirection: "row",
956
- gap: 8
957
- },
958
- // Same opacity as ProfilePicker's rowDisabled / InlineColorPicker's swatchTaken — the fleet's
959
- // established "shown, not removed" treatment for another seat's own current pick.
960
- itemTaken: {
961
- opacity: 0.35
962
- },
963
- menu: {
964
- borderRadius: 12,
965
- borderWidth: MENU_BORDER_WIDTH,
966
- elevation: 8,
967
- maxWidth: MENU_MAX_WIDTH,
968
- minWidth: MENU_MIN_WIDTH,
969
- shadowColor: "#000000",
970
- shadowOffset: { height: 2, width: 0 },
971
- shadowOpacity: 0.3,
972
- shadowRadius: 8
973
- },
974
- // Separate from `menu` itself — a ScrollView's own style sets the scrolling frame's bounds
975
- // (including the maxHeight that actually caps it), while padding/gap belong to its
976
- // contentContainerStyle, which sizes to the *unclamped* content instead of the frame.
977
- menuContent: {
978
- gap: 4,
979
- padding: 6
980
- },
981
- // Fixed hit-area regardless of the current option's iconSize, so a small-vs-large trigger icon
982
- // doesn't shift this picker's position within its row.
983
- triggerBox: {
984
- alignItems: "center",
985
- height: TRIGGER_SIZE,
986
- justifyContent: "center",
987
- width: TRIGGER_SIZE
988
- }
989
- });
990
-
991
1096
  // src/SharedActionBand.tsx
992
1097
  import { IconButton as IconButton4 } from "@rific/feedback-press";
993
- import { StyleSheet as StyleSheet12, View as View10 } from "react-native";
994
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1098
+ import { StyleSheet as StyleSheet14, View as View12 } from "react-native";
1099
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
995
1100
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
996
- return /* @__PURE__ */ jsxs10(View10, { style: [styles11.column, popoverOpen && styles11.columnOpen], children: [
997
- /* @__PURE__ */ jsxs10(View10, { style: styles11.actionsRow, children: [
998
- /* @__PURE__ */ jsx13(IconButton4, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
999
- onRandomize && /* @__PURE__ */ jsx13(IconButton4, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1000
- onReset && /* @__PURE__ */ jsx13(IconButton4, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1001
- /* @__PURE__ */ jsx13(IconButton4, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1101
+ return /* @__PURE__ */ jsxs12(View12, { style: [styles13.column, popoverOpen && styles13.columnOpen], children: [
1102
+ /* @__PURE__ */ jsxs12(View12, { style: styles13.actionsRow, children: [
1103
+ /* @__PURE__ */ jsx16(IconButton4, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1104
+ onRandomize && /* @__PURE__ */ jsx16(IconButton4, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1105
+ onReset && /* @__PURE__ */ jsx16(IconButton4, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1106
+ /* @__PURE__ */ jsx16(IconButton4, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1002
1107
  ] }),
1003
1108
  children
1004
1109
  ] });
1005
1110
  }
1006
- var styles11 = StyleSheet12.create({
1111
+ var styles13 = StyleSheet14.create({
1007
1112
  actionsRow: {
1008
1113
  alignItems: "center",
1009
1114
  flexDirection: "row",
@@ -1019,20 +1124,20 @@ var styles11 = StyleSheet12.create({
1019
1124
  });
1020
1125
 
1021
1126
  // src/StatRow.tsx
1022
- import { useAutoPaperTheme as useAutoPaperTheme4 } from "@rific/auto-paper";
1023
- import { StyleSheet as StyleSheet13, View as View11 } from "react-native";
1024
- import { Text as Text8 } from "react-native-paper";
1025
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1127
+ import { useAutoPaperTheme as useAutoPaperTheme5 } from "@rific/auto-paper";
1128
+ import { StyleSheet as StyleSheet15, View as View13 } from "react-native";
1129
+ import { Text as Text9 } from "react-native-paper";
1130
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1026
1131
  function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
1027
- const { dark } = useAutoPaperTheme4();
1132
+ const { dark } = useAutoPaperTheme5();
1028
1133
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1029
1134
  const fgMuted = fgMutedOverride ?? (dark ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)");
1030
- return /* @__PURE__ */ jsxs11(View11, { style: styles12.row, children: [
1031
- /* @__PURE__ */ jsx14(Text8, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
1032
- /* @__PURE__ */ jsx14(Text8, { variant: "bodyMedium", style: [styles12.value, { color: fg }], children: value })
1135
+ return /* @__PURE__ */ jsxs13(View13, { style: styles14.row, children: [
1136
+ /* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
1137
+ /* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: [styles14.value, { color: fg }], children: value })
1033
1138
  ] });
1034
1139
  }
1035
- var styles12 = StyleSheet13.create({
1140
+ var styles14 = StyleSheet15.create({
1036
1141
  row: {
1037
1142
  alignItems: "center",
1038
1143
  flexDirection: "row",
@@ -1044,20 +1149,20 @@ var styles12 = StyleSheet13.create({
1044
1149
  });
1045
1150
 
1046
1151
  // src/StatSection.tsx
1047
- import { useAutoPaperTheme as useAutoPaperTheme5 } from "@rific/auto-paper";
1048
- import { StyleSheet as StyleSheet14, View as View12 } from "react-native";
1049
- import { Text as Text9 } from "react-native-paper";
1050
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1152
+ import { useAutoPaperTheme as useAutoPaperTheme6 } from "@rific/auto-paper";
1153
+ import { StyleSheet as StyleSheet16, View as View14 } from "react-native";
1154
+ import { Text as Text10 } from "react-native-paper";
1155
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1051
1156
  function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
1052
- const { dark } = useAutoPaperTheme5();
1157
+ const { dark } = useAutoPaperTheme6();
1053
1158
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1054
1159
  const sectionBg = sectionBgOverride ?? (dark ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.04)");
1055
- return /* @__PURE__ */ jsxs12(View12, { style: [styles13.section, { backgroundColor: sectionBg }], children: [
1056
- /* @__PURE__ */ jsx15(Text9, { variant: "labelMedium", style: [styles13.label, { color: fg }], children: label }),
1160
+ return /* @__PURE__ */ jsxs14(View14, { style: [styles15.section, { backgroundColor: sectionBg }], children: [
1161
+ /* @__PURE__ */ jsx18(Text10, { variant: "labelMedium", style: [styles15.label, { color: fg }], children: label }),
1057
1162
  children
1058
1163
  ] });
1059
1164
  }
1060
- var styles13 = StyleSheet14.create({
1165
+ var styles15 = StyleSheet16.create({
1061
1166
  // Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
1062
1167
  // same visual weight as StatRow's own row labels below it (both used the identical muted color;
1063
1168
  // letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
@@ -1087,8 +1192,11 @@ export {
1087
1192
  AchievementRow,
1088
1193
  BaseSettingsDialog,
1089
1194
  BaseStatsScreen,
1195
+ ConfirmDialog,
1090
1196
  ContentGutter,
1197
+ ControlSchemePicker,
1091
1198
  CornerActionButtons,
1199
+ CornerStatusBadges,
1092
1200
  InlineColorPicker,
1093
1201
  LABELED_DROPDOWN_POPOVER_WIDTH,
1094
1202
  LOCKED_BADGE_COLOR,