@tastic/hud 0.6.0 → 0.8.1

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
@@ -1,3 +1,7 @@
1
+ import {
2
+ SkiaGate
3
+ } from "./chunk-XEOFR236.mjs";
4
+
1
5
  // src/AchievementRow.tsx
2
6
  import { useAutoPaperTheme } from "@rific/auto-paper";
3
7
  import { StyleSheet, View } from "react-native";
@@ -70,7 +74,7 @@ var styles = StyleSheet.create({
70
74
  import { AutoAppearancePicker, Dialog, useAutoPaperTheme as useAutoPaperTheme2 } from "@rific/auto-paper";
71
75
  import { Button, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from "@rific/feedback-press";
72
76
  import { useUpdater } from "@rific/updater";
73
- import { useIsTouchPrimaryDevice } from "@tastic/core";
77
+ import { useIsTouchPrimaryDevice, useRotation } from "@tastic/core";
74
78
  import { useContext, useState } from "react";
75
79
  import { Platform, ScrollView, StyleSheet as StyleSheet2, View as View2 } from "react-native";
76
80
  import { Icon as Icon2, Portal, Text as Text2 } from "react-native-paper";
@@ -78,8 +82,10 @@ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
78
82
  function SettingIcon({ source, color, containerColor }) {
79
83
  return /* @__PURE__ */ jsx2(View2, { style: [styles2.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx2(Icon2, { source, size: 18, color }) });
80
84
  }
81
- function BaseSettingsDialog({ visible, onDismiss, rotation = 0, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
85
+ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
82
86
  const { dark, colors } = useAutoPaperTheme2();
87
+ const ambientRotation = useRotation();
88
+ const rotation = rotationOverride ?? ambientRotation;
83
89
  const isTouchPrimary = useIsTouchPrimaryDevice();
84
90
  const { settings: hapticSettings, set: setHapticSettings } = useHapticSettings();
85
91
  const { settings: soundSettings, set: setSoundSettings } = useSoundSettings();
@@ -271,12 +277,15 @@ var styles2 = StyleSheet2.create({
271
277
  // src/BaseStatsScreen.tsx
272
278
  import { useAutoPaperTheme as useAutoPaperTheme3 } from "@rific/auto-paper";
273
279
  import { Button as Button2, IconButton } from "@rific/feedback-press";
280
+ import { useRotation as useRotation2 } from "@tastic/core";
274
281
  import { useState as useState2 } from "react";
275
282
  import { ScrollView as ScrollView2, StyleSheet as StyleSheet3, View as View3 } from "react-native";
276
283
  import { Icon as Icon3, Portal as Portal2, Text as Text3 } from "react-native-paper";
277
284
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
278
- function BaseStatsScreen({ rotation = 0, title = "Achievements", titleVariant = "headlineSmall", onBack, insets, onReset, resetLabel = "Reset All Stats", resetConfirmTitle = "Reset Everything?", resetConfirmBody = "This permanently erases all stats and achievements. This cannot be undone.", fg: fgOverride, bg: bgOverride, cardBg: cardBgOverride, accentColor: accentColorOverride, children }) {
285
+ function BaseStatsScreen({ rotation: rotationOverride, title = "Achievements", titleVariant = "headlineSmall", onBack, insets, onReset, resetLabel = "Reset All Stats", resetConfirmTitle = "Reset Everything?", resetConfirmBody = "This permanently erases all stats and achievements. This cannot be undone.", fg: fgOverride, bg: bgOverride, cardBg: cardBgOverride, accentColor: accentColorOverride, children }) {
279
286
  const { dark, colors } = useAutoPaperTheme3();
287
+ const ambientRotation = useRotation2();
288
+ const rotation = rotationOverride ?? ambientRotation;
280
289
  const [confirmResetVisible, setConfirmResetVisible] = useState2(false);
281
290
  const showReset = !!onReset;
282
291
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
@@ -369,20 +378,79 @@ var styles3 = StyleSheet3.create({
369
378
  }
370
379
  });
371
380
 
381
+ // src/ConfirmDialog.tsx
382
+ import { useAutoPaperTheme as useAutoPaperTheme4 } from "@rific/auto-paper";
383
+ import { Button as Button3 } from "@rific/feedback-press";
384
+ import { StyleSheet as StyleSheet4, View as View4 } from "react-native";
385
+ import { Icon as Icon4, Portal as Portal3, Text as Text4 } from "react-native-paper";
386
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
387
+ function ConfirmDialog({ visible, title, message, confirmLabel, cancelLabel, onConfirm, onCancel, rotation = 0, icon = "help-circle-outline", destructive = false }) {
388
+ const { dark, colors } = useAutoPaperTheme4();
389
+ if (!visible) return null;
390
+ const fg = dark ? "#FFFFFF" : "#000000";
391
+ const cardBg = dark ? "#111111" : "#F2F2F2";
392
+ const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
393
+ const accent = destructive ? colors.danger : colors.primary;
394
+ const onAccent = destructive ? colors.onDanger : colors.onPrimary;
395
+ 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: [
396
+ /* @__PURE__ */ jsx4(Icon4, { source: icon, size: 64, color: accent }),
397
+ /* @__PURE__ */ jsx4(Text4, { variant: "headlineLarge", style: [styles4.title, { color: accent }], children: title }),
398
+ /* @__PURE__ */ jsx4(Text4, { variant: "bodyLarge", style: [styles4.body, { color: fg }], children: message }),
399
+ /* @__PURE__ */ jsxs4(View4, { style: styles4.actions, children: [
400
+ /* @__PURE__ */ jsx4(Button3, { mode: "outlined", onPress: onCancel, style: styles4.actionButton, children: cancelLabel }),
401
+ /* @__PURE__ */ jsx4(Button3, { mode: "contained", onPress: onConfirm, style: styles4.actionButton, buttonColor: accent, textColor: onAccent, children: confirmLabel })
402
+ ] })
403
+ ] }) }) });
404
+ }
405
+ var styles4 = StyleSheet4.create({
406
+ actionButton: {
407
+ flex: 1
408
+ },
409
+ actions: {
410
+ flexDirection: "row",
411
+ gap: 12,
412
+ width: "100%"
413
+ },
414
+ body: {
415
+ textAlign: "center"
416
+ },
417
+ card: {
418
+ alignItems: "center",
419
+ borderRadius: 20,
420
+ borderWidth: 1,
421
+ gap: 16,
422
+ maxWidth: 360,
423
+ padding: 32
424
+ },
425
+ overlay: {
426
+ alignItems: "center",
427
+ backgroundColor: "rgba(0,0,0,0.72)",
428
+ bottom: 0,
429
+ justifyContent: "center",
430
+ left: 0,
431
+ position: "absolute",
432
+ right: 0,
433
+ top: 0
434
+ },
435
+ title: {
436
+ fontWeight: "bold"
437
+ }
438
+ });
439
+
372
440
  // src/ContentGutter.tsx
373
441
  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";
442
+ import { StyleSheet as StyleSheet5, useWindowDimensions, View as View5 } from "react-native";
443
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
376
444
  function ContentGutter({ maxContentWidth, leftGutter, rightGutter, style, children }) {
377
445
  const { width: windowWidth } = useWindowDimensions();
378
446
  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 })
447
+ return /* @__PURE__ */ jsxs5(View5, { style: [styles5.row, style], children: [
448
+ /* @__PURE__ */ jsx5(View5, { style: [styles5.gutter, { width: gutterWidth }], children: leftGutter }),
449
+ /* @__PURE__ */ jsx5(View5, { style: { width: contentWidth }, children }),
450
+ /* @__PURE__ */ jsx5(View5, { style: [styles5.gutter, { width: gutterWidth }], children: rightGutter })
383
451
  ] });
384
452
  }
385
- var styles4 = StyleSheet4.create({
453
+ var styles5 = StyleSheet5.create({
386
454
  // overflow:'hidden' keeps an oversized leftGutter/rightGutter from bleeding into the content
387
455
  // column instead of clipping cleanly at its own real width.
388
456
  gutter: {
@@ -393,39 +461,24 @@ var styles4 = StyleSheet4.create({
393
461
  }
394
462
  });
395
463
 
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
- });
464
+ // src/ControlSchemePicker.tsx
465
+ import { useIsTouchPrimaryDevice as useIsTouchPrimaryDevice2 } from "@tastic/core";
466
+ import { Platform as Platform3 } from "react-native";
467
+
468
+ // src/SectionedDropdown.tsx
469
+ import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
470
+ import { IconButton as IconButton2, TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
471
+ import { useRotation as useRotation3 } from "@tastic/core";
472
+ import { ScrollView as ScrollView3, StyleSheet as StyleSheet7, View as View8 } from "react-native";
473
+ import { Icon as Icon5, Text as Text5 } from "react-native-paper";
414
474
 
415
475
  // src/fonts.ts
416
476
  import { Platform as Platform2 } from "react-native";
417
477
  var MONO_FONT = Platform2.select({ ios: "Menlo", android: "monospace", default: "monospace" });
418
478
 
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
479
  // 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";
480
+ import { StyleSheet as StyleSheet6, View as View6 } from "react-native";
481
+ import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
429
482
  var CARET_SIZE = 7;
430
483
  var CARET_RING_OFFSET = 2;
431
484
  var CARET_DIP = 1;
@@ -439,11 +492,11 @@ function PopoverBody({ visible, children, align = "center", verticalAlign = "bel
439
492
  const caretFill = above ? "borderTopColor" : "borderBottomColor";
440
493
  const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
441
494
  const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
442
- return /* @__PURE__ */ jsxs6(View5, { style: [styles6.content, alignStyle, verticalStyle], children: [
495
+ return /* @__PURE__ */ jsxs6(View6, { style: [styles6.content, alignStyle, verticalStyle], children: [
443
496
  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 }] })
497
+ caretColor && /* @__PURE__ */ jsxs6(Fragment2, { children: [
498
+ /* @__PURE__ */ jsx6(View6, { style: [styles6.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
499
+ /* @__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
500
  ] })
448
501
  ] });
449
502
  }
@@ -489,11 +542,27 @@ var styles6 = StyleSheet6.create({
489
542
  }
490
543
  });
491
544
 
545
+ // src/TriggerGaugeHost.tsx
546
+ import { jsx as jsx7 } from "react/jsx-runtime";
547
+ var getTriggerGauge = () => import("./TriggerGauge-2OJOOF6I.mjs").then((mod) => ({ default: mod.TriggerGauge }));
548
+ function TriggerGaugeHost(props) {
549
+ return /* @__PURE__ */ jsx7(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
550
+ }
551
+
492
552
  // src/useAutoAlign.ts
493
553
  import { useCallback, useEffect, useRef, useState as useState3 } from "react";
494
554
  import { useWindowDimensions as useWindowDimensions2 } from "react-native";
495
555
  var EDGE_MARGIN = 12;
496
- function useAutoAlign(open, contentWidth, contentHeight) {
556
+ function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
557
+ if (rotation === 0) return { x, y, width, height };
558
+ const cx = windowWidth / 2;
559
+ const cy = windowHeight / 2;
560
+ const dx = x + width / 2 - cx;
561
+ const dy = y + height / 2 - cy;
562
+ const [newDx, newDy, newWidth, newHeight] = rotation === 180 ? [-dx, -dy, width, height] : rotation === 90 ? [-dy, dx, height, width] : [dy, -dx, height, width];
563
+ return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
564
+ }
565
+ function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
497
566
  const triggerRef = useRef(null);
498
567
  const { width: windowWidth, height: windowHeight } = useWindowDimensions2();
499
568
  const [align, setAlign] = useState3("center");
@@ -506,7 +575,8 @@ function useAutoAlign(open, contentWidth, contentHeight) {
506
575
  if (open) setMeasured(false);
507
576
  }
508
577
  const measure = useCallback(() => {
509
- triggerRef.current?.measureInWindow((x, y, triggerWidth, triggerHeight) => {
578
+ triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
579
+ const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
510
580
  const centerX = x + triggerWidth / 2;
511
581
  const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
512
582
  const overflowsLeft = centerX - contentWidth / 2 < EDGE_MARGIN;
@@ -520,15 +590,275 @@ function useAutoAlign(open, contentWidth, contentHeight) {
520
590
  setMaxHeight(Math.max(above ? roomAbove : roomBelow, 0));
521
591
  setMeasured(true);
522
592
  });
523
- }, [contentWidth, contentHeight, windowWidth, windowHeight]);
593
+ }, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
524
594
  useEffect(() => {
525
595
  if (open) measure();
526
596
  }, [open, measure]);
527
597
  return { align, maxHeight, measured, triggerRef, verticalAlign };
528
598
  }
529
599
 
600
+ // src/SectionedDropdown.tsx
601
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
602
+ var MENU_BORDER_WIDTH = 1;
603
+ var TRIGGER_SIZE = 44;
604
+ var MENU_MIN_WIDTH = 200;
605
+ var MENU_MAX_WIDTH = 220;
606
+ var MENU_ITEM_ICON_SIZE = 18;
607
+ var MENU_ITEM_LABEL_MAX_WIDTH = 150;
608
+ var MENU_ITEM_HEIGHT = 40;
609
+ var MENU_ITEM_HEIGHT_WITH_DESCRIPTION = 58;
610
+ var MENU_DIVIDER_HEIGHT = 9;
611
+ var MENU_VERTICAL_PADDING = 12;
612
+ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, rotation: rotationOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
613
+ const ambientRotation = useRotation3();
614
+ const rotation = rotationOverride ?? ambientRotation;
615
+ const menuBg = dark ? "#000000" : "#FFFFFF";
616
+ const menuBorderColor = getBlendedColor(mutedColor, menuBg, 0.5);
617
+ const resolvedOnAccentColor = onAccentColor ?? getColorRoles(accentColor, menuBg).onColor;
618
+ const fg = dark ? "#FFFFFF" : "#000000";
619
+ const open = host.openId === id;
620
+ const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
621
+ const rows = section.options.reduce((rowSum, option) => rowSum + (option.description ? MENU_ITEM_HEIGHT_WITH_DESCRIPTION : MENU_ITEM_HEIGHT), 0);
622
+ const footer = section.kind === "multi" && section.allClear ? MENU_ITEM_HEIGHT : 0;
623
+ const divider = sectionIndex > 0 ? MENU_DIVIDER_HEIGHT : 0;
624
+ return sum + rows + footer + divider;
625
+ }, 0);
626
+ const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, MENU_MAX_WIDTH, estimatedHeight, rotation);
627
+ const align = alignOverride ?? autoAlign;
628
+ const onlySection = sections.length === 1 ? sections[0] : null;
629
+ const selectedOption = onlySection?.kind === "single" ? onlySection.options.find((o) => o.value === onlySection.value) : void 0;
630
+ const triggerIcon = selectedOption?.icon ?? icon;
631
+ const triggerIconSize = selectedOption?.iconSize ?? 22;
632
+ const hasMultiSection = sections.some((s) => s.kind === "multi");
633
+ const anyMultiSelected = sections.some((s) => s.kind === "multi" && s.value.length > 0);
634
+ const triggerIconColor = hasMultiSection ? anyMultiSelected ? accentColor : fg : fg;
635
+ const gaugeSegments = sections.reduce((sum, section) => sum + section.options.length, 0);
636
+ const gaugeLitIndices = [];
637
+ let gaugeOffset = 0;
638
+ for (const section of sections) {
639
+ if (section.kind === "single") {
640
+ const index = section.options.findIndex((o) => o.value === section.value);
641
+ if (index >= 0) gaugeLitIndices.push(gaugeOffset + index);
642
+ } else {
643
+ section.options.forEach((o, i) => {
644
+ if (section.value.includes(o.value)) gaugeLitIndices.push(gaugeOffset + i);
645
+ });
646
+ }
647
+ gaugeOffset += section.options.length;
648
+ }
649
+ const anchorStyle = [styles7.anchor, open && styles7.anchorOpen];
650
+ const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
651
+ const dividerStyle = { backgroundColor: menuBorderColor };
652
+ return /* @__PURE__ */ jsxs7(View8, { style: anchorStyle, children: [
653
+ /* @__PURE__ */ jsxs7(View8, { ref: triggerRef, collapsable: false, style: styles7.triggerBox, children: [
654
+ /* @__PURE__ */ jsx8(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
655
+ /* @__PURE__ */ jsx8(IconButton2, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
656
+ ] }),
657
+ /* @__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: [
658
+ sectionIndex > 0 && /* @__PURE__ */ jsx8(View8, { style: [styles7.divider, dividerStyle] }),
659
+ section.kind === "single" ? /* @__PURE__ */ jsx8(
660
+ SingleSection,
661
+ {
662
+ section,
663
+ accentColor,
664
+ onAccentColor: resolvedOnAccentColor,
665
+ mutedColor,
666
+ labelFontFamily,
667
+ onSelect: (value) => {
668
+ section.onChange(value);
669
+ if (autoDismiss) host.close();
670
+ }
671
+ }
672
+ ) : /* @__PURE__ */ jsx8(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
673
+ ] }, section.id)) }) })
674
+ ] });
675
+ }
676
+ function SingleSection({
677
+ section,
678
+ accentColor,
679
+ onAccentColor,
680
+ mutedColor,
681
+ labelFontFamily,
682
+ onSelect
683
+ }) {
684
+ return /* @__PURE__ */ jsx8(Fragment3, { children: section.options.map((option) => {
685
+ const selected = option.value === section.value;
686
+ const taken = !selected && option.value === section.takenValue;
687
+ const rowColor = selected ? onAccentColor : mutedColor;
688
+ const itemStyle = [styles7.item, selected && { backgroundColor: accentColor }, taken && styles7.itemTaken];
689
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
690
+ const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
691
+ return /* @__PURE__ */ jsx8(TouchableRipple2, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs7(View8, { style: styles7.itemRow, children: [
692
+ option.icon && /* @__PURE__ */ jsx8(Icon5, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
693
+ /* @__PURE__ */ jsxs7(View8, { style: styles7.itemLabelColumn, children: [
694
+ /* @__PURE__ */ jsx8(Text5, { variant: "labelLarge", style: labelStyle, children: option.label }),
695
+ option.description && /* @__PURE__ */ jsx8(Text5, { variant: "labelSmall", style: descriptionStyle, children: option.description })
696
+ ] })
697
+ ] }) }, option.value);
698
+ }) });
699
+ }
700
+ function MultiSection({
701
+ section,
702
+ accentColor,
703
+ onAccentColor,
704
+ mutedColor,
705
+ labelFontFamily,
706
+ allClearLabels
707
+ }) {
708
+ const allSelected = section.value.length === section.options.length;
709
+ return /* @__PURE__ */ jsxs7(Fragment3, { children: [
710
+ section.options.map((option, i) => {
711
+ const selected = section.value.includes(option.value);
712
+ const rowColor = selected ? onAccentColor : mutedColor;
713
+ const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
714
+ const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
715
+ const itemStyle = [styles7.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
716
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
717
+ 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: [
718
+ option.icon && /* @__PURE__ */ jsx8(Icon5, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
719
+ /* @__PURE__ */ jsx8(Text5, { variant: "labelLarge", style: [styles7.itemLabelFlex, labelStyle], children: option.label })
720
+ ] }) }, option.value);
721
+ }),
722
+ 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 }) })
723
+ ] });
724
+ }
725
+ var styles7 = StyleSheet7.create({
726
+ allClearLabel: {
727
+ fontWeight: "bold",
728
+ textAlign: "center"
729
+ },
730
+ anchor: {
731
+ position: "relative"
732
+ },
733
+ // React Native Web gives every position:'relative' view an explicit zIndex (0, not 'auto'),
734
+ // which makes each one its own stacking context — so a zIndex set only on the popover content
735
+ // below only wins comparisons within this anchor's own box, not against this anchor's own later
736
+ // siblings (e.g. a Ready button), which are otherwise painted on top by DOM-order tiebreak.
737
+ // Elevating the anchor itself, only while its popover is open, fixes that at the right level.
738
+ anchorOpen: {
739
+ zIndex: 100
740
+ },
741
+ divider: {
742
+ height: StyleSheet7.hairlineWidth,
743
+ marginVertical: 4
744
+ },
745
+ item: {
746
+ borderRadius: 8,
747
+ paddingHorizontal: 12,
748
+ paddingVertical: 8
749
+ },
750
+ itemLabelColumn: {
751
+ maxWidth: MENU_ITEM_LABEL_MAX_WIDTH
752
+ },
753
+ itemLabelFlex: {
754
+ flex: 1
755
+ },
756
+ itemRow: {
757
+ alignItems: "center",
758
+ flexDirection: "row",
759
+ gap: 8
760
+ },
761
+ // Same opacity as ProfilePicker's rowDisabled / InlineColorPicker's swatchTaken — the fleet's
762
+ // established "shown, not removed" treatment for another seat's own current pick.
763
+ itemTaken: {
764
+ opacity: 0.35
765
+ },
766
+ menu: {
767
+ borderRadius: 12,
768
+ borderWidth: MENU_BORDER_WIDTH,
769
+ elevation: 8,
770
+ maxWidth: MENU_MAX_WIDTH,
771
+ minWidth: MENU_MIN_WIDTH,
772
+ shadowColor: "#000000",
773
+ shadowOffset: { height: 2, width: 0 },
774
+ shadowOpacity: 0.3,
775
+ shadowRadius: 8
776
+ },
777
+ // Separate from `menu` itself — a ScrollView's own style sets the scrolling frame's bounds
778
+ // (including the maxHeight that actually caps it), while padding/gap belong to its
779
+ // contentContainerStyle, which sizes to the *unclamped* content instead of the frame.
780
+ menuContent: {
781
+ gap: 4,
782
+ padding: 6
783
+ },
784
+ // Fixed hit-area regardless of the current option's iconSize, so a small-vs-large trigger icon
785
+ // doesn't shift this picker's position within its row.
786
+ triggerBox: {
787
+ alignItems: "center",
788
+ height: TRIGGER_SIZE,
789
+ justifyContent: "center",
790
+ width: TRIGGER_SIZE
791
+ }
792
+ });
793
+
794
+ // src/ControlSchemePicker.tsx
795
+ import { jsx as jsx9 } from "react/jsx-runtime";
796
+ function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, labelFontFamily }) {
797
+ const isTouchPrimary = useIsTouchPrimaryDevice2();
798
+ if (Platform3.OS !== "web" || isTouchPrimary) return null;
799
+ 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 });
800
+ }
801
+
802
+ // src/CornerActionButtons.tsx
803
+ import { IconButton as IconButton3 } from "@rific/feedback-press";
804
+ import { StyleSheet as StyleSheet8 } from "react-native";
805
+ import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
806
+ function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back" }) {
807
+ return /* @__PURE__ */ jsxs8(Fragment4, { children: [
808
+ /* @__PURE__ */ jsx10(IconButton3, { icon: backIcon, iconColor: fg, size: 24, style: [styles8.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: backLabel }),
809
+ /* @__PURE__ */ jsx10(IconButton3, { icon: "cog", iconColor: fg, size: 24, style: [styles8.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
810
+ ] });
811
+ }
812
+ var styles8 = StyleSheet8.create({
813
+ back: {
814
+ position: "absolute"
815
+ },
816
+ topRight: {
817
+ position: "absolute"
818
+ }
819
+ });
820
+
821
+ // src/CornerStatusBadges.tsx
822
+ import { StyleSheet as StyleSheet9, View as View9 } from "react-native";
823
+ import { Icon as Icon6 } from "react-native-paper";
824
+ import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
825
+ var BADGE_SIZE = 30;
826
+ function StatusBadge({ icon }) {
827
+ return /* @__PURE__ */ jsx11(View9, { style: styles9.badge, children: icon && /* @__PURE__ */ jsx11(Icon6, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
828
+ }
829
+ function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
830
+ const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
831
+ const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
832
+ return /* @__PURE__ */ jsxs9(Fragment5, { children: [
833
+ p1 && /* @__PURE__ */ jsx11(View9, { pointerEvents: "none", style: p1OnRightSide ? styles9.bottomRight : styles9.bottomLeft, children: /* @__PURE__ */ jsx11(StatusBadge, { icon: p1.icon }) }),
834
+ p2 && /* @__PURE__ */ jsx11(View9, { pointerEvents: "none", style: p2OnLeftSide ? styles9.topLeft : styles9.topRight, children: /* @__PURE__ */ jsx11(StatusBadge, { icon: p2.icon }) })
835
+ ] });
836
+ }
837
+ var styles9 = StyleSheet9.create({
838
+ badge: {
839
+ alignItems: "center",
840
+ backgroundColor: "rgba(0,0,0,0.28)",
841
+ borderColor: "rgba(255,255,255,0.18)",
842
+ borderRadius: BADGE_SIZE / 2,
843
+ borderWidth: 1,
844
+ height: BADGE_SIZE,
845
+ justifyContent: "center",
846
+ opacity: 0.7,
847
+ width: BADGE_SIZE
848
+ },
849
+ bottomLeft: { bottom: 12, left: 12, position: "absolute" },
850
+ bottomRight: { bottom: 12, position: "absolute", right: 12 },
851
+ topLeft: { left: 12, position: "absolute", top: 12 },
852
+ topRight: { position: "absolute", right: 12, top: 12 }
853
+ });
854
+
530
855
  // src/InlineColorPicker.tsx
531
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
856
+ import { defaultColors, getContrastColor } from "@rific/auto-paper";
857
+ import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
858
+ import { clamp, useRotation as useRotation4 } from "@tastic/core";
859
+ import { ScrollView as ScrollView4, StyleSheet as StyleSheet10, useWindowDimensions as useWindowDimensions3, View as View10 } from "react-native";
860
+ import { Icon as Icon7, Text as Text6 } from "react-native-paper";
861
+ import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
532
862
  var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
533
863
  var DEFAULT_SIZE = 48;
534
864
  var SWATCH_SIZE = 28;
@@ -541,7 +871,9 @@ var SCREEN_MARGIN = 40;
541
871
  function widthForColumns(columns) {
542
872
  return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
543
873
  }
544
- function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
874
+ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
875
+ const ambientRotation = useRotation4();
876
+ const rotation = rotationOverride ?? ambientRotation;
545
877
  const menuBg = dark ? "#000000" : "#FFFFFF";
546
878
  const { width: windowWidth } = useWindowDimensions3();
547
879
  const autoColumns = clamp(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
@@ -550,21 +882,21 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
550
882
  const swatchRows = Math.ceil(swatches.length / resolvedColumns);
551
883
  const swatchesHeight = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * swatchRows + SWATCHES_GAP * (swatchRows - 1);
552
884
  const open = host.openId === id;
553
- const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, swatchesWidth, swatchesHeight);
885
+ const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
554
886
  const align = alignOverride ?? autoAlign;
555
887
  const displayFor = previewValue ?? ((hex) => hex);
556
888
  const displayValue = displayFor(value);
557
889
  const contrastColor = getContrastColor(displayValue);
558
890
  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) => {
891
+ return /* @__PURE__ */ jsxs10(View10, { style: [styles10.anchor, open && styles10.anchorOpen], children: [
892
+ /* @__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 }) }) }),
893
+ /* @__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
894
  const selected = swatch.value.toLowerCase() === value.toLowerCase();
563
895
  const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
564
896
  const swappable = taken && allowSwapTaken;
565
897
  const swatchDisplay = displayFor(swatch.value);
566
- return /* @__PURE__ */ jsx7(
567
- TouchableRipple2,
898
+ return /* @__PURE__ */ jsx12(
899
+ TouchableRipple3,
568
900
  {
569
901
  disabled: taken && !swappable,
570
902
  onPress: () => {
@@ -572,15 +904,15 @@ function InlineColorPicker({ id, host, value, onChange, previewValue, swatches =
572
904
  if (autoDismiss) host.close();
573
905
  },
574
906
  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, {})
907
+ style: [styles10.swatch, { backgroundColor: swatchDisplay }, selected && styles10.swatchSelected, taken && !swappable && styles10.swatchTaken],
908
+ 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
909
  },
578
910
  swatch.value
579
911
  );
580
912
  }) }) })
581
913
  ] });
582
914
  }
