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