@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/dist/index.mjs CHANGED
@@ -10,18 +10,24 @@ import {
10
10
  ConfirmDialog,
11
11
  ContentGutter,
12
12
  CornerActionButtons,
13
+ InlineColorPicker,
13
14
  LOCKED_BADGE_COLOR,
14
15
  MONO_FONT,
16
+ PopoverBody,
17
+ PressAwayOverlay,
15
18
  RotatedFrame,
16
19
  StaggeredWord,
17
20
  StatRow,
18
21
  StatSection,
19
22
  UpdateDialog,
20
23
  WELL_SHADOW,
24
+ getInlineColorPickerContentSize,
21
25
  getStaggeredWordDuration,
26
+ useAutoAlign,
22
27
  useCompactDialog,
28
+ usePopoverHost,
23
29
  useWellColors
24
- } from "./chunk-N7A7W72S.mjs";
30
+ } from "./chunk-BXG44LIA.mjs";
25
31
  import {
26
32
  COMPACT_DIALOG_HEIGHT,
27
33
  DialogHeader,
@@ -85,132 +91,18 @@ import { Platform } from "react-native";
85
91
  import { getBlendedColor, getColorRoles } from "@rific/auto-paper";
86
92
  import { IconButton, TouchableRipple } from "@rific/feedback-press";
87
93
  import { useRotation } from "@tastic/core";
88
- import { ScrollView, StyleSheet as StyleSheet3, View as View4 } from "react-native";
94
+ import { ScrollView, StyleSheet as StyleSheet2, View as View2 } from "react-native";
89
95
  import { Icon as Icon2, Text as Text2 } from "react-native-paper";
90
96
 
91
- // src/PopoverBody.tsx
92
- import { StyleSheet as StyleSheet2, View as View2 } from "react-native";
93
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
94
- var CARET_SIZE = 7;
95
- var CARET_RING_OFFSET = 2;
96
- var CARET_DIP = 1;
97
- function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
98
- if (!visible) return null;
99
- const above = verticalAlign === "above";
100
- const alignStyle = align === "left" ? styles2.contentLeft : align === "right" ? styles2.contentRight : styles2.contentCenter;
101
- const verticalStyle = above ? styles2.contentAbove : styles2.contentBelow;
102
- const ringSize = CARET_SIZE + caretBorderWidth;
103
- const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
104
- const caretFill = above ? "borderTopColor" : "borderBottomColor";
105
- const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
106
- const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
107
- return /* @__PURE__ */ jsxs2(View2, { style: [styles2.content, alignStyle, verticalStyle], children: [
108
- children,
109
- caretColor && /* @__PURE__ */ jsxs2(Fragment, { children: [
110
- /* @__PURE__ */ jsx2(View2, { style: [styles2.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
111
- /* @__PURE__ */ jsx2(View2, { style: [styles2.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
112
- ] })
113
- ] });
114
- }
115
- var styles2 = StyleSheet2.create({
116
- caret: {
117
- borderLeftColor: "transparent",
118
- borderRightColor: "transparent",
119
- height: 0,
120
- position: "absolute",
121
- width: 0,
122
- // Explicit, not left to DOM order - the box it dips into is itself a position:'relative' view,
123
- // which React Native Web always gives an implicit zIndex:0 (see PopoverBody's stacking-context
124
- // notes elsewhere in this codebase), so painting on top needs a real zIndex to beat that
125
- // reliably rather than relying on being the later sibling.
126
- zIndex: 1
127
- },
128
- content: {
129
- position: "absolute",
130
- zIndex: 50
131
- },
132
- contentAbove: {
133
- bottom: "100%",
134
- marginBottom: 8
135
- },
136
- contentBelow: {
137
- marginTop: 8,
138
- top: "100%"
139
- },
140
- // Stretched to the anchor's own (trigger) width, with alignItems centering the actual (usually
141
- // much wider) popover box inside via plain flexbox - not `left:'50%'` plus a percentage
142
- // `transform`, which depends on native resolving the box's own auto width before applying the
143
- // transform and has proven unreliable there, visibly shifting the box off-center.
144
- contentCenter: {
145
- alignItems: "center",
146
- left: 0,
147
- right: 0
148
- },
149
- contentLeft: {
150
- left: 0
151
- },
152
- contentRight: {
153
- right: 0
154
- }
155
- });
156
-
157
97
  // src/TriggerGaugeHost.tsx
158
- import { jsx as jsx3 } from "react/jsx-runtime";
98
+ import { jsx as jsx2 } from "react/jsx-runtime";
159
99
  var getTriggerGauge = () => import("./TriggerGauge-GIHKGAZE.mjs").then((mod) => ({ default: mod.TriggerGauge }));
160
100
  function TriggerGaugeHost(props) {
161
- return /* @__PURE__ */ jsx3(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
162
- }
163
-
164
- // src/useAutoAlign.ts
165
- import { useCallback, useEffect, useRef, useState } from "react";
166
- import { useWindowDimensions } from "react-native";
167
- var EDGE_MARGIN = 12;
168
- function rotateRect(x, y, width, height, rotation, windowWidth, windowHeight) {
169
- if (rotation === 0) return { x, y, width, height };
170
- const cx = windowWidth / 2;
171
- const cy = windowHeight / 2;
172
- const dx = x + width / 2 - cx;
173
- const dy = y + height / 2 - cy;
174
- const [newDx, newDy, newWidth, newHeight] = rotation === 180 ? [-dx, -dy, width, height] : rotation === 90 ? [-dy, dx, height, width] : [dy, -dx, height, width];
175
- return { x: cx + newDx - newWidth / 2, y: cy + newDy - newHeight / 2, width: newWidth, height: newHeight };
176
- }
177
- function useAutoAlign(open, contentWidth, contentHeight, rotation = 0) {
178
- const triggerRef = useRef(null);
179
- const { width: windowWidth, height: windowHeight } = useWindowDimensions();
180
- const [align, setAlign] = useState("center");
181
- const [verticalAlign, setVerticalAlign] = useState("below");
182
- const [maxHeight, setMaxHeight] = useState(contentHeight);
183
- const [measured, setMeasured] = useState(false);
184
- const [prevOpen, setPrevOpen] = useState(open);
185
- if (open !== prevOpen) {
186
- setPrevOpen(open);
187
- if (open) setMeasured(false);
188
- }
189
- const measure = useCallback(() => {
190
- triggerRef.current?.measureInWindow((rawX, rawY, rawWidth, rawHeight) => {
191
- const { x, y, width: triggerWidth, height: triggerHeight } = rotateRect(rawX, rawY, rawWidth, rawHeight, rotation, windowWidth, windowHeight);
192
- const centerX = x + triggerWidth / 2;
193
- const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
194
- const overflowsLeft = centerX - contentWidth / 2 < EDGE_MARGIN;
195
- if (overflowsRight && !overflowsLeft) setAlign("right");
196
- else if (overflowsLeft && !overflowsRight) setAlign("left");
197
- else setAlign("center");
198
- const roomBelow = windowHeight - (y + triggerHeight) - EDGE_MARGIN;
199
- const roomAbove = y - EDGE_MARGIN;
200
- const above = contentHeight > roomBelow && roomAbove > roomBelow;
201
- setVerticalAlign(above ? "above" : "below");
202
- setMaxHeight(Math.max(above ? roomAbove : roomBelow, 0));
203
- setMeasured(true);
204
- });
205
- }, [contentWidth, contentHeight, windowWidth, windowHeight, rotation]);
206
- useEffect(() => {
207
- if (open) measure();
208
- }, [open, measure]);
209
- return { align, maxHeight, measured, triggerRef, verticalAlign };
101
+ return /* @__PURE__ */ jsx2(SkiaGate, { getComponent: getTriggerGauge, componentProps: props });
210
102
  }
211
103
 
212
104
  // src/SectionedDropdown.tsx
213
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
105
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
214
106
  var MENU_BORDER_WIDTH = 1;
215
107
  var TRIGGER_SIZE = 44;
216
108
  var MENU_MIN_WIDTH = 200;
@@ -260,17 +152,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
260
152
  }
261
153
  gaugeOffset += section.options.length;
262
154
  }
263
- const anchorStyle = [styles3.anchor, open && styles3.anchorOpen];
155
+ const anchorStyle = [styles2.anchor, open && styles2.anchorOpen];
264
156
  const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
265
157
  const dividerStyle = { backgroundColor: menuBorderColor };
266
- return /* @__PURE__ */ jsxs3(View4, { style: anchorStyle, children: [
267
- /* @__PURE__ */ jsxs3(View4, { ref: triggerRef, collapsable: false, style: styles3.triggerBox, children: [
268
- /* @__PURE__ */ jsx4(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
269
- /* @__PURE__ */ jsx4(IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
158
+ return /* @__PURE__ */ jsxs2(View2, { style: anchorStyle, children: [
159
+ /* @__PURE__ */ jsxs2(View2, { ref: triggerRef, collapsable: false, style: styles2.triggerBox, children: [
160
+ /* @__PURE__ */ jsx3(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
161
+ /* @__PURE__ */ jsx3(IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
270
162
  ] }),
271
- /* @__PURE__ */ jsx4(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx4(ScrollView, { style: [styles3.menu, menuStyle], contentContainerStyle: styles3.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs3(View4, { children: [
272
- sectionIndex > 0 && /* @__PURE__ */ jsx4(View4, { style: [styles3.divider, dividerStyle] }),
273
- section.kind === "single" ? /* @__PURE__ */ jsx4(
163
+ /* @__PURE__ */ jsx3(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx3(ScrollView, { style: [styles2.menu, menuStyle], contentContainerStyle: styles2.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs2(View2, { children: [
164
+ sectionIndex > 0 && /* @__PURE__ */ jsx3(View2, { style: [styles2.divider, dividerStyle] }),
165
+ section.kind === "single" ? /* @__PURE__ */ jsx3(
274
166
  SingleSection,
275
167
  {
276
168
  section,
@@ -283,7 +175,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
283
175
  if (autoDismiss) host.close();
284
176
  }
285
177
  }
286
- ) : /* @__PURE__ */ jsx4(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
178
+ ) : /* @__PURE__ */ jsx3(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
287
179
  ] }, section.id)) }) })
288
180
  ] });
289
181
  }
@@ -295,18 +187,18 @@ function SingleSection({
295
187
  labelFontFamily,
296
188
  onSelect
297
189
  }) {
298
- return /* @__PURE__ */ jsx4(Fragment2, { children: section.options.map((option) => {
190
+ return /* @__PURE__ */ jsx3(Fragment, { children: section.options.map((option) => {
299
191
  const selected = option.value === section.value;
300
192
  const taken = !selected && option.value === section.takenValue;
301
193
  const rowColor = selected ? onAccentColor : mutedColor;
302
- const itemStyle = [styles3.item, selected && { backgroundColor: accentColor }, taken && styles3.itemTaken];
194
+ const itemStyle = [styles2.item, selected && { backgroundColor: accentColor }, taken && styles2.itemTaken];
303
195
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
304
196
  const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
305
- return /* @__PURE__ */ jsx4(TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs3(View4, { style: styles3.itemRow, children: [
306
- option.icon && /* @__PURE__ */ jsx4(Icon2, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
307
- /* @__PURE__ */ jsxs3(View4, { style: styles3.itemLabelColumn, children: [
308
- /* @__PURE__ */ jsx4(Text2, { variant: "labelLarge", style: labelStyle, children: option.label }),
309
- option.description && /* @__PURE__ */ jsx4(Text2, { variant: "labelSmall", style: descriptionStyle, children: option.description })
197
+ return /* @__PURE__ */ jsx3(TouchableRipple, { disabled: taken, onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs2(View2, { style: styles2.itemRow, children: [
198
+ option.icon && /* @__PURE__ */ jsx3(Icon2, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
199
+ /* @__PURE__ */ jsxs2(View2, { style: styles2.itemLabelColumn, children: [
200
+ /* @__PURE__ */ jsx3(Text2, { variant: "labelLarge", style: labelStyle, children: option.label }),
201
+ option.description && /* @__PURE__ */ jsx3(Text2, { variant: "labelSmall", style: descriptionStyle, children: option.description })
310
202
  ] })
311
203
  ] }) }, option.value);
312
204
  }) });
@@ -320,23 +212,23 @@ function MultiSection({
320
212
  allClearLabels
321
213
  }) {
322
214
  const allSelected = section.value.length === section.options.length;
323
- return /* @__PURE__ */ jsxs3(Fragment2, { children: [
215
+ return /* @__PURE__ */ jsxs2(Fragment, { children: [
324
216
  section.options.map((option, i) => {
325
217
  const selected = section.value.includes(option.value);
326
218
  const rowColor = selected ? onAccentColor : mutedColor;
327
219
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
328
220
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
329
- const itemStyle = [styles3.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
221
+ const itemStyle = [styles2.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
330
222
  const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
331
- return /* @__PURE__ */ jsx4(TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs3(View4, { style: styles3.itemRow, children: [
332
- option.icon && /* @__PURE__ */ jsx4(Icon2, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
333
- /* @__PURE__ */ jsx4(Text2, { variant: "labelLarge", style: [styles3.itemLabelFlex, labelStyle], children: option.label })
223
+ return /* @__PURE__ */ jsx3(TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs2(View2, { style: styles2.itemRow, children: [
224
+ option.icon && /* @__PURE__ */ jsx3(Icon2, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
225
+ /* @__PURE__ */ jsx3(Text2, { variant: "labelLarge", style: [styles2.itemLabelFlex, labelStyle], children: option.label })
334
226
  ] }) }, option.value);
335
227
  }),
336
- section.allClear && /* @__PURE__ */ jsx4(TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles3.item, children: /* @__PURE__ */ jsx4(Text2, { variant: "labelLarge", style: [styles3.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
228
+ section.allClear && /* @__PURE__ */ jsx3(TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles2.item, children: /* @__PURE__ */ jsx3(Text2, { variant: "labelLarge", style: [styles2.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
337
229
  ] });
338
230
  }
339
- var styles3 = StyleSheet3.create({
231
+ var styles2 = StyleSheet2.create({
340
232
  allClearLabel: {
341
233
  fontWeight: "bold",
342
234
  textAlign: "center"
@@ -353,7 +245,7 @@ var styles3 = StyleSheet3.create({
353
245
  zIndex: 100
354
246
  },
355
247
  divider: {
356
- height: StyleSheet3.hairlineWidth,
248
+ height: StyleSheet2.hairlineWidth,
357
249
  marginVertical: 4
358
250
  },
359
251
  item: {
@@ -406,30 +298,30 @@ var styles3 = StyleSheet3.create({
406
298
  });
407
299
 
408
300
  // src/ControlSchemePicker.tsx
409
- import { jsx as jsx5 } from "react/jsx-runtime";
301
+ import { jsx as jsx4 } from "react/jsx-runtime";
410
302
  function ControlSchemePicker({ id, host, value, onChange, options, takenValue, accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily }) {
411
303
  const isTouchPrimary = useIsTouchPrimaryDevice();
412
304
  if (Platform.OS !== "web" || isTouchPrimary) return null;
413
- return /* @__PURE__ */ jsx5(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
305
+ return /* @__PURE__ */ jsx4(SectionedDropdown, { id, host, icon: "keyboard-outline", accessibilityLabel: "Control scheme", sections: [{ kind: "single", id: "controls", options, value, onChange, takenValue }], accentColor, mutedColor, onAccentColor, dark, align, alignOverride, rotation, labelFontFamily });
414
306
  }
415
307
 
416
308
  // src/CornerStatusBadges.tsx
417
- import { StyleSheet as StyleSheet4, View as View5 } from "react-native";
309
+ import { StyleSheet as StyleSheet3, View as View3 } from "react-native";
418
310
  import { Icon as Icon3 } from "react-native-paper";
419
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
311
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
420
312
  var BADGE_SIZE = 30;
421
313
  function StatusBadge({ icon }) {
422
- return /* @__PURE__ */ jsx6(View5, { style: styles4.badge, children: icon && /* @__PURE__ */ jsx6(Icon3, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
314
+ return /* @__PURE__ */ jsx5(View3, { style: styles3.badge, children: icon && /* @__PURE__ */ jsx5(Icon3, { source: icon, size: 16, color: "rgba(255,255,255,0.85)" }) });
423
315
  }
424
316
  function CornerStatusBadges({ orientationMode, p1OnRight, p1, p2 }) {
425
317
  const p1OnRightSide = orientationMode === "sideBySide" && p1OnRight;
426
318
  const p2OnLeftSide = orientationMode === "sideBySide" && !p1OnRight;
427
- return /* @__PURE__ */ jsxs4(Fragment3, { children: [
428
- p1 && /* @__PURE__ */ jsx6(View5, { pointerEvents: "none", style: p1OnRightSide ? styles4.bottomRight : styles4.bottomLeft, children: /* @__PURE__ */ jsx6(StatusBadge, { icon: p1.icon }) }),
429
- p2 && /* @__PURE__ */ jsx6(View5, { pointerEvents: "none", style: p2OnLeftSide ? styles4.topLeft : styles4.topRight, children: /* @__PURE__ */ jsx6(StatusBadge, { icon: p2.icon }) })
319
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
320
+ p1 && /* @__PURE__ */ jsx5(View3, { pointerEvents: "none", style: p1OnRightSide ? styles3.bottomRight : styles3.bottomLeft, children: /* @__PURE__ */ jsx5(StatusBadge, { icon: p1.icon }) }),
321
+ p2 && /* @__PURE__ */ jsx5(View3, { pointerEvents: "none", style: p2OnLeftSide ? styles3.topLeft : styles3.topRight, children: /* @__PURE__ */ jsx5(StatusBadge, { icon: p2.icon }) })
430
322
  ] });
431
323
  }
432
- var styles4 = StyleSheet4.create({
324
+ var styles3 = StyleSheet3.create({
433
325
  badge: {
434
326
  alignItems: "center",
435
327
  backgroundColor: "rgba(0,0,0,0.28)",
@@ -447,149 +339,12 @@ var styles4 = StyleSheet4.create({
447
339
  topRight: { position: "absolute", right: 12, top: 12 }
448
340
  });
449
341
 
450
- // src/InlineColorPicker.tsx
451
- import { defaultColors, getContrastColor as getContrastColor2 } from "@rific/auto-paper";
342
+ // src/LabeledDropdown.tsx
343
+ import { getContrastColor as getContrastColor2 } from "@rific/auto-paper";
452
344
  import { TouchableRipple as TouchableRipple2 } from "@rific/feedback-press";
453
- import { clamp, useRotation as useRotation2 } from "@tastic/core";
454
- import { ScrollView as ScrollView2, StyleSheet as StyleSheet5, useWindowDimensions as useWindowDimensions2, View as View6 } from "react-native";
345
+ import { ScrollView as ScrollView2, StyleSheet as StyleSheet4, View as View4 } from "react-native";
455
346
  import { Icon as Icon4, Text as Text3 } from "react-native-paper";
456
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
457
- var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
458
- var DEFAULT_SIZE = 48;
459
- var SWATCH_SIZE = 28;
460
- var SWATCHES_PADDING = 8;
461
- var SWATCHES_GAP = 6;
462
- var SWATCHES_BORDER_WIDTH = 2;
463
- var MIN_COLUMNS = 4;
464
- var MAX_COLUMNS = 5;
465
- var SCREEN_MARGIN = 40;
466
- function widthForColumns(columns) {
467
- return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
468
- }
469
- function getInlineColorPickerContentSize(swatchCount, windowWidth, columns) {
470
- const autoColumns = clamp(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
471
- const resolvedColumns = columns ?? autoColumns;
472
- const width = widthForColumns(resolvedColumns);
473
- const rows = Math.ceil(swatchCount / resolvedColumns);
474
- const height = SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * rows + SWATCHES_GAP * (rows - 1);
475
- return { width, height };
476
- }
477
- 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 }) {
478
- const ambientRotation = useRotation2();
479
- const rotation = rotationOverride ?? ambientRotation;
480
- const menuBg = dark ? "#000000" : "#FFFFFF";
481
- const { width: windowWidth } = useWindowDimensions2();
482
- const { width: swatchesWidth, height: swatchesHeight } = getInlineColorPickerContentSize(swatches.length, windowWidth, columns);
483
- const open = host.openId === id;
484
- const auto = useAutoAlign(open, swatchesWidth, swatchesHeight, rotation);
485
- const placement = alignOverride ?? auto;
486
- const { maxHeight, measured, triggerRef, verticalAlign } = placement;
487
- const align = forcedAlign ?? placement.align;
488
- const displayFor = previewValue ?? ((hex) => hex);
489
- const displayValue = displayFor(value);
490
- const contrastColor = getContrastColor2(displayValue);
491
- const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
492
- return /* @__PURE__ */ jsxs5(View6, { style: [styles5.anchor, open && styles5.anchorOpen], children: [
493
- /* @__PURE__ */ jsx7(TouchableRipple2, { onPress: () => host.toggle(id), borderless: true, style: [styles5.trigger, { backgroundColor: displayValue, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ jsx7(View6, { ref: triggerRef, collapsable: false, style: styles5.triggerMeasure, children: tag ? /* @__PURE__ */ jsx7(Text3, { style: [styles5.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ jsx7(Icon4, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
494
- /* @__PURE__ */ jsx7(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: displayValue, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ jsx7(ScrollView2, { style: [styles5.swatches, { backgroundColor: menuBg, borderColor: displayValue, width: swatchesWidth, maxHeight }], contentContainerStyle: styles5.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
495
- const selected = swatch.value.toLowerCase() === value.toLowerCase();
496
- const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
497
- const swappable = taken && allowSwapTaken;
498
- const swatchDisplay = displayFor(swatch.value);
499
- return /* @__PURE__ */ jsx7(
500
- TouchableRipple2,
501
- {
502
- disabled: taken && !swappable,
503
- onPress: () => {
504
- onChange(swatch.value);
505
- if (autoDismiss) host.close();
506
- },
507
- borderless: true,
508
- style: [styles5.swatch, { backgroundColor: swatchDisplay }, selected && styles5.swatchSelected, taken && !swappable && styles5.swatchTaken],
509
- children: selected ? /* @__PURE__ */ jsx7(Icon4, { source: "check", size: 16, color: getContrastColor2(swatchDisplay) }) : swappable ? /* @__PURE__ */ jsx7(Icon4, { source: "swap-horizontal", size: 16, color: getContrastColor2(swatchDisplay) }) : taken ? /* @__PURE__ */ jsx7(Icon4, { source: "close", size: 16, color: getContrastColor2(swatchDisplay) }) : /* @__PURE__ */ jsx7(View6, {})
510
- },
511
- swatch.value
512
- );
513
- }) }) })
514
- ] });
515
- }
516
- var styles5 = StyleSheet5.create({
517
- anchor: {
518
- position: "relative"
519
- },
520
- // See SectionedDropdown's identical comment - React Native Web gives every position:'relative' view
521
- // its own stacking context, so the elevation has to live on the anchor itself, not just the
522
- // popover content nested inside it, to correctly paint above this anchor's own later siblings.
523
- anchorOpen: {
524
- zIndex: 100
525
- },
526
- swatch: {
527
- alignItems: "center",
528
- borderRadius: SWATCH_SIZE / 2,
529
- height: SWATCH_SIZE,
530
- justifyContent: "center",
531
- width: SWATCH_SIZE
532
- },
533
- swatchSelected: {
534
- borderColor: "#ffffff",
535
- borderWidth: 2
536
- },
537
- swatchTaken: {
538
- opacity: 0.35
539
- },
540
- swatches: {
541
- borderRadius: 12,
542
- borderWidth: SWATCHES_BORDER_WIDTH,
543
- elevation: 8,
544
- shadowColor: "#000000",
545
- shadowOffset: { height: 2, width: 0 },
546
- shadowOpacity: 0.3,
547
- shadowRadius: 8
548
- // width is set inline above - border-box sizing means it has to include the border too
549
- // (2*SWATCHES_BORDER_WIDTH), not just padding+content, or exactly enough room goes missing that
550
- // the last column silently wraps to a new row. Anything wider than the exact sum just shows as
551
- // dead space on the right edge of each row instead.
552
- },
553
- // Separate from `swatches` itself - see SectionedDropdown's identical menu/menuContent split.
554
- // The scroll frame's own bounds (including maxHeight) live on the ScrollView; the actual grid
555
- // wrapping belongs to its contentContainerStyle, which sizes to the unclamped content instead.
556
- swatchesContent: {
557
- flexDirection: "row",
558
- flexWrap: "wrap",
559
- gap: SWATCHES_GAP,
560
- padding: SWATCHES_PADDING
561
- },
562
- tagLabel: {
563
- fontWeight: "700",
564
- letterSpacing: 0.5
565
- },
566
- // borderRadius/height/width come from the `size` prop instead (see render-site override) - no
567
- // fixed default here, since this style object is shared by every caller regardless of size.
568
- trigger: {
569
- alignItems: "center",
570
- alignSelf: "flex-start",
571
- justifyContent: "center"
572
- },
573
- // Wraps just the icon/tag, inside the TouchableRipple, purely so useAutoAlign has a plain View
574
- // to attach its measurement ref to - TouchableRipple itself doesn't forward a ref to a
575
- // measurable native node. Padded horizontally so a multi-character tag doesn't butt right up
576
- // against the trigger's own circular edge (an icon alone doesn't need it, but this style is
577
- // shared by both).
578
- triggerMeasure: {
579
- alignItems: "center",
580
- height: "100%",
581
- justifyContent: "center",
582
- paddingHorizontal: 4,
583
- width: "100%"
584
- }
585
- });
586
-
587
- // src/LabeledDropdown.tsx
588
- import { getContrastColor as getContrastColor3 } from "@rific/auto-paper";
589
- import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
590
- import { ScrollView as ScrollView3, StyleSheet as StyleSheet6, View as View7 } from "react-native";
591
- import { Icon as Icon5, Text as Text4 } from "react-native-paper";
592
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
347
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
593
348
  var TRIGGER_HEIGHT = 28;
594
349
  var POPOVER_WIDTH = 180;
595
350
  var ROW_HEIGHT = 36;
@@ -612,22 +367,22 @@ function LabeledDropdown({ id, host, options, value, onChange, color, dark, alig
612
367
  onChange(option.value);
613
368
  host.close();
614
369
  };
615
- return /* @__PURE__ */ jsxs6(View7, { style: [styles6.anchor, open && styles6.anchorOpen], children: [
616
- /* @__PURE__ */ jsx8(TouchableRipple3, { onPress: () => host.toggle(id), style: styles6.trigger, children: /* @__PURE__ */ jsxs6(View7, { ref: triggerRef, collapsable: false, style: styles6.triggerInner, children: [
617
- /* @__PURE__ */ jsx8(Text4, { style: [styles6.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
618
- /* @__PURE__ */ jsx8(Icon5, { source: "menu-down", size: 16, color })
370
+ return /* @__PURE__ */ jsxs4(View4, { style: [styles4.anchor, open && styles4.anchorOpen], children: [
371
+ /* @__PURE__ */ jsx6(TouchableRipple2, { onPress: () => host.toggle(id), style: styles4.trigger, children: /* @__PURE__ */ jsxs4(View4, { ref: triggerRef, collapsable: false, style: styles4.triggerInner, children: [
372
+ /* @__PURE__ */ jsx6(Text3, { style: [styles4.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
373
+ /* @__PURE__ */ jsx6(Icon4, { source: "menu-down", size: 16, color })
619
374
  ] }) }),
620
- /* @__PURE__ */ jsx8(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx8(ScrollView3, { style: [styles6.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles6.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
375
+ /* @__PURE__ */ jsx6(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ jsx6(ScrollView2, { style: [styles4.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles4.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
621
376
  const isSelected = option.value === value;
622
- const onColor = getContrastColor3(color);
623
- return /* @__PURE__ */ jsx8(TouchableRipple3, { onPress: () => handleSelect(option), style: [styles6.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs6(View7, { style: styles6.rowInner, children: [
624
- option.icon && /* @__PURE__ */ jsx8(Icon5, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
625
- /* @__PURE__ */ jsx8(Text4, { style: [styles6.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
377
+ const onColor = getContrastColor2(color);
378
+ return /* @__PURE__ */ jsx6(TouchableRipple2, { onPress: () => handleSelect(option), style: [styles4.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ jsxs4(View4, { style: styles4.rowInner, children: [
379
+ option.icon && /* @__PURE__ */ jsx6(Icon4, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
380
+ /* @__PURE__ */ jsx6(Text3, { style: [styles4.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
626
381
  ] }) }, option.value);
627
382
  }) }) })
628
383
  ] });
629
384
  }
630
- var styles6 = StyleSheet6.create({
385
+ var styles4 = StyleSheet4.create({
631
386
  anchor: {
632
387
  position: "relative"
633
388
  },
@@ -686,21 +441,21 @@ function loadSkiaWeb() {
686
441
 
687
442
  // src/PlayerSetupPanel.tsx
688
443
  import { getOptionPickerContentSize, getProfilePickerContentSize, OptionPicker, ProfilePicker } from "@tastic/profile";
689
- import { StyleSheet as StyleSheet8, View as View8 } from "react-native";
690
- import { Text as Text6 } from "react-native-paper";
444
+ import { StyleSheet as StyleSheet6, View as View5 } from "react-native";
445
+ import { Text as Text5 } from "react-native-paper";
691
446
 
692
447
  // src/ReadyButton.tsx
693
- import { TouchableRipple as TouchableRipple4 } from "@rific/feedback-press";
694
- import { StyleSheet as StyleSheet7 } from "react-native";
695
- import { Text as Text5 } from "react-native-paper";
696
- import { jsx as jsx9 } from "react/jsx-runtime";
448
+ import { TouchableRipple as TouchableRipple3 } from "@rific/feedback-press";
449
+ import { StyleSheet as StyleSheet5 } from "react-native";
450
+ import { Text as Text4 } from "react-native-paper";
451
+ import { jsx as jsx7 } from "react/jsx-runtime";
697
452
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
698
- const readyButtonStyle = [styles7.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
453
+ const readyButtonStyle = [styles5.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
699
454
  const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
700
455
  const labelColorStyle = { color: ready ? "#000000" : color };
701
- return /* @__PURE__ */ jsx9(TouchableRipple4, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx9(Text5, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
456
+ return /* @__PURE__ */ jsx7(TouchableRipple3, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx7(Text4, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
702
457
  }
703
- var styles7 = StyleSheet7.create({
458
+ var styles5 = StyleSheet5.create({
704
459
  readyButton: {
705
460
  alignItems: "center",
706
461
  borderRadius: 12,
@@ -712,41 +467,30 @@ var styles7 = StyleSheet7.create({
712
467
  }
713
468
  });
714
469
 
715
- // src/usePopoverHost.ts
716
- import { useCallback as useCallback2, useState as useState2 } from "react";
717
- function usePopoverHost() {
718
- const [openId, setOpenId] = useState2(null);
719
- const toggle = useCallback2((id) => {
720
- setOpenId((prev) => prev === id ? null : id);
721
- }, []);
722
- const close = useCallback2(() => setOpenId(null), []);
723
- return { openId, toggle, close };
724
- }
725
-
726
470
  // src/useZoneClampedAlign.ts
727
471
  import { useZoneBounds } from "@tastic/split-screen";
728
- import { useEffect as useEffect2, useState as useState3 } from "react";
729
- import { useWindowDimensions as useWindowDimensions3 } from "react-native";
472
+ import { useEffect, useState } from "react";
473
+ import { useWindowDimensions } from "react-native";
730
474
  import { useSafeAreaInsets } from "react-native-safe-area-context";
731
- var EDGE_MARGIN2 = 12;
475
+ var EDGE_MARGIN = 12;
732
476
  function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
733
477
  const auto = useAutoAlign(open, contentWidth, contentHeight, rotation);
734
478
  const zone = useZoneBounds();
735
- const { height: windowHeight } = useWindowDimensions3();
479
+ const { height: windowHeight } = useWindowDimensions();
736
480
  const insets = useSafeAreaInsets();
737
481
  const shouldMeasure = open && auto.measured && zone !== null;
738
- const [ownBounds, setOwnBounds] = useState3(null);
739
- const [prevShouldMeasure, setPrevShouldMeasure] = useState3(shouldMeasure);
482
+ const [ownBounds, setOwnBounds] = useState(null);
483
+ const [prevShouldMeasure, setPrevShouldMeasure] = useState(shouldMeasure);
740
484
  if (shouldMeasure !== prevShouldMeasure) {
741
485
  setPrevShouldMeasure(shouldMeasure);
742
486
  setOwnBounds(null);
743
487
  }
744
- useEffect2(() => {
488
+ useEffect(() => {
745
489
  if (!shouldMeasure) return;
746
490
  auto.triggerRef.current?.measureInWindow((_x, y, _width, height) => {
747
491
  const belowShared = zone.zoneSide === "belowShared";
748
- const awayRoom = belowShared ? windowHeight - insets.bottom - (y + height) - EDGE_MARGIN2 : y - insets.top - EDGE_MARGIN2;
749
- const towardRoom = belowShared ? y - zone.sharedEdgeY - EDGE_MARGIN2 : zone.sharedEdgeY - (y + height) - EDGE_MARGIN2;
492
+ const awayRoom = belowShared ? windowHeight - insets.bottom - (y + height) - EDGE_MARGIN : y - insets.top - EDGE_MARGIN;
493
+ const towardRoom = belowShared ? y - zone.sharedEdgeY - EDGE_MARGIN : zone.sharedEdgeY - (y + height) - EDGE_MARGIN;
750
494
  const useToward = contentHeight > awayRoom && towardRoom > awayRoom;
751
495
  let awaySide = belowShared ? "below" : "above";
752
496
  let towardSide = belowShared ? "above" : "below";
@@ -763,7 +507,7 @@ function useZoneClampedAlign(open, contentWidth, contentHeight, rotation = 0) {
763
507
  }
764
508
 
765
509
  // src/PlayerSetupPanel.tsx
766
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
510
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
767
511
  function getColorPopoverId(idPrefix) {
768
512
  return `${idPrefix}-color`;
769
513
  }
@@ -786,16 +530,16 @@ function PlayerSetupPanel({ idPrefix, host, label, labelFontFamily, color, onCol
786
530
  const seatPickerId = showProfilePicker ? getProfilePopoverId(idPrefix) : getCpuDifficultyPopoverId(idPrefix);
787
531
  const seatPickerSize = showProfilePicker ? getProfilePickerContentSize(profiles.length, !!onManageProfiles, colorSection) : getOptionPickerContentSize(cpuDifficultyOptions?.length ?? 0, colorSection);
788
532
  const seatPickerAlign = useZoneClampedAlign(seatButton && popover.openId === seatPickerId, seatPickerSize.width, seatPickerSize.height);
789
- return /* @__PURE__ */ jsxs7(View8, { style: [styles8.panel, ownPopoverOpen && styles8.panelOpen], children: [
790
- showProfilePicker ? /* @__PURE__ */ jsx10(ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles, colorSection, alignOverride: seatPickerAlign }) : showCpuDifficulty ? /* @__PURE__ */ jsx10(OptionPicker, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, icon: cpuIcon, colorSection, alignOverride: seatPickerAlign }) : label && /* @__PURE__ */ jsx10(Text6, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
791
- (!seatButton || secondPicker) && /* @__PURE__ */ jsxs7(View8, { style: [styles8.pickerRow, pickerRowPopoverOpen && styles8.pickerRowOpen], children: [
792
- !seatButton && /* @__PURE__ */ jsx10(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
533
+ return /* @__PURE__ */ jsxs5(View5, { style: [styles6.panel, ownPopoverOpen && styles6.panelOpen], children: [
534
+ showProfilePicker ? /* @__PURE__ */ jsx8(ProfilePicker, { idPrefix, host: popover, profiles, selectedId: selectedProfileId ?? null, takenId: takenProfileId, color, dark, guestLabel: guestLabel ?? "GUEST", onSelect: (profile) => onProfileSelect?.(profile), onManage: onManageProfiles, colorSection, alignOverride: seatPickerAlign }) : showCpuDifficulty ? /* @__PURE__ */ jsx8(OptionPicker, { id: getCpuDifficultyPopoverId(idPrefix), host: popover, options: cpuDifficultyOptions, value: cpuDifficulty, onChange: onCpuDifficultyChange, color, dark, icon: cpuIcon, colorSection, alignOverride: seatPickerAlign }) : label && /* @__PURE__ */ jsx8(Text5, { variant: "labelSmall", style: { color, fontFamily: labelFontFamily }, children: label }),
535
+ (!seatButton || secondPicker) && /* @__PURE__ */ jsxs5(View5, { style: [styles6.pickerRow, pickerRowPopoverOpen && styles6.pickerRowOpen], children: [
536
+ !seatButton && /* @__PURE__ */ jsx8(InlineColorPicker, { id: getColorPopoverId(idPrefix), host: popover, value: color, onChange: onColorChange, swatches, takenValue: takenColor, allowSwapTaken, alignOverride: colorAlignOverride, rotation: colorRotation, dark, tag: isHuman ? selectedProfile?.tag : void 0, icon: isHuman ? humanIcon : cpuIcon }),
793
537
  secondPicker
794
538
  ] }),
795
- isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ jsx10(ReadyButton, { color, ready: ready ?? false, onToggleReady })
539
+ isHuman && showReadyButton && onToggleReady && /* @__PURE__ */ jsx8(ReadyButton, { color, ready: ready ?? false, onToggleReady })
796
540
  ] });
797
541
  }
798
- var styles8 = StyleSheet8.create({
542
+ var styles6 = StyleSheet6.create({
799
543
  panel: {
800
544
  alignItems: "center",
801
545
  gap: 12
@@ -826,30 +570,22 @@ var styles8 = StyleSheet8.create({
826
570
  }
827
571
  });
828
572
 
829
- // src/PressAwayOverlay.tsx
830
- import { Pressable, StyleSheet as StyleSheet9 } from "react-native";
831
- import { jsx as jsx11 } from "react/jsx-runtime";
832
- function PressAwayOverlay({ active, onPress, style }) {
833
- if (!active) return null;
834
- return /* @__PURE__ */ jsx11(Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [StyleSheet9.absoluteFill, style] });
835
- }
836
-
837
573
  // src/SharedActionBand.tsx
838
574
  import { IconButton as IconButton2 } from "@rific/feedback-press";
839
- import { StyleSheet as StyleSheet10, View as View9 } from "react-native";
840
- import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
575
+ import { StyleSheet as StyleSheet7, View as View6 } from "react-native";
576
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
841
577
  function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
842
- return /* @__PURE__ */ jsxs8(View9, { style: [styles9.column, popoverOpen && styles9.columnOpen], children: [
843
- /* @__PURE__ */ jsxs8(View9, { style: styles9.actionsRow, children: [
844
- /* @__PURE__ */ jsx12(IconButton2, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
845
- onRandomize && /* @__PURE__ */ jsx12(IconButton2, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
846
- onReset && /* @__PURE__ */ jsx12(IconButton2, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
847
- /* @__PURE__ */ jsx12(IconButton2, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
578
+ return /* @__PURE__ */ jsxs6(View6, { style: [styles7.column, popoverOpen && styles7.columnOpen], children: [
579
+ /* @__PURE__ */ jsxs6(View6, { style: styles7.actionsRow, children: [
580
+ /* @__PURE__ */ jsx9(IconButton2, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
581
+ onRandomize && /* @__PURE__ */ jsx9(IconButton2, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
582
+ onReset && /* @__PURE__ */ jsx9(IconButton2, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
583
+ /* @__PURE__ */ jsx9(IconButton2, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
848
584
  ] }),
849
585
  children
850
586
  ] });
851
587
  }
852
- var styles9 = StyleSheet10.create({
588
+ var styles7 = StyleSheet7.create({
853
589
  actionsRow: {
854
590
  alignItems: "center",
855
591
  flexDirection: "row",
@@ -865,22 +601,22 @@ var styles9 = StyleSheet10.create({
865
601
  });
866
602
 
867
603
  // src/useQuitConfirmation.ts
868
- import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
604
+ import { useCallback, useEffect as useEffect2, useRef, useState as useState2 } from "react";
869
605
  function useQuitConfirmation(hasProgress, onConfirmedBack) {
870
- const [confirmVisible, setConfirmVisible] = useState4(false);
871
- const hasProgressRef = useRef2(hasProgress);
872
- useEffect3(() => {
606
+ const [confirmVisible, setConfirmVisible] = useState2(false);
607
+ const hasProgressRef = useRef(hasProgress);
608
+ useEffect2(() => {
873
609
  hasProgressRef.current = hasProgress;
874
610
  });
875
- const onConfirmedBackRef = useRef2(onConfirmedBack);
876
- useEffect3(() => {
611
+ const onConfirmedBackRef = useRef(onConfirmedBack);
612
+ useEffect2(() => {
877
613
  onConfirmedBackRef.current = onConfirmedBack;
878
614
  });
879
- const requestBack = useCallback3(() => {
615
+ const requestBack = useCallback(() => {
880
616
  if (hasProgressRef.current()) setConfirmVisible(true);
881
617
  else onConfirmedBackRef.current();
882
618
  }, []);
883
- const cancelBack = useCallback3(() => setConfirmVisible(false), []);
619
+ const cancelBack = useCallback(() => setConfirmVisible(false), []);
884
620
  return { confirmVisible, requestBack, cancelBack };
885
621
  }
886
622
  export {