@tastic/hud 0.22.0 → 0.23.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/README.md +26 -14
- package/dist/chrome/index.d.mts +87 -18
- package/dist/chrome/index.d.ts +87 -18
- package/dist/chrome/index.js +309 -22
- package/dist/chrome/index.mjs +13 -1
- package/dist/{chunk-N7A7W72S.mjs → chunk-BXG44LIA.mjs} +298 -19
- package/dist/index.d.mts +12 -81
- package/dist/index.d.ts +12 -81
- package/dist/index.js +27 -24
- package/dist/index.mjs +100 -364
- package/package.json +3 -2
- package/src/BaseSettingsDialog.tsx +13 -13
- package/src/chrome/index.ts +12 -4
|
@@ -281,6 +281,7 @@ var styles6 = StyleSheet6.create({
|
|
|
281
281
|
|
|
282
282
|
// src/BaseSettingsDialog.tsx
|
|
283
283
|
import { AutoAppearancePicker, Dialog, FadingScrollView, useAutoPaperTheme as useAutoPaperTheme4, useBlurModule, useThemeSettings } from "@rific/auto-paper";
|
|
284
|
+
import { useExpoKeepAwake, useKeepAwakeSettings } from "@rific/core";
|
|
284
285
|
import { Button as Button2, SoundContext, TouchableRipple, useHapticSettings, useSoundSettings, useVibration } from "@rific/feedback-press";
|
|
285
286
|
import { useUpdater } from "@rific/updater";
|
|
286
287
|
import { rotateInsets as rotateInsets2, useIsTouchPrimaryDevice, useRotation as useRotation2 } from "@tastic/core";
|
|
@@ -314,7 +315,7 @@ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
314
315
|
function SettingIcon({ source, color, containerColor }) {
|
|
315
316
|
return /* @__PURE__ */ jsx8(View6, { style: [styles7.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ jsx8(Icon2, { source, size: 18, color }) });
|
|
316
317
|
}
|
|
317
|
-
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures,
|
|
318
|
+
function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, onShowHowToPlay, children }) {
|
|
318
319
|
const { colors } = useAutoPaperTheme4();
|
|
319
320
|
const ambientRotation = useRotation2();
|
|
320
321
|
const rotation = rotationOverride ?? ambientRotation;
|
|
@@ -326,6 +327,8 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
326
327
|
const isTouchPrimary = useIsTouchPrimaryDevice();
|
|
327
328
|
const { settings: hapticSettings, set: setHapticSettings } = useHapticSettings();
|
|
328
329
|
const { settings: soundSettings, set: setSoundSettings } = useSoundSettings();
|
|
330
|
+
const { settings: keepAwakeSettings, set: setKeepAwakeSettings } = useKeepAwakeSettings();
|
|
331
|
+
const expoKeepAwake = useExpoKeepAwake();
|
|
329
332
|
const sound = useContext(SoundContext);
|
|
330
333
|
const { forceShort: forceHapticFeedback } = useVibration();
|
|
331
334
|
const { settings: themeSettings, set: setThemeSettings } = useThemeSettings();
|
|
@@ -344,7 +347,7 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
344
347
|
if (visible && !opened) setOpened(true);
|
|
345
348
|
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
346
349
|
const showEdgeGuard = Platform2.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
347
|
-
const showKeepAwake = isTouchPrimary &&
|
|
350
|
+
const showKeepAwake = isTouchPrimary && expoKeepAwake !== void 0;
|
|
348
351
|
const showHaptics = Platform2.OS !== "web" && !hideHaptics;
|
|
349
352
|
const showSound = !hideSound;
|
|
350
353
|
const showAppearance = !hideAppearance;
|
|
@@ -371,8 +374,8 @@ function BaseSettingsDialog({ visible, onDismiss, rotation: rotationOverride, ve
|
|
|
371
374
|
/* @__PURE__ */ jsx8(Text6, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Require second swipe" })
|
|
372
375
|
] })
|
|
373
376
|
] }) }),
|
|
374
|
-
showKeepAwake && /* @__PURE__ */ jsx8(TouchableRipple, { onPress: () =>
|
|
375
|
-
/* @__PURE__ */ jsx8(SettingIcon, { source:
|
|
377
|
+
showKeepAwake && /* @__PURE__ */ jsx8(TouchableRipple, { onPress: () => setKeepAwakeSettings({ enabled: !keepAwakeSettings.enabled }), style: styles7.toggleButton, accessibilityLabel: `Keep awake ${keepAwakeSettings.enabled ? "on" : "off"}`, children: /* @__PURE__ */ jsxs7(View6, { style: styles7.toggleContent, children: [
|
|
378
|
+
/* @__PURE__ */ jsx8(SettingIcon, { source: keepAwakeSettings.enabled ? "eye" : "eye-closed", color: keepAwakeSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: keepAwakeSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
376
379
|
/* @__PURE__ */ jsxs7(View6, { style: styles7.flexShrink, children: [
|
|
377
380
|
/* @__PURE__ */ jsx8(Text6, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Keep Awake" }),
|
|
378
381
|
/* @__PURE__ */ jsx8(Text6, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Stop auto-lock mid-match" })
|
|
@@ -644,17 +647,131 @@ var styles9 = StyleSheet9.create({
|
|
|
644
647
|
}
|
|
645
648
|
});
|
|
646
649
|
|
|
650
|
+
// src/PopoverBody.tsx
|
|
651
|
+
import { StyleSheet as StyleSheet10, View as View9 } from "react-native";
|
|
652
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
653
|
+
var CARET_SIZE = 7;
|
|
654
|
+
var CARET_RING_OFFSET = 2;
|
|
655
|
+
var CARET_DIP = 1;
|
|
656
|
+
function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
|
|
657
|
+
if (!visible) return null;
|
|
658
|
+
const above = verticalAlign === "above";
|
|
659
|
+
const alignStyle = align === "left" ? styles10.contentLeft : align === "right" ? styles10.contentRight : styles10.contentCenter;
|
|
660
|
+
const verticalStyle = above ? styles10.contentAbove : styles10.contentBelow;
|
|
661
|
+
const ringSize = CARET_SIZE + caretBorderWidth;
|
|
662
|
+
const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
|
|
663
|
+
const caretFill = above ? "borderTopColor" : "borderBottomColor";
|
|
664
|
+
const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
|
|
665
|
+
const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
|
|
666
|
+
return /* @__PURE__ */ jsxs10(View9, { style: [styles10.content, alignStyle, verticalStyle], children: [
|
|
667
|
+
children,
|
|
668
|
+
caretColor && /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
669
|
+
/* @__PURE__ */ jsx11(View9, { style: [styles10.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
|
|
670
|
+
/* @__PURE__ */ jsx11(View9, { style: [styles10.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
|
|
671
|
+
] })
|
|
672
|
+
] });
|
|
673
|
+
}
|
|
674
|
+
var styles10 = StyleSheet10.create({
|
|
675
|
+
caret: {
|
|
676
|
+
borderLeftColor: "transparent",
|
|
677
|
+
borderRightColor: "transparent",
|
|
678
|
+
height: 0,
|
|
679
|
+
position: "absolute",
|
|
680
|
+
width: 0,
|
|
681
|
+
// Explicit, not left to DOM order - the box it dips into is itself a position:'relative' view,
|
|
682
|
+
// which React Native Web always gives an implicit zIndex:0 (see PopoverBody's stacking-context
|
|
683
|
+
// notes elsewhere in this codebase), so painting on top needs a real zIndex to beat that
|
|
684
|
+
// reliably rather than relying on being the later sibling.
|
|
685
|
+
zIndex: 1
|
|
686
|
+
},
|
|
687
|
+
content: {
|
|
688
|
+
position: "absolute",
|
|
689
|
+
zIndex: 50
|
|
690
|
+
},
|
|
691
|
+
contentAbove: {
|
|
692
|
+
bottom: "100%",
|
|
693
|
+
marginBottom: 8
|
|
694
|
+
},
|
|
695
|
+
contentBelow: {
|
|
696
|
+
marginTop: 8,
|
|
697
|
+
top: "100%"
|
|
698
|
+
},
|
|
699
|
+
// Stretched to the anchor's own (trigger) width, with alignItems centering the actual (usually
|
|
700
|
+
// much wider) popover box inside via plain flexbox - not `left:'50%'` plus a percentage
|
|
701
|
+
// `transform`, which depends on native resolving the box's own auto width before applying the
|
|
702
|
+
// transform and has proven unreliable there, visibly shifting the box off-center.
|
|
703
|
+
contentCenter: {
|
|
704
|
+
alignItems: "center",
|
|
705
|
+
left: 0,
|
|
706
|
+
right: 0
|
|
707
|
+
},
|
|
708
|
+
contentLeft: {
|
|
709
|
+
left: 0
|
|
710
|
+
},
|
|
711
|
+
contentRight: {
|
|
712
|
+
right: 0
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
// src/useAutoAlign.ts
|
|
717
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useRef as useRef3, useState as useState5 } from "react";
|
|
718
|
+
import { useWindowDimensions as useWindowDimensions4 } from "react-native";
|
|
719
|
+
var EDGE_MARGIN = 12;
|
|
720
|
+
function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
|
|
721
|
+
if (rotation === 0) return { x, y, width, height };
|
|
722
|
+
const cx = windowWidth / 2;
|
|
723
|
+
const cy = windowHeight / 2;
|
|
724
|
+
const dx = x + width / 2 - cx;
|
|
725
|
+
const dy = y + height / 2 - cy;
|
|
726
|
+
const [newDx, newDy, newWidth, newHeight] = rotation === 180 ? [-dx, -dy, width, height] : rotation === 90 ? [-dy, dx, height, width] : [dy, -dx, height, width];
|
|
727
|
+
return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
|
|
728
|
+
}
|
|
729
|
+
function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
|
|
730
|
+
const triggerRef = useRef3(null);
|
|
731
|
+
const { width: windowWidth, height: windowHeight } = useWindowDimensions4();
|
|
732
|
+
const [align, setAlign] = useState5("center");
|
|
733
|
+
const [verticalAlign, setVerticalAlign] = useState5("below");
|
|
734
|
+
const [maxHeight, setMaxHeight] = useState5(contentHeight);
|
|
735
|
+
const [measured, setMeasured] = useState5(false);
|
|
736
|
+
const [prevOpen, setPrevOpen] = useState5(open);
|
|
737
|
+
if (open !== prevOpen) {
|
|
738
|
+
setPrevOpen(open);
|
|
739
|
+
if (open) setMeasured(false);
|
|
740
|
+
}
|
|
741
|
+
const measure = useCallback3(() => {
|
|
742
|
+
triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
|
|
743
|
+
const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
|
|
744
|
+
const centerX = x + triggerWidth / 2;
|
|
745
|
+
const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
|
|
746
|
+
const overflowsLeft = centerX - contentWidth / 2 < EDGE_MARGIN;
|
|
747
|
+
if (overflowsRight && !overflowsLeft) setAlign("right");
|
|
748
|
+
else if (overflowsLeft && !overflowsRight) setAlign("left");
|
|
749
|
+
else setAlign("center");
|
|
750
|
+
const roomBelow = windowHeight - (y + triggerHeight) - EDGE_MARGIN;
|
|
751
|
+
const roomAbove = y - EDGE_MARGIN;
|
|
752
|
+
const above = contentHeight > roomBelow && roomAbove > roomBelow;
|
|
753
|
+
setVerticalAlign(above ? "above" : "below");
|
|
754
|
+
setMaxHeight(Math.max(above ? roomAbove : roomBelow, 0));
|
|
755
|
+
setMeasured(true);
|
|
756
|
+
});
|
|
757
|
+
}, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
|
|
758
|
+
useEffect2(() => {
|
|
759
|
+
if (open) measure();
|
|
760
|
+
}, [open, measure]);
|
|
761
|
+
return { align, maxHeight, measured, triggerRef, verticalAlign };
|
|
762
|
+
}
|
|
763
|
+
|
|
647
764
|
// src/CornerActionButtons.tsx
|
|
648
765
|
import { IconButton as IconButton2 } from "@rific/feedback-press";
|
|
649
|
-
import { StyleSheet as
|
|
650
|
-
import { Fragment as
|
|
766
|
+
import { StyleSheet as StyleSheet11 } from "react-native";
|
|
767
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
651
768
|
function CornerActionButtons({ onBack, onSettings, fg, insets, backIcon = "arrow-left", backLabel = "Back", hitSlop }) {
|
|
652
|
-
return /* @__PURE__ */
|
|
653
|
-
/* @__PURE__ */
|
|
654
|
-
/* @__PURE__ */
|
|
769
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
770
|
+
/* @__PURE__ */ jsx12(IconButton2, { icon: backIcon, iconColor: fg, size: 24, style: [styles11.back, { top: 8 + insets.top, left: 8 + insets.left }], hitSlop, onPress: onBack, accessibilityLabel: backLabel }),
|
|
771
|
+
/* @__PURE__ */ jsx12(IconButton2, { icon: "cog", iconColor: fg, size: 24, style: [styles11.topRight, { top: 8 + insets.top, right: 8 + insets.right }], hitSlop, onPress: onSettings, accessibilityLabel: "Settings" })
|
|
655
772
|
] });
|
|
656
773
|
}
|
|
657
|
-
var
|
|
774
|
+
var styles11 = StyleSheet11.create({
|
|
658
775
|
back: {
|
|
659
776
|
position: "absolute"
|
|
660
777
|
},
|
|
@@ -663,11 +780,167 @@ var styles10 = StyleSheet10.create({
|
|
|
663
780
|
}
|
|
664
781
|
});
|
|
665
782
|
|
|
783
|
+
// src/InlineColorPicker.tsx
|
|
784
|
+
import { defaultColors, getContrastColor } from "@rific/auto-paper";
|
|
785
|
+
import { TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
|
|
786
|
+
import { clamp, useRotation as useRotation4 } from "@tastic/core";
|
|
787
|
+
import { ScrollView, StyleSheet as StyleSheet12, useWindowDimensions as useWindowDimensions5, View as View11 } from "react-native";
|
|
788
|
+
import { Icon as Icon3, Text as Text8 } from "react-native-paper";
|
|
789
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
790
|
+
var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
|
|
791
|
+
var DEFAULT_SIZE = 48;
|
|
792
|
+
var SWATCH_SIZE = 28;
|
|
793
|
+
var SWATCHES_PADDING = 8;
|
|
794
|
+
var SWATCHES_GAP = 6;
|
|
795
|
+
var SWATCHES_BORDER_WIDTH = 2;
|
|
796
|
+
var MIN_COLUMNS = 4;
|
|
797
|
+
var MAX_COLUMNS = 5;
|
|
798
|
+
var SCREEN_MARGIN = 40;
|
|
799
|
+
function widthForColumns(columns) {
|
|
800
|
+
return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
|
|
801
|
+
}
|
|
802
|
+
function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
|
|
803
|
+
const autoColumns = clamp(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
|
|
804
|
+
const resolvedColumns = columns ?? autoColumns;
|
|
805
|
+
const width = widthForColumns(resolvedColumns);
|
|
806
|
+
const rows = Math.ceil(swatchCount / resolvedColumns);
|
|
807
|
+
const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
|
|
808
|
+
return { width, height };
|
|
809
|
+
}
|
|
810
|
+
function InlineColorPicker({ id, host, value, onChange, previewValue, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
|
|
811
|
+
const ambientRotation = useRotation4();
|
|
812
|
+
const rotation = rotationOverride ?? ambientRotation;
|
|
813
|
+
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
814
|
+
const { width: windowWidth } = useWindowDimensions5();
|
|
815
|
+
const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
|
|
816
|
+
const open = host.openId === id;
|
|
817
|
+
const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
|
|
818
|
+
const placement = alignOverride ?? auto;
|
|
819
|
+
const { maxHeight, measured, triggerRef, verticalAlign } = placement;
|
|
820
|
+
const align = forcedAlign ?? placement.align;
|
|
821
|
+
const displayFor = previewValue ?? ((hex) => hex);
|
|
822
|
+
const displayValue = displayFor(value);
|
|
823
|
+
const contrastColor = getContrastColor(displayValue);
|
|
824
|
+
const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
|
|
825
|
+
return /* @__PURE__ */ jsxs12(View11, { style: [styles12.anchor, open && styles12.anchorOpen], children: [
|
|
826
|
+
/* @__PURE__ */ jsx13(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles12.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx13(View11, { ref: triggerRef, collapsable: false, style: styles12.triggerMeasure, children: tag ? /* @__PURE__ */ jsx13(Text8, { style: [styles12.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx13(Icon3, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
|
|
827
|
+
/* @__PURE__ */ jsx13(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx13(ScrollView, { style: [styles12.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles12.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
|
|
828
|
+
const selected = swatch.value.toLowerCase() === value.toLowerCase();
|
|
829
|
+
const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
|
|
830
|
+
const swappable = taken && allowSwapTaken;
|
|
831
|
+
const swatchDisplay = displayFor(swatch.value);
|
|
832
|
+
return /* @__PURE__ */ jsx13(
|
|
833
|
+
TouchableRipple2,
|
|
834
|
+
{
|
|
835
|
+
disabled: taken && !swappable,
|
|
836
|
+
onPress: () => {
|
|
837
|
+
onChange(swatch.value);
|
|
838
|
+
if (autoDismiss) host.close();
|
|
839
|
+
},
|
|
840
|
+
borderless: true,
|
|
841
|
+
style: [styles12.swatch, { backgroundColor: swatchDisplay }, selected && styles12.swatchSelected, taken && !swappable && styles12.swatchTaken],
|
|
842
|
+
children: selected ? /* @__PURE__ */ jsx13(Icon3, { source: "check", size: 16, color: getContrastColor(swatchDisplay) }) : swappable ? /* @__PURE__ */ jsx13(Icon3, { source: "swap-horizontal", size: 16, color: getContrastColor(swatchDisplay) }) : taken ? /* @__PURE__ */ jsx13(Icon3, { source: "close", size: 16, color: getContrastColor(swatchDisplay) }) : /* @__PURE__ */ jsx13(View11, {})
|
|
843
|
+
},
|
|
844
|
+
swatch.value
|
|
845
|
+
);
|
|
846
|
+
}) }) })
|
|
847
|
+
] });
|
|
848
|
+
}
|
|
849
|
+
var styles12 = StyleSheet12.create({
|
|
850
|
+
anchor: {
|
|
851
|
+
position: "relative"
|
|
852
|
+
},
|
|
853
|
+
// See SectionedDropdown's identical comment - React Native Web gives every position:'relative' view
|
|
854
|
+
// its own stacking context, so the elevation has to live on the anchor itself, not just the
|
|
855
|
+
// popover content nested inside it, to correctly paint above this anchor's own later siblings.
|
|
856
|
+
anchorOpen: {
|
|
857
|
+
zIndex: 100
|
|
858
|
+
},
|
|
859
|
+
swatch: {
|
|
860
|
+
alignItems: "center",
|
|
861
|
+
borderRadius: SWATCH_SIZE / 2,
|
|
862
|
+
height: SWATCH_SIZE,
|
|
863
|
+
justifyContent: "center",
|
|
864
|
+
width: SWATCH_SIZE
|
|
865
|
+
},
|
|
866
|
+
swatchSelected: {
|
|
867
|
+
borderColor: "#ffffff",
|
|
868
|
+
borderWidth: 2
|
|
869
|
+
},
|
|
870
|
+
swatchTaken: {
|
|
871
|
+
opacity: 0.35
|
|
872
|
+
},
|
|
873
|
+
swatches: {
|
|
874
|
+
borderRadius: 12,
|
|
875
|
+
borderWidth: SWATCHES_BORDER_WIDTH,
|
|
876
|
+
elevation: 8,
|
|
877
|
+
shadowColor: "#000000",
|
|
878
|
+
shadowOffset: { height: 2, width: 0 },
|
|
879
|
+
shadowOpacity: 0.3,
|
|
880
|
+
shadowRadius: 8
|
|
881
|
+
// width is set inline above - border-box sizing means it has to include the border too
|
|
882
|
+
// (2*SWATCHES_BORDER_WIDTH), not just padding+content, or exactly enough room goes missing that
|
|
883
|
+
// the last column silently wraps to a new row. Anything wider than the exact sum just shows as
|
|
884
|
+
// dead space on the right edge of each row instead.
|
|
885
|
+
},
|
|
886
|
+
// Separate from `swatches` itself - see SectionedDropdown's identical menu/menuContent split.
|
|
887
|
+
// The scroll frame's own bounds (including maxHeight) live on the ScrollView; the actual grid
|
|
888
|
+
// wrapping belongs to its contentContainerStyle, which sizes to the unclamped content instead.
|
|
889
|
+
swatchesContent: {
|
|
890
|
+
flexDirection: "row",
|
|
891
|
+
flexWrap: "wrap",
|
|
892
|
+
gap: SWATCHES_GAP,
|
|
893
|
+
padding: SWATCHES_PADDING
|
|
894
|
+
},
|
|
895
|
+
tagLabel: {
|
|
896
|
+
fontWeight: "700",
|
|
897
|
+
letterSpacing: 0.5
|
|
898
|
+
},
|
|
899
|
+
// borderRadius/height/width come from the `size` prop instead (see render-site override) - no
|
|
900
|
+
// fixed default here, since this style object is shared by every caller regardless of size.
|
|
901
|
+
trigger: {
|
|
902
|
+
alignItems: "center",
|
|
903
|
+
alignSelf: "flex-start",
|
|
904
|
+
justifyContent: "center"
|
|
905
|
+
},
|
|
906
|
+
// Wraps just the icon/tag, inside the TouchableRipple, purely so useAutoAlign has a plain View
|
|
907
|
+
// to attach its measurement ref to - TouchableRipple itself doesn't forward a ref to a
|
|
908
|
+
// measurable native node. Padded horizontally so a multi-character tag doesn't butt right up
|
|
909
|
+
// against the trigger's own circular edge (an icon alone doesn't need it, but this style is
|
|
910
|
+
// shared by both).
|
|
911
|
+
triggerMeasure: {
|
|
912
|
+
alignItems: "center",
|
|
913
|
+
height: "100%",
|
|
914
|
+
justifyContent: "center",
|
|
915
|
+
paddingHorizontal: 4,
|
|
916
|
+
width: "100%"
|
|
917
|
+
}
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
// src/usePopoverHost.ts
|
|
921
|
+
import { useCallback as useCallback4, useState as useState6 } from "react";
|
|
922
|
+
function usePopoverHost() {
|
|
923
|
+
const [openId, setOpenId] = useState6(null);
|
|
924
|
+
const toggle = useCallback4((id) => {
|
|
925
|
+
setOpenId((prev) => prev === id ? null : id);
|
|
926
|
+
}, []);
|
|
927
|
+
const close = useCallback4(() => setOpenId(null), []);
|
|
928
|
+
return { openId, toggle, close };
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// src/PressAwayOverlay.tsx
|
|
932
|
+
import { Pressable, StyleSheet as StyleSheet13 } from "react-native";
|
|
933
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
934
|
+
function PressAwayOverlay({ active, onPress, style }) {
|
|
935
|
+
if (!active) return null;
|
|
936
|
+
return /* @__PURE__ */ jsx14(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet13.absoluteFill, style] });
|
|
937
|
+
}
|
|
938
|
+
|
|
666
939
|
// src/StaggeredWord.tsx
|
|
667
|
-
import { useEffect as
|
|
668
|
-
import { StyleSheet as
|
|
940
|
+
import { useEffect as useEffect3 } from "react";
|
|
941
|
+
import { StyleSheet as StyleSheet14, View as View12 } from "react-native";
|
|
669
942
|
import Animated, { Easing, useAnimatedStyle, useSharedValue, withDelay, withTiming } from "react-native-reanimated";
|
|
670
|
-
import { jsx as
|
|
943
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
671
944
|
var STAGGER_MS = 45;
|
|
672
945
|
var LETTER_DURATION_MS = 320;
|
|
673
946
|
function getStaggeredWordDuration(letterCount) {
|
|
@@ -675,7 +948,7 @@ function getStaggeredWordDuration(letterCount) {
|
|
|
675
948
|
}
|
|
676
949
|
function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }) {
|
|
677
950
|
const progress = useSharedValue(reducedMotion ? 1 : 0);
|
|
678
|
-
|
|
951
|
+
useEffect3(() => {
|
|
679
952
|
if (reducedMotion) return;
|
|
680
953
|
progress.value = withDelay(index * STAGGER_MS, withTiming(1, { duration: LETTER_DURATION_MS, easing: Easing.out(Easing.back(1.5)) }));
|
|
681
954
|
}, [reducedMotion]);
|
|
@@ -683,12 +956,12 @@ function AnimatedLetter({ char, index, color, reducedMotion, fontFamily, fontSiz
|
|
|
683
956
|
opacity: progress.value,
|
|
684
957
|
transform: [{ translateY: (1 - progress.value) * 12 }, { scale: 0.85 + progress.value * 0.15 }]
|
|
685
958
|
}));
|
|
686
|
-
return /* @__PURE__ */
|
|
959
|
+
return /* @__PURE__ */ jsx15(Animated.Text, { allowFontScaling: false, style: [{ color, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, style], children: char });
|
|
687
960
|
}
|
|
688
961
|
function StaggeredWord({ word, color, fontFamily, fontSize, lineHeight, reducedMotion, startIndex = 0, fontWeight = "bold", letterSpacing, style, onLayout }) {
|
|
689
|
-
return /* @__PURE__ */
|
|
962
|
+
return /* @__PURE__ */ jsx15(View12, { style: [styles13.row, style], onLayout, children: word.split("").map((char, i) => /* @__PURE__ */ jsx15(AnimatedLetter, { char, index: startIndex + i, color, reducedMotion, fontFamily, fontSize, lineHeight, fontWeight, letterSpacing }, i)) });
|
|
690
963
|
}
|
|
691
|
-
var
|
|
964
|
+
var styles13 = StyleSheet14.create({
|
|
692
965
|
row: {
|
|
693
966
|
flexDirection: "row"
|
|
694
967
|
}
|
|
@@ -696,12 +969,12 @@ var styles11 = StyleSheet11.create({
|
|
|
696
969
|
|
|
697
970
|
// src/UpdateDialog.tsx
|
|
698
971
|
import { useUpdater as useUpdater2 } from "@rific/updater";
|
|
699
|
-
import { jsx as
|
|
972
|
+
import { jsx as jsx16 } from "react/jsx-runtime";
|
|
700
973
|
function UpdateDialog({ rotation = 0, autoCheck = true, autoPrompt = true, onError }) {
|
|
701
974
|
const { manifest, onConfirm, respond } = useUpdateConfirmBridge();
|
|
702
975
|
useUpdater2({ autoCheck, autoPrompt, onConfirm, onError });
|
|
703
976
|
const date = manifest ? new Date(manifest.createdAt) : null;
|
|
704
|
-
return /* @__PURE__ */
|
|
977
|
+
return /* @__PURE__ */ jsx16(ConfirmDialog, { visible: !!manifest, title: "Update Available", message: date ? `Released ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}` : "", confirmLabel: "Restart", cancelLabel: "Later", icon: "update", rotation, onConfirm: () => respond(true), onCancel: () => respond(false) });
|
|
705
978
|
}
|
|
706
979
|
|
|
707
980
|
export {
|
|
@@ -720,7 +993,13 @@ export {
|
|
|
720
993
|
BaseSettingsDialog,
|
|
721
994
|
BaseStatsScreen,
|
|
722
995
|
ContentGutter,
|
|
996
|
+
PopoverBody,
|
|
997
|
+
useAutoAlign,
|
|
723
998
|
CornerActionButtons,
|
|
999
|
+
getInlineColorPickerContentSize,
|
|
1000
|
+
InlineColorPicker,
|
|
1001
|
+
usePopoverHost,
|
|
1002
|
+
PressAwayOverlay,
|
|
724
1003
|
getStaggeredWordDuration,
|
|
725
1004
|
StaggeredWord,
|
|
726
1005
|
UpdateDialog
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
import { PopoverHost, AlignResult, PopoverRotation, useAutoAlign } from './chrome/index.mjs';
|
|
2
|
+
export { AchievementCatalogSection, AchievementRow, ActivityStatSection, BaseSettingsDialog, BaseSettingsDialogProps, BaseStatsScreen, COMPACT_DIALOG_HEIGHT, ConfirmDialog, ConfirmDialogProps, ContentGutter, CornerActionButtons, DialogHeader, DialogHeaderProps, InlineColorPicker, LOCKED_BADGE_COLOR, MONO_FONT, OverlayBackdrop, OverlayBackdropProps, OverlayCard, OverlayCardProps, OverlayCardThemeColors, PopoverAlign, PopoverBody, PopoverVerticalAlign, PressAwayOverlay, RotatedFrame, RotatedFrameProps, StaggeredWord, StaggeredWordProps, StatRow, StatSection, UpdateDialog, UpdateDialogProps, WELL_SHADOW, WellColors, getInlineColorPickerContentSize, getStaggeredWordDuration, isCompactDialogHeight, overlayActionStyles, overlayStyles, useCompactDialog, useOverlayCardColors, usePopoverHost, useWellColors } from './chrome/index.mjs';
|
|
2
3
|
import * as react from 'react';
|
|
3
|
-
import {
|
|
4
|
+
import { ReactNode } from 'react';
|
|
4
5
|
import { AchievementTier } from '@tastic/achievements';
|
|
5
6
|
import { Profile } from '@tastic/profile';
|
|
6
|
-
import { ViewStyle,
|
|
7
|
-
import { ViewRotation } from '@tastic/core';
|
|
7
|
+
import { ViewStyle, StyleProp } from 'react-native';
|
|
8
8
|
import { SeedColor } from '@rific/auto-paper';
|
|
9
9
|
export { SkiaGate, SkiaGateProps } from './SkiaGate.mjs';
|
|
10
|
+
import '@tastic/core';
|
|
10
11
|
|
|
11
12
|
interface UnlockedAchievement {
|
|
12
13
|
id: string;
|
|
@@ -18,7 +19,7 @@ interface AchievementUnlockOwner {
|
|
|
18
19
|
profile?: Profile | null;
|
|
19
20
|
color: string;
|
|
20
21
|
}
|
|
21
|
-
interface Props$
|
|
22
|
+
interface Props$4<Seat extends number> {
|
|
22
23
|
unlocks: Partial<Record<Seat, UnlockedAchievement[]>>;
|
|
23
24
|
seats: readonly Seat[];
|
|
24
25
|
owners: Record<Seat, AchievementUnlockOwner>;
|
|
@@ -26,32 +27,7 @@ interface Props$7<Seat extends number> {
|
|
|
26
27
|
fg?: string;
|
|
27
28
|
style?: ViewStyle;
|
|
28
29
|
}
|
|
29
|
-
declare function AchievementUnlockList<Seat extends number>({ unlocks, seats, owners, tierColors, fg: fgOverride, style }: Props$
|
|
30
|
-
|
|
31
|
-
type PopoverAlign = 'left' | 'right' | 'center';
|
|
32
|
-
type PopoverVerticalAlign = 'below' | 'above';
|
|
33
|
-
type PopoverRotation = ViewRotation;
|
|
34
|
-
interface AlignResult {
|
|
35
|
-
align: PopoverAlign;
|
|
36
|
-
verticalAlign: PopoverVerticalAlign;
|
|
37
|
-
maxHeight: number;
|
|
38
|
-
measured: boolean;
|
|
39
|
-
triggerRef: RefObject<View | null>;
|
|
40
|
-
}
|
|
41
|
-
declare function useAutoAlign(open: boolean, contentWidth: number, contentHeight: number, rotation?: PopoverRotation): {
|
|
42
|
-
align: PopoverAlign;
|
|
43
|
-
maxHeight: number;
|
|
44
|
-
measured: boolean;
|
|
45
|
-
triggerRef: RefObject<View | null>;
|
|
46
|
-
verticalAlign: PopoverVerticalAlign;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
interface PopoverHost {
|
|
50
|
-
openId: string | null;
|
|
51
|
-
toggle: (id: string) => void;
|
|
52
|
-
close: () => void;
|
|
53
|
-
}
|
|
54
|
-
declare function usePopoverHost(): PopoverHost;
|
|
30
|
+
declare function AchievementUnlockList<Seat extends number>({ unlocks, seats, owners, tierColors, fg: fgOverride, style }: Props$4<Seat>): react.JSX.Element | null;
|
|
55
31
|
|
|
56
32
|
interface MenuOption<T extends string | number> {
|
|
57
33
|
value: T;
|
|
@@ -77,7 +53,7 @@ interface MultiSelectSection<T extends string | number> {
|
|
|
77
53
|
allClear?: boolean;
|
|
78
54
|
}
|
|
79
55
|
type MenuSection = SingleSelectSection<any> | MultiSelectSection<any>;
|
|
80
|
-
interface Props$
|
|
56
|
+
interface Props$3 {
|
|
81
57
|
id: string;
|
|
82
58
|
host: PopoverHost;
|
|
83
59
|
icon: string;
|
|
@@ -97,7 +73,7 @@ interface Props$6 {
|
|
|
97
73
|
clear: string;
|
|
98
74
|
};
|
|
99
75
|
}
|
|
100
|
-
declare function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, autoDismiss, labelFontFamily, allClearLabels }: Props$
|
|
76
|
+
declare function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, autoDismiss, labelFontFamily, allClearLabels }: Props$3): react.JSX.Element;
|
|
101
77
|
|
|
102
78
|
interface ControlSchemePickerProps<T extends string | number> {
|
|
103
79
|
id: string;
|
|
@@ -129,32 +105,6 @@ interface CornerStatusBadgesProps {
|
|
|
129
105
|
}
|
|
130
106
|
declare function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }: CornerStatusBadgesProps): react.JSX.Element;
|
|
131
107
|
|
|
132
|
-
declare function getInlineColorPickerContentSize(swatchCount: number, windowWidth: number, columns?: number): {
|
|
133
|
-
width: number;
|
|
134
|
-
height: number;
|
|
135
|
-
};
|
|
136
|
-
interface Props$5 {
|
|
137
|
-
id: string;
|
|
138
|
-
host: PopoverHost;
|
|
139
|
-
value: string;
|
|
140
|
-
onChange: (hex: string) => void;
|
|
141
|
-
previewValue?: (hex: string) => string;
|
|
142
|
-
swatches?: SeedColor[];
|
|
143
|
-
takenValue?: string;
|
|
144
|
-
allowSwapTaken?: boolean;
|
|
145
|
-
dark: boolean;
|
|
146
|
-
align?: 'left' | 'right' | 'center';
|
|
147
|
-
alignOverride?: AlignResult;
|
|
148
|
-
rotation?: PopoverRotation;
|
|
149
|
-
icon?: string;
|
|
150
|
-
tag?: string;
|
|
151
|
-
labelFontFamily?: string;
|
|
152
|
-
autoDismiss?: boolean;
|
|
153
|
-
columns?: number;
|
|
154
|
-
size?: number;
|
|
155
|
-
}
|
|
156
|
-
declare function InlineColorPicker({ id, host, value, onChange, previewValue, swatches, takenValue, allowSwapTaken, dark, align: forcedAlign, alignOverride, rotation: rotationOverride, icon, tag, labelFontFamily, autoDismiss, columns, size }: Props$5): react.JSX.Element;
|
|
157
|
-
|
|
158
108
|
declare const LABELED_DROPDOWN_POPOVER_WIDTH = 180;
|
|
159
109
|
declare function getLabeledDropdownContentHeight(optionCount: number): number;
|
|
160
110
|
interface LabeledDropdownOption<T extends string> {
|
|
@@ -162,7 +112,7 @@ interface LabeledDropdownOption<T extends string> {
|
|
|
162
112
|
label: string;
|
|
163
113
|
icon?: string;
|
|
164
114
|
}
|
|
165
|
-
interface Props$
|
|
115
|
+
interface Props$2<T extends string> {
|
|
166
116
|
id: string;
|
|
167
117
|
host: PopoverHost;
|
|
168
118
|
options: LabeledDropdownOption<T>[];
|
|
@@ -173,7 +123,7 @@ interface Props$4<T extends string> {
|
|
|
173
123
|
align?: 'left' | 'right' | 'center';
|
|
174
124
|
alignOverride?: AlignResult;
|
|
175
125
|
}
|
|
176
|
-
declare function LabeledDropdown<T extends string>({ id, host, options, value, onChange, color, dark, align: forcedAlign, alignOverride }: Props$
|
|
126
|
+
declare function LabeledDropdown<T extends string>({ id, host, options, value, onChange, color, dark, align: forcedAlign, alignOverride }: Props$2<T>): react.JSX.Element;
|
|
177
127
|
|
|
178
128
|
declare function loadSkiaWeb(): Promise<void>;
|
|
179
129
|
|
|
@@ -215,25 +165,6 @@ interface PlayerSetupPanelProps<C extends string = string> {
|
|
|
215
165
|
}
|
|
216
166
|
declare function PlayerSetupPanel<C extends string = string>({ idPrefix, host, label, labelFontFamily, color, onColorChange, swatches, takenColor, allowSwapTaken, colorCaption, showColor, colorAlignOverride, colorRotation, isHuman, secondPicker, secondPickerId, ready, onToggleReady, dark, showReadyButton, profiles, selectedProfileId, takenProfileId, guestLabel, onProfileSelect, onManageProfiles, cpuDifficulty, cpuDifficultyOptions, onCpuDifficultyChange, humanIcon, cpuIcon }: PlayerSetupPanelProps<C>): react.JSX.Element;
|
|
217
167
|
|
|
218
|
-
interface Props$3 {
|
|
219
|
-
visible: boolean;
|
|
220
|
-
children: ReactNode;
|
|
221
|
-
align?: 'left' | 'right' | 'center';
|
|
222
|
-
verticalAlign?: 'below' | 'above';
|
|
223
|
-
caretColor?: string;
|
|
224
|
-
caretBorderColor?: string;
|
|
225
|
-
caretBorderWidth?: number;
|
|
226
|
-
triggerSize?: number;
|
|
227
|
-
}
|
|
228
|
-
declare function PopoverBody({ visible, children, align, verticalAlign, caretColor, caretBorderColor, caretBorderWidth, triggerSize }: Props$3): react.JSX.Element | null;
|
|
229
|
-
|
|
230
|
-
interface Props$2 {
|
|
231
|
-
active: boolean;
|
|
232
|
-
onPress: () => void;
|
|
233
|
-
style?: StyleProp<ViewStyle>;
|
|
234
|
-
}
|
|
235
|
-
declare function PressAwayOverlay({ active, onPress, style }: Props$2): react.JSX.Element | null;
|
|
236
|
-
|
|
237
168
|
interface Props$1 {
|
|
238
169
|
color: string;
|
|
239
170
|
ready: boolean;
|
|
@@ -279,4 +210,4 @@ declare function useQuitConfirmation(hasProgress: () => boolean, onConfirmedBack
|
|
|
279
210
|
|
|
280
211
|
declare function useZoneClampedAlign(open: boolean, contentWidth: number, contentHeight: number, rotation?: PopoverRotation): ReturnType<typeof useAutoAlign>;
|
|
281
212
|
|
|
282
|
-
export { AchievementUnlockList, type AchievementUnlockOwner,
|
|
213
|
+
export { AchievementUnlockList, type AchievementUnlockOwner, AlignResult, ControlSchemePicker, type ControlSchemePickerProps, type CornerStatusBadgeSeat, CornerStatusBadges, type CornerStatusBadgesProps, LABELED_DROPDOWN_POPOVER_WIDTH, LabeledDropdown, type LabeledDropdownOption, type MenuOption, type MenuSection, type MultiSelectSection, type OrientationMode, PlayerSetupPanel, type PlayerSetupPanelProps, PopoverHost, PopoverRotation, type QuitConfirmation, ReadyButton, SectionedDropdown, SharedActionBand, type SingleSelectSection, TriggerGaugeHost, type TriggerGaugeProps, type UnlockedAchievement, getColorPopoverId, getCpuDifficultyPopoverId, getLabeledDropdownContentHeight, getProfilePopoverId, loadSkiaWeb, useAutoAlign, useQuitConfirmation, useZoneClampedAlign };
|