@tastic/hud 0.1.0 → 0.1.2

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.
@@ -100,7 +100,15 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
100
100
  return path;
101
101
  }, [segments, litIndicesKey, transitionFromKey, singleSelect, step, startDeg, dashAngleDeg, totalDurationMs, oval.x, oval.y, oval.width, oval.height]);
102
102
  if (segments < 2) return null;
103
- return /* @__PURE__ */ jsx(View, { style: [styles.container, { height: size, width: size }], pointerEvents: "none", children: /* @__PURE__ */ jsxs(Canvas, { style: { height: canvasSize, width: canvasSize }, children: [
103
+ const gaugeSizeStyle = {
104
+ height: size,
105
+ width: size
106
+ };
107
+ const canvasSizeStyle = {
108
+ height: canvasSize,
109
+ width: canvasSize
110
+ };
111
+ return /* @__PURE__ */ jsx(View, { style: [styles.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ jsxs(Canvas, { style: canvasSizeStyle, children: [
104
112
  /* @__PURE__ */ jsx(Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
105
113
  /* @__PURE__ */ jsx(Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
106
114
  ] }) });
package/dist/index.js CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __esm = (fn, res) => function __init() {
9
7
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -20,14 +18,6 @@ var __copyProps = (to, from, except, desc) => {
20
18
  }
21
19
  return to;
22
20
  };
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
- // If the importer is in node compatibility mode or this is not an ESM
25
- // file that has been converted to a CommonJS file using a Babel-
26
- // compatible transform (i.e. "__esModule" has not been set), then set
27
- // "default" to the CommonJS "module.exports" for node compatibility.
28
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
- mod
30
- ));
31
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
22
 
33
23
  // src/TriggerGauge.tsx
@@ -122,18 +112,26 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
122
112
  return path;
123
113
  }, [segments, litIndicesKey, transitionFromKey, singleSelect, step, startDeg, dashAngleDeg, totalDurationMs, oval.x, oval.y, oval.width, oval.height]);
124
114
  if (segments < 2) return null;
125
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native8.View, { style: [styles4.container, { height: size, width: size }], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native_skia.Canvas, { style: { height: canvasSize, width: canvasSize }, children: [
115
+ const gaugeSizeStyle = {
116
+ height: size,
117
+ width: size
118
+ };
119
+ const canvasSizeStyle = {
120
+ height: canvasSize,
121
+ width: canvasSize
122
+ };
123
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native7.View, { style: [styles4.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
126
124
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
127
125
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
128
126
  ] }) });
129
127
  }
130
- var import_react_native_skia, import_react2, import_react_native8, import_react_native_reanimated, import_jsx_runtime5, 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, styles4;
128
+ var import_react_native_skia, import_react2, import_react_native7, import_react_native_reanimated, import_jsx_runtime5, 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, styles4;
131
129
  var init_TriggerGauge = __esm({
132
130
  "src/TriggerGauge.tsx"() {
133
131
  "use strict";
134
132
  import_react_native_skia = require("@shopify/react-native-skia");
135
133
  import_react2 = require("react");
136
- import_react_native8 = require("react-native");
134
+ import_react_native7 = require("react-native");
137
135
  import_react_native_reanimated = require("react-native-reanimated");
138
136
  import_jsx_runtime5 = require("react/jsx-runtime");
139
137
  UNLIT_THICKNESS = 3;
@@ -145,7 +143,7 @@ var init_TriggerGauge = __esm({
145
143
  MOUNT_DURATION_MS = 450;
146
144
  MOUNT_STAGGER_MS = 40;
147
145
  SELECTION_TRANSITION_DURATION_MS = 260;
148
- styles4 = import_react_native8.StyleSheet.create({
146
+ styles4 = import_react_native7.StyleSheet.create({
149
147
  container: {
150
148
  alignItems: "center",
151
149
  justifyContent: "center",
@@ -398,29 +396,30 @@ var styles2 = import_react_native4.StyleSheet.create({
398
396
  });
399
397
 
400
398
  // src/loadSkiaWeb.ts
401
- var import_react_native5 = require("react-native");
402
399
  function loadSkiaWeb() {
403
- if (import_react_native5.Platform.OS !== "web") return Promise.resolve();
404
- return import("@shopify/react-native-skia/src/web").then((m) => m.LoadSkiaWeb());
400
+ return Promise.resolve();
405
401
  }
406
402
 
407
403
  // src/PressAwayOverlay.tsx
408
- var import_react_native6 = require("react-native");
404
+ var import_react_native5 = require("react-native");
409
405
  var import_jsx_runtime3 = require("react/jsx-runtime");
410
406
  function PressAwayOverlay({ active, onPress, style }) {
411
407
  if (!active) return null;
412
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native6.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native6.StyleSheet.absoluteFill, style] });
408
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native5.StyleSheet.absoluteFill, style] });
413
409
  }
414
410
 
415
411
  // src/ReadyButton.tsx
416
412
  var import_feedback_press2 = require("@rific/feedback-press");
417
- var import_react_native7 = require("react-native");
413
+ var import_react_native6 = require("react-native");
418
414
  var import_react_native_paper2 = require("react-native-paper");
419
415
  var import_jsx_runtime4 = require("react/jsx-runtime");
420
416
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
421
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press2.TouchableRipple, { onPress: onToggleReady, borderless: true, style: [styles3.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { variant: "labelLarge", style: [{ fontFamily: labelFontFamily, fontWeight: "bold" }, { color: ready ? "#000000" : color }], children: ready ? "READY \u2713" : "READY?" }) });
417
+ const readyButtonStyle = [styles3.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
418
+ const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
419
+ const labelColorStyle = { color: ready ? "#000000" : color };
420
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press2.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
422
421
  }
423
- var styles3 = import_react_native7.StyleSheet.create({
422
+ var styles3 = import_react_native6.StyleSheet.create({
424
423
  readyButton: {
425
424
  alignItems: "center",
426
425
  borderRadius: 12,
@@ -435,7 +434,7 @@ var styles3 = import_react_native7.StyleSheet.create({
435
434
  // src/SectionedDropdown.tsx
436
435
  var import_auto_paper2 = require("@rific/auto-paper");
437
436
  var import_feedback_press3 = require("@rific/feedback-press");
438
- var import_react_native9 = require("react-native");
437
+ var import_react_native8 = require("react-native");
439
438
  var import_react_native_paper3 = require("react-native-paper");
440
439
 
441
440
  // src/TriggerGaugeHost.tsx
@@ -493,13 +492,16 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
493
492
  }
494
493
  gaugeOffset += section.options.length;
495
494
  }
496
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: [styles5.anchor, open && styles5.anchorOpen], children: [
497
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { ref: triggerRef, collapsable: false, style: styles5.triggerBox, children: [
495
+ const anchorStyle = [styles5.anchor, open && styles5.anchorOpen];
496
+ const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
497
+ const dividerStyle = { backgroundColor: menuBorderColor };
498
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: anchorStyle, children: [
499
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { ref: triggerRef, collapsable: false, style: styles5.triggerBox, children: [
498
500
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
499
501
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
500
502
  ] }),
501
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.ScrollView, { style: [styles5.menu, { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight }], contentContainerStyle: styles5.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { children: [
502
- sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native9.View, { style: [styles5.divider, { backgroundColor: menuBorderColor }] }),
503
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.ScrollView, { style: [styles5.menu, menuStyle], contentContainerStyle: styles5.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { children: [
504
+ sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [styles5.divider, dividerStyle] }),
503
505
  section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
504
506
  SingleSection,
505
507
  {
@@ -528,11 +530,14 @@ function SingleSection({
528
530
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: section.options.map((option) => {
529
531
  const selected = option.value === section.value;
530
532
  const rowColor = selected ? onAccentColor : mutedColor;
531
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => onSelect(option.value), style: [styles5.item, selected && { backgroundColor: accentColor }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: styles5.itemRow, children: [
533
+ const itemStyle = [styles5.item, selected && { backgroundColor: accentColor }];
534
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
535
+ const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
536
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles5.itemRow, children: [
532
537
  option.icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
533
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: styles5.itemLabelColumn, children: [
534
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: [{ fontFamily: labelFontFamily }, { color: rowColor, fontWeight: selected ? "bold" : "normal" }], children: option.label }),
535
- option.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelSmall", style: [{ fontFamily: labelFontFamily }, { color: rowColor }], children: option.description })
538
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles5.itemLabelColumn, children: [
539
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
540
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
536
541
  ] })
537
542
  ] }) }, option.value);
538
543
  }) });
@@ -552,15 +557,17 @@ function MultiSection({
552
557
  const rowColor = selected ? onAccentColor : mutedColor;
553
558
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
554
559
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
555
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: [styles5.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }], children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native9.View, { style: styles5.itemRow, children: [
560
+ const itemStyle = [styles5.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
561
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
562
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles5.itemRow, children: [
556
563
  option.icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
557
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: [styles5.itemLabelFlex, { fontFamily: labelFontFamily }, { color: rowColor, fontWeight: selected ? "bold" : "normal" }], children: option.label })
564
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: [styles5.itemLabelFlex, labelStyle], children: option.label })
558
565
  ] }) }, option.value);
559
566
  }),
560
567
  section.allClear && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles5.item, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: [styles5.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
561
568
  ] });
562
569
  }
563
- var styles5 = import_react_native9.StyleSheet.create({
570
+ var styles5 = import_react_native8.StyleSheet.create({
564
571
  allClearLabel: {
565
572
  fontWeight: "bold",
566
573
  textAlign: "center"
@@ -577,7 +584,7 @@ var styles5 = import_react_native9.StyleSheet.create({
577
584
  zIndex: 100
578
585
  },
579
586
  divider: {
580
- height: import_react_native9.StyleSheet.hairlineWidth,
587
+ height: import_react_native8.StyleSheet.hairlineWidth,
581
588
  marginVertical: 4
582
589
  },
583
590
  item: {
package/dist/index.mjs CHANGED
@@ -225,10 +225,8 @@ var styles2 = StyleSheet2.create({
225
225
  });
226
226
 
227
227
  // src/loadSkiaWeb.ts
228
- import { Platform as Platform2 } from "react-native";
229
228
  function loadSkiaWeb() {
230
- if (Platform2.OS !== "web") return Promise.resolve();
231
- return import("@shopify/react-native-skia/src/web").then((m) => m.LoadSkiaWeb());
229
+ return Promise.resolve();
232
230
  }
233
231
 
234
232
  // src/PressAwayOverlay.tsx
@@ -245,7 +243,10 @@ import { StyleSheet as StyleSheet4 } from "react-native";
245
243
  import { Text } from "react-native-paper";
246
244
  import { jsx as jsx4 } from "react/jsx-runtime";
247
245
  function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
248
- return /* @__PURE__ */ jsx4(TouchableRipple2, { onPress: onToggleReady, borderless: true, style: [styles3.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style], children: /* @__PURE__ */ jsx4(Text, { variant: "labelLarge", style: [{ fontFamily: labelFontFamily, fontWeight: "bold" }, { color: ready ? "#000000" : color }], children: ready ? "READY \u2713" : "READY?" }) });
246
+ const readyButtonStyle = [styles3.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
247
+ const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
248
+ const labelColorStyle = { color: ready ? "#000000" : color };
249
+ return /* @__PURE__ */ jsx4(TouchableRipple2, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ jsx4(Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
249
250
  }
250
251
  var styles3 = StyleSheet4.create({
251
252
  readyButton: {
@@ -268,7 +269,7 @@ import { Icon as Icon2, Text as Text2 } from "react-native-paper";
268
269
  // src/TriggerGaugeHost.tsx
269
270
  import { lazy, Suspense } from "react";
270
271
  import { jsx as jsx5 } from "react/jsx-runtime";
271
- var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-HIPRGEWJ.mjs").then((m) => ({ default: m.TriggerGauge }))));
272
+ var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-XBKZ3KER.mjs").then((m) => ({ default: m.TriggerGauge }))));
272
273
  function TriggerGaugeHost(props) {
273
274
  return /* @__PURE__ */ jsx5(Suspense, { fallback: null, children: /* @__PURE__ */ jsx5(LazyTriggerGauge, { ...props }) });
274
275
  }
@@ -320,13 +321,16 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
320
321
  }
321
322
  gaugeOffset += section.options.length;
322
323
  }
323
- return /* @__PURE__ */ jsxs3(View4, { style: [styles4.anchor, open && styles4.anchorOpen], children: [
324
+ const anchorStyle = [styles4.anchor, open && styles4.anchorOpen];
325
+ const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
326
+ const dividerStyle = { backgroundColor: menuBorderColor };
327
+ return /* @__PURE__ */ jsxs3(View4, { style: anchorStyle, children: [
324
328
  /* @__PURE__ */ jsxs3(View4, { ref: triggerRef, collapsable: false, style: styles4.triggerBox, children: [
325
329
  /* @__PURE__ */ jsx6(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
326
330
  /* @__PURE__ */ jsx6(IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
327
331
  ] }),
328
- /* @__PURE__ */ jsx6(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx6(ScrollView2, { style: [styles4.menu, { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight }], contentContainerStyle: styles4.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs3(View4, { children: [
329
- sectionIndex > 0 && /* @__PURE__ */ jsx6(View4, { style: [styles4.divider, { backgroundColor: menuBorderColor }] }),
332
+ /* @__PURE__ */ jsx6(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ jsx6(ScrollView2, { style: [styles4.menu, menuStyle], contentContainerStyle: styles4.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs3(View4, { children: [
333
+ sectionIndex > 0 && /* @__PURE__ */ jsx6(View4, { style: [styles4.divider, dividerStyle] }),
330
334
  section.kind === "single" ? /* @__PURE__ */ jsx6(
331
335
  SingleSection,
332
336
  {
@@ -355,11 +359,14 @@ function SingleSection({
355
359
  return /* @__PURE__ */ jsx6(Fragment2, { children: section.options.map((option) => {
356
360
  const selected = option.value === section.value;
357
361
  const rowColor = selected ? onAccentColor : mutedColor;
358
- return /* @__PURE__ */ jsx6(TouchableRipple3, { onPress: () => onSelect(option.value), style: [styles4.item, selected && { backgroundColor: accentColor }], children: /* @__PURE__ */ jsxs3(View4, { style: styles4.itemRow, children: [
362
+ const itemStyle = [styles4.item, selected && { backgroundColor: accentColor }];
363
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
364
+ const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
365
+ return /* @__PURE__ */ jsx6(TouchableRipple3, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ jsxs3(View4, { style: styles4.itemRow, children: [
359
366
  option.icon && /* @__PURE__ */ jsx6(Icon2, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
360
367
  /* @__PURE__ */ jsxs3(View4, { style: styles4.itemLabelColumn, children: [
361
- /* @__PURE__ */ jsx6(Text2, { variant: "labelLarge", style: [{ fontFamily: labelFontFamily }, { color: rowColor, fontWeight: selected ? "bold" : "normal" }], children: option.label }),
362
- option.description && /* @__PURE__ */ jsx6(Text2, { variant: "labelSmall", style: [{ fontFamily: labelFontFamily }, { color: rowColor }], children: option.description })
368
+ /* @__PURE__ */ jsx6(Text2, { variant: "labelLarge", style: labelStyle, children: option.label }),
369
+ option.description && /* @__PURE__ */ jsx6(Text2, { variant: "labelSmall", style: descriptionStyle, children: option.description })
363
370
  ] })
364
371
  ] }) }, option.value);
365
372
  }) });
@@ -379,9 +386,11 @@ function MultiSection({
379
386
  const rowColor = selected ? onAccentColor : mutedColor;
380
387
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
381
388
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
382
- return /* @__PURE__ */ jsx6(TouchableRipple3, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: [styles4.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }], children: /* @__PURE__ */ jsxs3(View4, { style: styles4.itemRow, children: [
389
+ const itemStyle = [styles4.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
390
+ const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
391
+ return /* @__PURE__ */ jsx6(TouchableRipple3, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ jsxs3(View4, { style: styles4.itemRow, children: [
383
392
  option.icon && /* @__PURE__ */ jsx6(Icon2, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
384
- /* @__PURE__ */ jsx6(Text2, { variant: "labelLarge", style: [styles4.itemLabelFlex, { fontFamily: labelFontFamily }, { color: rowColor, fontWeight: selected ? "bold" : "normal" }], children: option.label })
393
+ /* @__PURE__ */ jsx6(Text2, { variant: "labelLarge", style: [styles4.itemLabelFlex, labelStyle], children: option.label })
385
394
  ] }) }, option.value);
386
395
  }),
387
396
  section.allClear && /* @__PURE__ */ jsx6(TouchableRipple3, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles4.item, children: /* @__PURE__ */ jsx6(Text2, { variant: "labelLarge", style: [styles4.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tastic/hud",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Visual component kit for local-multiplayer React Native games: inline (non-modal) popovers, dropdowns, color pickers, gauges, ready buttons, and dialogs, built to stay scoped to one player's own zone on a shared screen",
5
5
  "keywords": [
6
6
  "react-native",
@@ -1,5 +1,5 @@
1
1
  import { TouchableRipple } from '@rific/feedback-press'
2
- import { StyleProp, StyleSheet, ViewStyle } from 'react-native'
2
+ import { StyleProp, StyleSheet, TextStyle, ViewStyle } from 'react-native'
3
3
  import { Text } from 'react-native-paper'
4
4
 
5
5
  import { MONO_FONT } from './fonts'
@@ -21,9 +21,13 @@ interface Props {
21
21
  // below a shared row — e.g. a vs-CPU mode with only one human player needs just one Ready toggle,
22
22
  // not one tucked under each slot.
23
23
  export function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }: Props) {
24
+ const readyButtonStyle = [styles.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style]
25
+ const labelTextStyle: TextStyle = { fontFamily: labelFontFamily, fontWeight: 'bold' }
26
+ const labelColorStyle = { color: ready ? '#000000' : color }
27
+
24
28
  return (
25
- <TouchableRipple onPress={onToggleReady} borderless style={[styles.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style]}>
26
- <Text variant='labelLarge' style={[{ fontFamily: labelFontFamily, fontWeight: 'bold' }, { color: ready ? '#000000' : color }]}>
29
+ <TouchableRipple onPress={onToggleReady} borderless style={readyButtonStyle}>
30
+ <Text variant='labelLarge' style={[labelTextStyle, labelColorStyle]}>
27
31
  {ready ? 'READY ✓' : 'READY?'}
28
32
  </Text>
29
33
  </TouchableRipple>
@@ -1,6 +1,6 @@
1
1
  import { getBlendedColor, getColorRoles } from '@rific/auto-paper'
2
2
  import { IconButton, TouchableRipple } from '@rific/feedback-press'
3
- import { ScrollView, StyleSheet, View } from 'react-native'
3
+ import { ScrollView, StyleSheet, TextStyle, View } from 'react-native'
4
4
  import { Icon, Text } from 'react-native-paper'
5
5
 
6
6
  import { MONO_FONT } from './fonts'
@@ -177,8 +177,12 @@ export function SectionedDropdown({ id, host, icon, accessibilityLabel, sections
177
177
  gaugeOffset += section.options.length
178
178
  }
179
179
 
180
+ const anchorStyle = [styles.anchor, open && styles.anchorOpen]
181
+ const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight }
182
+ const dividerStyle = { backgroundColor: menuBorderColor }
183
+
180
184
  return (
181
- <View style={[styles.anchor, open && styles.anchorOpen]}>
185
+ <View style={anchorStyle}>
182
186
  <View ref={triggerRef} collapsable={false} style={styles.triggerBox}>
183
187
  <TriggerGaugeHost segments={gaugeSegments} litIndices={gaugeLitIndices} size={TRIGGER_SIZE} accentColor={accentColor} mutedColor={mutedColor} />
184
188
  <IconButton icon={triggerIcon} iconColor={triggerIconColor} size={triggerIconSize} accessibilityLabel={accessibilityLabel} onPress={() => host.toggle(id)} />
@@ -194,13 +198,13 @@ export function SectionedDropdown({ id, host, icon, accessibilityLabel, sections
194
198
  is always <= maxHeight then, so nothing scrolls); on a short landscape screen where neither
195
199
  direction has enough room, this is what keeps the menu from just running off the screen
196
200
  edge instead of flipping only made it run off a *smaller* amount. */}
197
- <ScrollView style={[styles.menu, { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight }]} contentContainerStyle={styles.menuContent} showsVerticalScrollIndicator={false}>
201
+ <ScrollView style={[styles.menu, menuStyle]} contentContainerStyle={styles.menuContent} showsVerticalScrollIndicator={false}>
198
202
  {sections.map((section, sectionIndex) => (
199
203
  <View key={section.id}>
200
204
  {/* Every section after the first gets a rule above it — the divider belongs to the
201
205
  boundary between sections, not to either section itself, so it's keyed off position
202
206
  rather than each section carrying its own "divider below me" flag. */}
203
- {sectionIndex > 0 && <View style={[styles.divider, { backgroundColor: menuBorderColor }]} />}
207
+ {sectionIndex > 0 && <View style={[styles.divider, dividerStyle]} />}
204
208
 
205
209
  {section.kind === 'single' ? (
206
210
  <SingleSection
@@ -247,16 +251,19 @@ function SingleSection({
247
251
  {section.options.map((option) => {
248
252
  const selected = option.value === section.value
249
253
  const rowColor = selected ? onAccentColor : mutedColor
254
+ const itemStyle = [styles.item, selected && { backgroundColor: accentColor }]
255
+ const labelStyle: TextStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? 'bold' : 'normal' }
256
+ const descriptionStyle: TextStyle = { fontFamily: labelFontFamily, color: rowColor }
250
257
  return (
251
- <TouchableRipple key={option.value} onPress={() => onSelect(option.value)} style={[styles.item, selected && { backgroundColor: accentColor }]}>
258
+ <TouchableRipple key={option.value} onPress={() => onSelect(option.value)} style={itemStyle}>
252
259
  <View style={styles.itemRow}>
253
260
  {option.icon && <Icon source={option.icon} size={MENU_ITEM_ICON_SIZE} color={rowColor} />}
254
261
  <View style={styles.itemLabelColumn}>
255
- <Text variant='labelLarge' style={[{ fontFamily: labelFontFamily }, { color: rowColor, fontWeight: selected ? 'bold' : 'normal' }]}>
262
+ <Text variant='labelLarge' style={labelStyle}>
256
263
  {option.label}
257
264
  </Text>
258
265
  {option.description && (
259
- <Text variant='labelSmall' style={[{ fontFamily: labelFontFamily }, { color: rowColor }]}>
266
+ <Text variant='labelSmall' style={descriptionStyle}>
260
267
  {option.description}
261
268
  </Text>
262
269
  )}
@@ -299,11 +306,13 @@ function MultiSection({
299
306
  // separately-rounded pills.
300
307
  const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value)
301
308
  const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value)
309
+ const itemStyle = [styles.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }]
310
+ const labelStyle: TextStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? 'bold' : 'normal' }
302
311
  return (
303
- <TouchableRipple key={option.value} onPress={() => section.onChange(selected ? section.value.filter((v: unknown) => v !== option.value) : [...section.value, option.value])} style={[styles.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }]}>
312
+ <TouchableRipple key={option.value} onPress={() => section.onChange(selected ? section.value.filter((v: unknown) => v !== option.value) : [...section.value, option.value])} style={itemStyle}>
304
313
  <View style={styles.itemRow}>
305
314
  {option.icon && <Icon source={option.icon} size={MENU_ITEM_ICON_SIZE} color={rowColor} />}
306
- <Text variant='labelLarge' style={[styles.itemLabelFlex, { fontFamily: labelFontFamily }, { color: rowColor, fontWeight: selected ? 'bold' : 'normal' }]}>
315
+ <Text variant='labelLarge' style={[styles.itemLabelFlex, labelStyle]}>
307
316
  {option.label}
308
317
  </Text>
309
318
  </View>
@@ -266,9 +266,18 @@ export function TriggerGauge({ segments, litIndices, size, accentColor, mutedCol
266
266
 
267
267
  if (segments < 2) return null
268
268
 
269
+ const gaugeSizeStyle = {
270
+ height: size,
271
+ width: size
272
+ }
273
+ const canvasSizeStyle = {
274
+ height: canvasSize,
275
+ width: canvasSize
276
+ }
277
+
269
278
  return (
270
- <View style={[styles.container, { height: size, width: size }]} pointerEvents='none'>
271
- <Canvas style={{ height: canvasSize, width: canvasSize }}>
279
+ <View style={[styles.container, gaugeSizeStyle]} pointerEvents='none'>
280
+ <Canvas style={canvasSizeStyle}>
272
281
  <Path path={unlitPath} style='stroke' strokeWidth={UNLIT_THICKNESS} strokeCap='round' color={mutedColor} opacity={0.35} />
273
282
  <Path path={litPath} style='stroke' strokeWidth={LIT_THICKNESS} strokeCap='round' color={accentColor} opacity={1} />
274
283
  </Canvas>
@@ -11,10 +11,9 @@ import { TriggerGaugeProps } from './TriggerGauge'
11
11
  // file therefore never imports TriggerGauge itself except as a type (erased at compile time,
12
12
  // carrying no runtime module reference) — `lazy()` is what actually defers the real import to
13
13
  // runtime, after loadSkiaWeb() resolves. Always lazy, on every platform, rather than a native/web
14
- // branch here: this package builds to a single bundled dist file (see loadSkiaWeb's own comment on
15
- // why), so there's no reliable build-time way to give native a plain, non-lazy passthrough instead —
16
- // loadSkiaWeb() itself already resolves immediately on native, so the Suspense boundary there just
17
- // clears on the next tick, not a perceptible delay. The Suspense fallback renders nothing, so a
14
+ // branch here, purely to keep this file simple loadSkiaWeb() itself already resolves immediately
15
+ // on native (see its own file split), so the Suspense boundary there just clears on the next tick,
16
+ // not a perceptible delay. The Suspense fallback renders nothing, so a
18
17
  // consumer's trigger icon still shows immediately and the gauge ring just pops in a beat later.
19
18
  const LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import('./TriggerGauge').then((m) => ({ default: m.TriggerGauge }))))
20
19
 
@@ -1,14 +1,10 @@
1
- import { Platform } from 'react-native'
2
-
3
- // Skia's web target renders through CanvasKit, a WASM build of Skia fetched at runtime — nothing
4
- // using @shopify/react-native-skia's React components can draw a single frame until this resolves.
5
- // Skia on native (via JSI) is ready as soon as the app's native module is linked, so this only
6
- // actually does anything on web a Platform.OS check rather than a `.web.ts` sibling file, since
7
- // this package builds to a single bundled dist file (see package.json's `build` script): a bundler
8
- // that pre-flattens the whole module graph itself (tsup/esbuild) never sees or swaps in a `.web.ts`
9
- // variant the way a consuming app's own Metro bundler would, so the split has to be a runtime
10
- // branch that survives being bundled, not a build-time file choice that wouldn't.
1
+ // Native counterpart to loadSkiaWeb.web.ts — Skia on native (via JSI, no WASM) is ready as soon as
2
+ // the app's native module is linked, so there's nothing to actually wait on here. This file must
3
+ // never import '@shopify/react-native-skia/src/web' (even conditionally behind a Platform.OS check):
4
+ // that module pulls in canvaskit-wasm, which does `require('fs')` a runtime check doesn't stop
5
+ // Metro from statically resolving that import to build the native bundle graph, and Metro has no
6
+ // `fs` for iOS/Android, so the build fails outright. Metro's own platform-extension resolution (this
7
+ // file vs. loadSkiaWeb.web.ts) is what actually keeps the web-only module out of the native graph.
11
8
  export function loadSkiaWeb(): Promise<void> {
12
- if (Platform.OS !== 'web') return Promise.resolve()
13
- return import('@shopify/react-native-skia/src/web').then((m) => m.LoadSkiaWeb())
9
+ return Promise.resolve()
14
10
  }
@@ -0,0 +1,11 @@
1
+ import { LoadSkiaWeb } from '@shopify/react-native-skia/src/web'
2
+
3
+ // Skia's web target renders through CanvasKit, a WASM build of Skia fetched at runtime — nothing
4
+ // using @shopify/react-native-skia's React components can draw a single frame until this resolves.
5
+ // Kept as a thin wrapper (rather than importing LoadSkiaWeb directly at call sites) purely so this
6
+ // file's `.ts` counterpart, loadSkiaWeb.ts, gives native an identically-shaped async no-op — Metro's
7
+ // platform-extension resolution picks whichever one matches the bundle target, so canvaskit-wasm's
8
+ // `require('fs')' never even gets resolved into a native/iOS/Android bundle.
9
+ export function loadSkiaWeb(): Promise<void> {
10
+ return LoadSkiaWeb()
11
+ }