583
- var styles7 = StyleSheet7.create({
915
+ var styles10 = StyleSheet10.create({
584
916
  anchor: {
585
917
  position: "relative"
586
918
  },
@@ -653,10 +985,10 @@ var styles7 = StyleSheet7.create({
653
985
 
654
986
  // src/LabeledDropdown.tsx
655
987
  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";
988
+ import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
989
+ import { ScrollView as ScrollView5, StyleSheet as StyleSheet11, View as View11 } from "react-native";
990
+ import { Icon as Icon8, Text as Text7 } from "react-native-paper";
991
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
660
992
  var TRIGGER_HEIGHT = 28;
661
993
  var POPOVER_WIDTH = 180;
662
994
  var ROW_HEIGHT = 36;
@@ -679,22 +1011,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
679
1011
  onChange(option.value);
680
1012
  host.close();
681
1013
  };
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 })
1014
+ return /* @__PURE__ */ jsxs11(View11, { style: [styles11.anchor, open && styles11.anchorOpen], children: [
1015
+ /* @__PURE__ */ jsx13(TouchableRipple4, { onPress: () => host.toggle(id), style: styles11.trigger, children: /* @__PURE__ */ jsxs11(View11, { ref: triggerRef, collapsable: false, style: styles11.triggerInner, children: [
1016
+ /* @__PURE__ */ jsx13(Text7, { style: [styles11.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
1017
+ /* @__PURE__ */ jsx13(Icon8, { source: "menu-down", size: 16, color })
686
1018
  ] }) }),
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) => {
1019
+ /* @__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
1020
  const isSelected = option.value === value;
689
1021
  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 })
1022
+ return /* @__PURE__ */ jsx13(TouchableRipple4, { onPress: () => handleSelect(option), style: [styles11.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs11(View11, { style: styles11.rowInner, children: [
1023
+ option.icon && /* @__PURE__ */ jsx13(Icon8, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
1024
+ /* @__PURE__ */ jsx13(Text7, { style: [styles11.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
693
1025
  ] }) }, option.value);
694
1026
  }) }) })
695
1027
  ] });
696
1028
  }
697
- var styles8 = StyleSheet8.create({
1029
+ var styles11 = StyleSheet11.create({
698
1030
  anchor: {
699
1031
  position: "relative"
700
1032
  },
@@ -752,25 +1084,25 @@ function loadSkiaWeb() {
752
1084
  }
753
1085
 
754
1086
  // src/PressAwayOverlay.tsx
755
- import { Pressable, StyleSheet as StyleSheet9 } from "react-native";
756
- import { jsx as jsx9 } from "react/jsx-runtime";
1087
+ import { Pressable, StyleSheet as StyleSheet12 } from "react-native";
1088
+ import { jsx as jsx14 } from "react/jsx-runtime";
757
1089
  function PressAwayOverlay({ active, onPress, style }) {
758
1090
  if (!active) return null;
759
- return /* @__PURE__ */ jsx9(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet9.absoluteFill, style] });
1091
+ return /* @__PURE__ */ jsx14(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet12.absoluteFill, style] });
760
1092
  }
761
1093
 
762
1094
  // 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";
1095
+ import { TouchableRipple as TouchableRipple5 } from "@rific/feedback-press";
1096
+ import { StyleSheet as StyleSheet13 } from "react-native";
1097
+ import { Text as Text8 } from "react-native-paper";
1098
+ import { jsx as jsx15 } from "react/jsx-runtime";
767
1099
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
768
- const readyButtonStyle = [styles9.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
1100
+ const readyButtonStyle = [styles12.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
769
1101
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
770
1102
  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?" }) });
1103
+ 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
1104
  }
773
- var styles9 = StyleSheet10.create({
1105
+ var styles12 = StyleSheet13.create({
774
1106
  readyButton: {
775
1107
  alignItems: "center",
776
1108
  borderRadius: 12,
@@ -782,228 +1114,22 @@ var styles9 = StyleSheet10.create({
782
1114
  }
783
1115
  });
784
1116
 
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
1117
  // src/SharedActionBand.tsx
992
1118
  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";
1119
+ import { StyleSheet as StyleSheet14, View as View12 } from "react-native";
1120
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
995
1121
  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" })
1122
+ return /* @__PURE__ */ jsxs12(View12, { style: [styles13.column, popoverOpen && styles13.columnOpen], children: [
1123
+ /* @__PURE__ */ jsxs12(View12, { style: styles13.actionsRow, children: [
1124
+ /* @__PURE__ */ jsx16(IconButton4, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
1125
+ onRandomize && /* @__PURE__ */ jsx16(IconButton4, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
1126
+ onReset && /* @__PURE__ */ jsx16(IconButton4, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
1127
+ /* @__PURE__ */ jsx16(IconButton4, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
1002
1128
  ] }),
1003
1129
  children
1004
1130
  ] });
1005
1131
  }
1006
- var styles11 = StyleSheet12.create({
1132
+ var styles13 = StyleSheet14.create({
1007
1133
  actionsRow: {
1008
1134
  alignItems: "center",
1009
1135
  flexDirection: "row",
@@ -1019,20 +1145,20 @@ var styles11 = StyleSheet12.create({
1019
1145
  });
1020
1146
 
1021
1147
  // 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";
1148
+ import { useAutoPaperTheme as useAutoPaperTheme5 } from "@rific/auto-paper";
1149
+ import { StyleSheet as StyleSheet15, View as View13 } from "react-native";
1150
+ import { Text as Text9 } from "react-native-paper";
1151
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1026
1152
  function StatRow({ label, value, fg: fgOverride, fgMuted: fgMutedOverride }) {
1027
- const { dark } = useAutoPaperTheme4();
1153
+ const { dark } = useAutoPaperTheme5();
1028
1154
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1029
1155
  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 })
1156
+ return /* @__PURE__ */ jsxs13(View13, { style: styles14.row, children: [
1157
+ /* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: { color: fgMuted }, children: label }),
1158
+ /* @__PURE__ */ jsx17(Text9, { variant: "bodyMedium", style: [styles14.value, { color: fg }], children: value })
1033
1159
  ] });
1034
1160
  }
1035
- var styles12 = StyleSheet13.create({
1161
+ var styles14 = StyleSheet15.create({
1036
1162
  row: {
1037
1163
  alignItems: "center",
1038
1164
  flexDirection: "row",
@@ -1044,20 +1170,20 @@ var styles12 = StyleSheet13.create({
1044
1170
  });
1045
1171
 
1046
1172
  // 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";
1173
+ import { useAutoPaperTheme as useAutoPaperTheme6 } from "@rific/auto-paper";
1174
+ import { StyleSheet as StyleSheet16, View as View14 } from "react-native";
1175
+ import { Text as Text10 } from "react-native-paper";
1176
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1051
1177
  function StatSection({ label, fg: fgOverride, sectionBg: sectionBgOverride, children }) {
1052
- const { dark } = useAutoPaperTheme5();
1178
+ const { dark } = useAutoPaperTheme6();
1053
1179
  const fg = fgOverride ?? (dark ? "#FFFFFF" : "#000000");
1054
1180
  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 }),
1181
+ return /* @__PURE__ */ jsxs14(View14, { style: [styles15.section, { backgroundColor: sectionBg }], children: [
1182
+ /* @__PURE__ */ jsx18(Text10, { variant: "labelMedium", style: [styles15.label, { color: fg }], children: label }),
1057
1183
  children
1058
1184
  ] });
1059
1185
  }
1060
- var styles13 = StyleSheet14.create({
1186
+ var styles15 = StyleSheet16.create({
1061
1187
  // Bold and full-contrast (fg), not the original fontless/fgMuted treatment — that read at the
1062
1188
  // same visual weight as StatRow's own row labels below it (both used the identical muted color;
1063
1189
  // letterSpacing/variant alone didn't separate them enough to read as "this is the group header"
@@ -1087,8 +1213,11 @@ export {
1087
1213
  AchievementRow,
1088
1214
  BaseSettingsDialog,
1089
1215
  BaseStatsScreen,
1216
+ ConfirmDialog,
1090
1217
  ContentGutter,
1218
+ ControlSchemePicker,
1091
1219
  CornerActionButtons,
1220
+ CornerStatusBadges,
1092
1221
  InlineColorPicker,
1093
1222
  LABELED_DROPDOWN_POPOVER_WIDTH,
1094
1223
  LOCKED_BADGE_COLOR,
@@ -1099,6 +1228,7 @@ export {
1099
1228
  ReadyButton,
1100
1229
  SectionedDropdown,
1101
1230
  SharedActionBand,
1231
+ SkiaGate,
1102
1232
  StatRow,
1103
1233
  StatSection,
1104
1234
  TriggerGaugeHost,