@tastic/hud 0.1.1 → 0.1.3
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/{TriggerGauge-XBKZ3KER.mjs → TriggerGauge-2OJOOF6I.mjs} +3 -2
- package/dist/index.js +24 -34
- package/dist/index.mjs +4 -5
- package/package.json +4 -1
- package/src/InlineColorPicker.tsx +2 -1
- package/src/TriggerGauge.tsx +3 -2
- package/src/TriggerGaugeHost.tsx +3 -4
- package/src/loadSkiaWeb.ts +8 -12
- package/src/loadSkiaWeb.web.ts +11 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/TriggerGauge.tsx
|
|
2
2
|
import { Canvas, Path, Skia } from "@shopify/react-native-skia";
|
|
3
|
+
import { clamp } from "@tastic/core";
|
|
3
4
|
import { useCallback, useLayoutEffect, useRef, useState } from "react";
|
|
4
5
|
import { StyleSheet, View } from "react-native";
|
|
5
6
|
import { Easing, useDerivedValue, useSharedValue, withTiming } from "react-native-reanimated";
|
|
@@ -60,7 +61,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
60
61
|
if (mountProgress.value < 1) {
|
|
61
62
|
const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
|
|
62
63
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
|
|
63
|
-
local =
|
|
64
|
+
local = clamp((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
|
|
64
65
|
}
|
|
65
66
|
const sweep = dashAngleDeg * local;
|
|
66
67
|
if (sweep <= 0) continue;
|
|
@@ -84,7 +85,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
84
85
|
if (!isLitNow) continue;
|
|
85
86
|
const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
|
|
86
87
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
|
|
87
|
-
local =
|
|
88
|
+
local = clamp((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
|
|
88
89
|
} else if (isLitNow === wasLit) {
|
|
89
90
|
local = 1;
|
|
90
91
|
} else if (isLitNow) {
|
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
|
|
@@ -82,7 +72,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
82
72
|
if (mountProgress.value < 1) {
|
|
83
73
|
const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
|
|
84
74
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
|
|
85
|
-
local =
|
|
75
|
+
local = (0, import_core2.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
|
|
86
76
|
}
|
|
87
77
|
const sweep = dashAngleDeg * local;
|
|
88
78
|
if (sweep <= 0) continue;
|
|
@@ -106,7 +96,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
106
96
|
if (!isLitNow) continue;
|
|
107
97
|
const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
|
|
108
98
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
|
|
109
|
-
local =
|
|
99
|
+
local = (0, import_core2.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
|
|
110
100
|
} else if (isLitNow === wasLit) {
|
|
111
101
|
local = 1;
|
|
112
102
|
} else if (isLitNow) {
|
|
@@ -130,18 +120,19 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
130
120
|
height: canvasSize,
|
|
131
121
|
width: canvasSize
|
|
132
122
|
};
|
|
133
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
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: [
|
|
134
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 }),
|
|
135
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 })
|
|
136
126
|
] }) });
|
|
137
127
|
}
|
|
138
|
-
var import_react_native_skia, import_react2,
|
|
128
|
+
var import_react_native_skia, import_core2, 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;
|
|
139
129
|
var init_TriggerGauge = __esm({
|
|
140
130
|
"src/TriggerGauge.tsx"() {
|
|
141
131
|
"use strict";
|
|
142
132
|
import_react_native_skia = require("@shopify/react-native-skia");
|
|
133
|
+
import_core2 = require("@tastic/core");
|
|
143
134
|
import_react2 = require("react");
|
|
144
|
-
|
|
135
|
+
import_react_native7 = require("react-native");
|
|
145
136
|
import_react_native_reanimated = require("react-native-reanimated");
|
|
146
137
|
import_jsx_runtime5 = require("react/jsx-runtime");
|
|
147
138
|
UNLIT_THICKNESS = 3;
|
|
@@ -153,7 +144,7 @@ var init_TriggerGauge = __esm({
|
|
|
153
144
|
MOUNT_DURATION_MS = 450;
|
|
154
145
|
MOUNT_STAGGER_MS = 40;
|
|
155
146
|
SELECTION_TRANSITION_DURATION_MS = 260;
|
|
156
|
-
styles4 =
|
|
147
|
+
styles4 = import_react_native7.StyleSheet.create({
|
|
157
148
|
container: {
|
|
158
149
|
alignItems: "center",
|
|
159
150
|
justifyContent: "center",
|
|
@@ -186,6 +177,7 @@ var MONO_FONT = import_react_native.Platform.select({ ios: "Menlo", android: "mo
|
|
|
186
177
|
// src/InlineColorPicker.tsx
|
|
187
178
|
var import_auto_paper = require("@rific/auto-paper");
|
|
188
179
|
var import_feedback_press = require("@rific/feedback-press");
|
|
180
|
+
var import_core = require("@tastic/core");
|
|
189
181
|
var import_react_native4 = require("react-native");
|
|
190
182
|
var import_react_native_paper = require("react-native-paper");
|
|
191
183
|
|
|
@@ -309,7 +301,7 @@ function widthForColumns(columns) {
|
|
|
309
301
|
function InlineColorPicker({ id, host, value, onChange, swatches = import_auto_paper.defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = "palette", autoDismiss = true, columns }) {
|
|
310
302
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
311
303
|
const { width: windowWidth } = (0, import_react_native4.useWindowDimensions)();
|
|
312
|
-
const autoColumns =
|
|
304
|
+
const autoColumns = (0, import_core.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
|
|
313
305
|
const resolvedColumns = columns ?? autoColumns;
|
|
314
306
|
const swatchesWidth = widthForColumns(resolvedColumns);
|
|
315
307
|
const swatchRows = Math.ceil(swatches.length / resolvedColumns);
|
|
@@ -406,23 +398,21 @@ var styles2 = import_react_native4.StyleSheet.create({
|
|
|
406
398
|
});
|
|
407
399
|
|
|
408
400
|
// src/loadSkiaWeb.ts
|
|
409
|
-
var import_react_native5 = require("react-native");
|
|
410
401
|
function loadSkiaWeb() {
|
|
411
|
-
|
|
412
|
-
return import("@shopify/react-native-skia/src/web").then((m) => m.LoadSkiaWeb());
|
|
402
|
+
return Promise.resolve();
|
|
413
403
|
}
|
|
414
404
|
|
|
415
405
|
// src/PressAwayOverlay.tsx
|
|
416
|
-
var
|
|
406
|
+
var import_react_native5 = require("react-native");
|
|
417
407
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
418
408
|
function PressAwayOverlay({ active, onPress, style }) {
|
|
419
409
|
if (!active) return null;
|
|
420
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
410
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native5.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native5.StyleSheet.absoluteFill, style] });
|
|
421
411
|
}
|
|
422
412
|
|
|
423
413
|
// src/ReadyButton.tsx
|
|
424
414
|
var import_feedback_press2 = require("@rific/feedback-press");
|
|
425
|
-
var
|
|
415
|
+
var import_react_native6 = require("react-native");
|
|
426
416
|
var import_react_native_paper2 = require("react-native-paper");
|
|
427
417
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
428
418
|
function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
|
|
@@ -431,7 +421,7 @@ function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MON
|
|
|
431
421
|
const labelColorStyle = { color: ready ? "#000000" : color };
|
|
432
422
|
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?" }) });
|
|
433
423
|
}
|
|
434
|
-
var styles3 =
|
|
424
|
+
var styles3 = import_react_native6.StyleSheet.create({
|
|
435
425
|
readyButton: {
|
|
436
426
|
alignItems: "center",
|
|
437
427
|
borderRadius: 12,
|
|
@@ -446,7 +436,7 @@ var styles3 = import_react_native7.StyleSheet.create({
|
|
|
446
436
|
// src/SectionedDropdown.tsx
|
|
447
437
|
var import_auto_paper2 = require("@rific/auto-paper");
|
|
448
438
|
var import_feedback_press3 = require("@rific/feedback-press");
|
|
449
|
-
var
|
|
439
|
+
var import_react_native8 = require("react-native");
|
|
450
440
|
var import_react_native_paper3 = require("react-native-paper");
|
|
451
441
|
|
|
452
442
|
// src/TriggerGaugeHost.tsx
|
|
@@ -507,13 +497,13 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
|
|
|
507
497
|
const anchorStyle = [styles5.anchor, open && styles5.anchorOpen];
|
|
508
498
|
const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
|
|
509
499
|
const dividerStyle = { backgroundColor: menuBorderColor };
|
|
510
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
511
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: anchorStyle, children: [
|
|
501
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { ref: triggerRef, collapsable: false, style: styles5.triggerBox, children: [
|
|
512
502
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
|
|
513
503
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
|
|
514
504
|
] }),
|
|
515
|
-
/* @__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)(
|
|
516
|
-
sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
505
|
+
/* @__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: [
|
|
506
|
+
sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native8.View, { style: [styles5.divider, dividerStyle] }),
|
|
517
507
|
section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
518
508
|
SingleSection,
|
|
519
509
|
{
|
|
@@ -545,9 +535,9 @@ function SingleSection({
|
|
|
545
535
|
const itemStyle = [styles5.item, selected && { backgroundColor: accentColor }];
|
|
546
536
|
const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
|
|
547
537
|
const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
|
|
548
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
538
|
+
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: [
|
|
549
539
|
option.icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
|
|
550
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
540
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react_native8.View, { style: styles5.itemLabelColumn, children: [
|
|
551
541
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
|
|
552
542
|
option.description && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
|
|
553
543
|
] })
|
|
@@ -571,7 +561,7 @@ function MultiSection({
|
|
|
571
561
|
const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
|
|
572
562
|
const itemStyle = [styles5.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
|
|
573
563
|
const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
|
|
574
|
-
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)(
|
|
564
|
+
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: [
|
|
575
565
|
option.icon && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
|
|
576
566
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper3.Text, { variant: "labelLarge", style: [styles5.itemLabelFlex, labelStyle], children: option.label })
|
|
577
567
|
] }) }, option.value);
|
|
@@ -579,7 +569,7 @@ function MultiSection({
|
|
|
579
569
|
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 }) })
|
|
580
570
|
] });
|
|
581
571
|
}
|
|
582
|
-
var styles5 =
|
|
572
|
+
var styles5 = import_react_native8.StyleSheet.create({
|
|
583
573
|
allClearLabel: {
|
|
584
574
|
fontWeight: "bold",
|
|
585
575
|
textAlign: "center"
|
|
@@ -596,7 +586,7 @@ var styles5 = import_react_native9.StyleSheet.create({
|
|
|
596
586
|
zIndex: 100
|
|
597
587
|
},
|
|
598
588
|
divider: {
|
|
599
|
-
height:
|
|
589
|
+
height: import_react_native8.StyleSheet.hairlineWidth,
|
|
600
590
|
marginVertical: 4
|
|
601
591
|
},
|
|
602
592
|
item: {
|
package/dist/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ var MONO_FONT = Platform.select({ ios: "Menlo", android: "monospace", default: "
|
|
|
5
5
|
// src/InlineColorPicker.tsx
|
|
6
6
|
import { defaultColors, getContrastColor } from "@rific/auto-paper";
|
|
7
7
|
import { TouchableRipple } from "@rific/feedback-press";
|
|
8
|
+
import { clamp } from "@tastic/core";
|
|
8
9
|
import { ScrollView, StyleSheet as StyleSheet2, useWindowDimensions as useWindowDimensions2, View as View3 } from "react-native";
|
|
9
10
|
import { Icon } from "react-native-paper";
|
|
10
11
|
|
|
@@ -128,7 +129,7 @@ function widthForColumns(columns) {
|
|
|
128
129
|
function InlineColorPicker({ id, host, value, onChange, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = "palette", autoDismiss = true, columns }) {
|
|
129
130
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
130
131
|
const { width: windowWidth } = useWindowDimensions2();
|
|
131
|
-
const autoColumns =
|
|
132
|
+
const autoColumns = clamp(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
|
|
132
133
|
const resolvedColumns = columns ?? autoColumns;
|
|
133
134
|
const swatchesWidth = widthForColumns(resolvedColumns);
|
|
134
135
|
const swatchRows = Math.ceil(swatches.length / resolvedColumns);
|
|
@@ -225,10 +226,8 @@ var styles2 = StyleSheet2.create({
|
|
|
225
226
|
});
|
|
226
227
|
|
|
227
228
|
// src/loadSkiaWeb.ts
|
|
228
|
-
import { Platform as Platform2 } from "react-native";
|
|
229
229
|
function loadSkiaWeb() {
|
|
230
|
-
|
|
231
|
-
return import("@shopify/react-native-skia/src/web").then((m) => m.LoadSkiaWeb());
|
|
230
|
+
return Promise.resolve();
|
|
232
231
|
}
|
|
233
232
|
|
|
234
233
|
// src/PressAwayOverlay.tsx
|
|
@@ -271,7 +270,7 @@ import { Icon as Icon2, Text as Text2 } from "react-native-paper";
|
|
|
271
270
|
// src/TriggerGaugeHost.tsx
|
|
272
271
|
import { lazy, Suspense } from "react";
|
|
273
272
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
274
|
-
var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-
|
|
273
|
+
var LazyTriggerGauge = lazy(() => loadSkiaWeb().then(() => import("./TriggerGauge-2OJOOF6I.mjs").then((m) => ({ default: m.TriggerGauge }))));
|
|
275
274
|
function TriggerGaugeHost(props) {
|
|
276
275
|
return /* @__PURE__ */ jsx5(Suspense, { fallback: null, children: /* @__PURE__ */ jsx5(LazyTriggerGauge, { ...props }) });
|
|
277
276
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tastic/hud",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
31
|
"react-native": "./src/index.ts",
|
|
32
|
+
"browser": "./src/index.ts",
|
|
32
33
|
"types": "./dist/index.d.ts",
|
|
33
34
|
"import": "./dist/index.mjs",
|
|
34
35
|
"require": "./dist/index.js"
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"@rific/auto-paper": "^0.9.4",
|
|
64
65
|
"@rific/feedback-press": "^0.10.4",
|
|
65
66
|
"@shopify/react-native-skia": "^2.6.2",
|
|
67
|
+
"@tastic/core": "^0.1.2",
|
|
66
68
|
"@testing-library/dom": "^10.4.1",
|
|
67
69
|
"@testing-library/react": "^16.3.2",
|
|
68
70
|
"@types/jest": "^30.0.0",
|
|
@@ -92,6 +94,7 @@
|
|
|
92
94
|
"@rific/auto-paper": ">=0.9.0",
|
|
93
95
|
"@rific/feedback-press": ">=0.10.0",
|
|
94
96
|
"@shopify/react-native-skia": ">=1.5.0",
|
|
97
|
+
"@tastic/core": ">=0.1.0",
|
|
95
98
|
"react": ">=19.0.0",
|
|
96
99
|
"react-native": ">=0.76.0",
|
|
97
100
|
"react-native-paper": ">=5.0.0",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { defaultColors, getContrastColor, SeedColor } from '@rific/auto-paper'
|
|
2
2
|
import { TouchableRipple } from '@rific/feedback-press'
|
|
3
|
+
import { clamp } from '@tastic/core'
|
|
3
4
|
import { ScrollView, StyleSheet, useWindowDimensions, View } from 'react-native'
|
|
4
5
|
import { Icon } from 'react-native-paper'
|
|
5
6
|
|
|
@@ -63,7 +64,7 @@ interface Props {
|
|
|
63
64
|
export function InlineColorPicker({ id, host, value, onChange, swatches = defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = 'palette', autoDismiss = true, columns }: Props) {
|
|
64
65
|
const menuBg = dark ? '#000000' : '#FFFFFF'
|
|
65
66
|
const { width: windowWidth } = useWindowDimensions()
|
|
66
|
-
const autoColumns =
|
|
67
|
+
const autoColumns = clamp(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS)
|
|
67
68
|
const resolvedColumns = columns ?? autoColumns
|
|
68
69
|
const swatchesWidth = widthForColumns(resolvedColumns)
|
|
69
70
|
const swatchRows = Math.ceil(swatches.length / resolvedColumns)
|
package/src/TriggerGauge.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Canvas, Path, Skia } from '@shopify/react-native-skia'
|
|
2
|
+
import { clamp } from '@tastic/core'
|
|
2
3
|
import { useCallback, useLayoutEffect, useRef, useState } from 'react'
|
|
3
4
|
import { StyleSheet, View } from 'react-native'
|
|
4
5
|
import { Easing, useDerivedValue, useSharedValue, withTiming } from 'react-native-reanimated'
|
|
@@ -207,7 +208,7 @@ export function TriggerGauge({ segments, litIndices, size, accentColor, mutedCol
|
|
|
207
208
|
if (mountProgress.value < 1) {
|
|
208
209
|
const startFrac = (i * MOUNT_STAGGER_MS) / totalDurationMs
|
|
209
210
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs
|
|
210
|
-
local =
|
|
211
|
+
local = clamp((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1)
|
|
211
212
|
}
|
|
212
213
|
const sweep = dashAngleDeg * local
|
|
213
214
|
if (sweep <= 0) continue
|
|
@@ -245,7 +246,7 @@ export function TriggerGauge({ segments, litIndices, size, accentColor, mutedCol
|
|
|
245
246
|
if (!isLitNow) continue
|
|
246
247
|
const startFrac = (i * MOUNT_STAGGER_MS) / totalDurationMs
|
|
247
248
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs
|
|
248
|
-
local =
|
|
249
|
+
local = clamp((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1)
|
|
249
250
|
} else if (isLitNow === wasLit) {
|
|
250
251
|
local = 1 // steady — lit before and after (or the mount-only branch above already handled unlit)
|
|
251
252
|
} else if (isLitNow) {
|
package/src/TriggerGaugeHost.tsx
CHANGED
|
@@ -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
|
|
15
|
-
//
|
|
16
|
-
//
|
|
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
|
|
package/src/loadSkiaWeb.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
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
|
-
|
|
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
|
+
}
|