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