@tastic/hud 0.1.6 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +91 -23
- package/dist/index.d.ts +91 -23
- package/dist/index.js +463 -105
- package/dist/index.mjs +423 -71
- package/package.json +3 -1
- package/src/BaseSettingsDialog.tsx +371 -0
- package/src/CornerActionButtons.tsx +39 -0
- package/src/LabeledDropdown.tsx +175 -0
- package/src/SharedActionBand.tsx +61 -0
- package/src/index.ts +4 -0
package/dist/index.js
CHANGED
|
@@ -28,22 +28,22 @@ __export(TriggerGauge_exports, {
|
|
|
28
28
|
function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, dashWidth, startDeg = DEFAULT_START_DEG, endDeg = startDeg }) {
|
|
29
29
|
const totalDurationMs = MOUNT_DURATION_MS + Math.max(0, segments - 1) * MOUNT_STAGGER_MS;
|
|
30
30
|
const mountProgress = (0, import_react_native_reanimated.useSharedValue)(0);
|
|
31
|
-
(0,
|
|
31
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
32
32
|
mountProgress.value = (0, import_react_native_reanimated.withTiming)(1, { duration: totalDurationMs, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
|
|
33
33
|
}, []);
|
|
34
34
|
const rawSweepDeg = ((endDeg - startDeg) % 360 + 360) % 360;
|
|
35
35
|
const totalSweepDeg = rawSweepDeg === 0 ? 360 : rawSweepDeg;
|
|
36
36
|
const step = segments > 0 ? totalSweepDeg / segments : 0;
|
|
37
|
-
const centerDeg = (0,
|
|
37
|
+
const centerDeg = (0, import_react3.useCallback)((i) => startDeg + (i + 0.5) * step, [startDeg, step]);
|
|
38
38
|
const singleSelect = litIndices.length === 1;
|
|
39
39
|
const angleDeg = (0, import_react_native_reanimated.useSharedValue)(centerDeg(litIndices[0] ?? 0));
|
|
40
40
|
const litIndicesKey = [...litIndices].sort((a, b) => a - b).join(",");
|
|
41
|
-
const [transitionFrom, setTransitionFrom] = (0,
|
|
41
|
+
const [transitionFrom, setTransitionFrom] = (0, import_react3.useState)(litIndices);
|
|
42
42
|
const transitionFromKey = [...transitionFrom].sort((a, b) => a - b).join(",");
|
|
43
|
-
const lastKeyRef = (0,
|
|
44
|
-
const lastIndicesRef = (0,
|
|
43
|
+
const lastKeyRef = (0, import_react3.useRef)(litIndicesKey);
|
|
44
|
+
const lastIndicesRef = (0, import_react3.useRef)(litIndices);
|
|
45
45
|
const selectionProgress = (0, import_react_native_reanimated.useSharedValue)(1);
|
|
46
|
-
(0,
|
|
46
|
+
(0, import_react3.useLayoutEffect)(() => {
|
|
47
47
|
if (litIndicesKey !== lastKeyRef.current) {
|
|
48
48
|
if (singleSelect && lastIndicesRef.current.length === 1) {
|
|
49
49
|
angleDeg.value = (0, import_react_native_reanimated.withTiming)(centerDeg(litIndices[0]), { duration: SELECTION_TRANSITION_DURATION_MS, easing: import_react_native_reanimated.Easing.out(import_react_native_reanimated.Easing.cubic) });
|
|
@@ -72,7 +72,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
72
72
|
if (mountProgress.value < 1) {
|
|
73
73
|
const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
|
|
74
74
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
|
|
75
|
-
local = (0,
|
|
75
|
+
local = (0, import_core3.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
|
|
76
76
|
}
|
|
77
77
|
const sweep = dashAngleDeg * local;
|
|
78
78
|
if (sweep <= 0) continue;
|
|
@@ -96,7 +96,7 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
96
96
|
if (!isLitNow) continue;
|
|
97
97
|
const startFrac = i * MOUNT_STAGGER_MS / totalDurationMs;
|
|
98
98
|
const endFrac = startFrac + MOUNT_DURATION_MS / totalDurationMs;
|
|
99
|
-
local = (0,
|
|
99
|
+
local = (0, import_core3.clamp)((mountProgress.value - startFrac) / (endFrac - startFrac), 0, 1);
|
|
100
100
|
} else if (isLitNow === wasLit) {
|
|
101
101
|
local = 1;
|
|
102
102
|
} else if (isLitNow) {
|
|
@@ -120,21 +120,21 @@ function TriggerGauge({ segments, litIndices, size, accentColor, mutedColor, das
|
|
|
120
120
|
height: canvasSize,
|
|
121
121
|
width: canvasSize
|
|
122
122
|
};
|
|
123
|
-
return /* @__PURE__ */ (0,
|
|
124
|
-
/* @__PURE__ */ (0,
|
|
125
|
-
/* @__PURE__ */ (0,
|
|
123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native10.View, { style: [styles7.container, gaugeSizeStyle], pointerEvents: "none", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native_skia.Canvas, { style: canvasSizeStyle, children: [
|
|
124
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_skia.Path, { path: unlitPath, style: "stroke", strokeWidth: UNLIT_THICKNESS, strokeCap: "round", color: mutedColor, opacity: 0.35 }),
|
|
125
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_skia.Path, { path: litPath, style: "stroke", strokeWidth: LIT_THICKNESS, strokeCap: "round", color: accentColor, opacity: 1 })
|
|
126
126
|
] }) });
|
|
127
127
|
}
|
|
128
|
-
var import_react_native_skia,
|
|
128
|
+
var import_react_native_skia, import_core3, import_react3, import_react_native10, import_react_native_reanimated, import_jsx_runtime8, UNLIT_THICKNESS, LIT_THICKNESS, DASH_GAP_PX, ARC_GAP, DEFAULT_START_DEG, MIN_DASH_ANGLE_DEG, MOUNT_DURATION_MS, MOUNT_STAGGER_MS, SELECTION_TRANSITION_DURATION_MS, styles7;
|
|
129
129
|
var init_TriggerGauge = __esm({
|
|
130
130
|
"src/TriggerGauge.tsx"() {
|
|
131
131
|
"use strict";
|
|
132
132
|
import_react_native_skia = require("@shopify/react-native-skia");
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
import_core3 = require("@tastic/core");
|
|
134
|
+
import_react3 = require("react");
|
|
135
|
+
import_react_native10 = require("react-native");
|
|
136
136
|
import_react_native_reanimated = require("react-native-reanimated");
|
|
137
|
-
|
|
137
|
+
import_jsx_runtime8 = require("react/jsx-runtime");
|
|
138
138
|
UNLIT_THICKNESS = 3;
|
|
139
139
|
LIT_THICKNESS = 7;
|
|
140
140
|
DASH_GAP_PX = 9;
|
|
@@ -144,7 +144,7 @@ var init_TriggerGauge = __esm({
|
|
|
144
144
|
MOUNT_DURATION_MS = 450;
|
|
145
145
|
MOUNT_STAGGER_MS = 40;
|
|
146
146
|
SELECTION_TRANSITION_DURATION_MS = 260;
|
|
147
|
-
|
|
147
|
+
styles7 = import_react_native10.StyleSheet.create({
|
|
148
148
|
container: {
|
|
149
149
|
alignItems: "center",
|
|
150
150
|
justifyContent: "center",
|
|
@@ -157,55 +157,282 @@ var init_TriggerGauge = __esm({
|
|
|
157
157
|
// src/index.ts
|
|
158
158
|
var index_exports = {};
|
|
159
159
|
__export(index_exports, {
|
|
160
|
+
BaseSettingsDialog: () => BaseSettingsDialog,
|
|
161
|
+
CornerActionButtons: () => CornerActionButtons,
|
|
160
162
|
InlineColorPicker: () => InlineColorPicker,
|
|
163
|
+
LABELED_DROPDOWN_POPOVER_WIDTH: () => LABELED_DROPDOWN_POPOVER_WIDTH,
|
|
164
|
+
LabeledDropdown: () => LabeledDropdown,
|
|
161
165
|
MONO_FONT: () => MONO_FONT,
|
|
162
166
|
PopoverBody: () => PopoverBody,
|
|
163
167
|
PressAwayOverlay: () => PressAwayOverlay,
|
|
164
168
|
ReadyButton: () => ReadyButton,
|
|
165
169
|
SectionedDropdown: () => SectionedDropdown,
|
|
170
|
+
SharedActionBand: () => SharedActionBand,
|
|
166
171
|
TriggerGaugeHost: () => TriggerGaugeHost,
|
|
172
|
+
getLabeledDropdownContentHeight: () => getLabeledDropdownContentHeight,
|
|
167
173
|
loadSkiaWeb: () => loadSkiaWeb,
|
|
168
174
|
useAutoAlign: () => useAutoAlign,
|
|
169
175
|
usePopoverHost: () => usePopoverHost
|
|
170
176
|
});
|
|
171
177
|
module.exports = __toCommonJS(index_exports);
|
|
172
178
|
|
|
173
|
-
// src/
|
|
174
|
-
var import_react_native = require("react-native");
|
|
175
|
-
var MONO_FONT = import_react_native.Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
176
|
-
|
|
177
|
-
// src/InlineColorPicker.tsx
|
|
179
|
+
// src/BaseSettingsDialog.tsx
|
|
178
180
|
var import_auto_paper = require("@rific/auto-paper");
|
|
179
181
|
var import_feedback_press = require("@rific/feedback-press");
|
|
182
|
+
var import_updater = require("@rific/updater");
|
|
180
183
|
var import_core = require("@tastic/core");
|
|
181
|
-
var
|
|
184
|
+
var import_react = require("react");
|
|
185
|
+
var import_react_native = require("react-native");
|
|
182
186
|
var import_react_native_paper = require("react-native-paper");
|
|
187
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
188
|
+
function SettingIcon({ source, color, containerColor }) {
|
|
189
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: [styles.iconBadge, { backgroundColor: containerColor }], children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Icon, { source, size: 18, color }) });
|
|
190
|
+
}
|
|
191
|
+
function BaseSettingsDialog({ visible, onDismiss, rotation = 0, version, lockOrientation, onLockOrientationChange, deferBottomEdgeGestures, onDeferBottomEdgeGestures, hideSound = false, hideHaptics = false, hideAppearance = false, hideUpdateCheck = false, onUpdateError, children }) {
|
|
192
|
+
const { dark, colors } = (0, import_auto_paper.useAutoPaperTheme)();
|
|
193
|
+
const isTouchPrimary = (0, import_core.useIsTouchPrimaryDevice)();
|
|
194
|
+
const { settings: hapticSettings, set: setHapticSettings } = (0, import_feedback_press.useHapticSettings)();
|
|
195
|
+
const { settings: soundSettings, set: setSoundSettings } = (0, import_feedback_press.useSoundSettings)();
|
|
196
|
+
const sound = (0, import_react.useContext)(import_feedback_press.SoundContext);
|
|
197
|
+
const { forceShort: forceHapticFeedback } = (0, import_feedback_press.useVibration)();
|
|
198
|
+
const [infoMessage, setInfoMessage] = (0, import_react.useState)(null);
|
|
199
|
+
const { check, checking, updateReady } = (0, import_updater.useUpdater)({
|
|
200
|
+
autoCheck: false,
|
|
201
|
+
autoPrompt: false,
|
|
202
|
+
onError: onUpdateError,
|
|
203
|
+
onInfo: (title, message) => setInfoMessage({ title, message })
|
|
204
|
+
});
|
|
205
|
+
const showLockOrientation = isTouchPrimary && lockOrientation !== void 0 && onLockOrientationChange !== void 0;
|
|
206
|
+
const showEdgeGuard = import_react_native.Platform.OS === "ios" && deferBottomEdgeGestures !== void 0 && onDeferBottomEdgeGestures !== void 0;
|
|
207
|
+
const showHaptics = import_react_native.Platform.OS !== "web" && !hideHaptics;
|
|
208
|
+
const showSound = !hideSound;
|
|
209
|
+
const showAppearance = !hideAppearance;
|
|
210
|
+
const showUpdateCheck = import_react_native.Platform.OS !== "web" && !hideUpdateCheck;
|
|
211
|
+
const fg = dark ? "#FFFFFF" : "#000000";
|
|
212
|
+
const cardBg = dark ? "#111111" : "#F2F2F2";
|
|
213
|
+
const cardBorder = dark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)";
|
|
214
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
215
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_auto_paper.Dialog, { visible, onDismiss, style: [styles.dialog, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
|
|
216
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_auto_paper.Dialog.Title, { children: "Settings" }),
|
|
217
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_auto_paper.Dialog.ScrollArea, { style: styles.scrollArea, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.ScrollView, { contentContainerStyle: styles.content, showsVerticalScrollIndicator: false, children: [
|
|
218
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.toggleGroup, children: [
|
|
219
|
+
showLockOrientation && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_feedback_press.TouchableRipple, { onPress: () => onLockOrientationChange(!lockOrientation), style: styles.toggleButton, accessibilityLabel: `Lock orientation ${lockOrientation ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.toggleContent, children: [
|
|
220
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingIcon, { source: lockOrientation ? "lock" : "lock-open-variant-outline", color: lockOrientation ? colors.secondary : colors.onSurfaceVariant, containerColor: lockOrientation ? colors.secondaryContainer : colors.surfaceVariant }),
|
|
221
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.flexShrink, children: [
|
|
222
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Lock Orientation" }),
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Pins the current layout" })
|
|
224
|
+
] })
|
|
225
|
+
] }) }),
|
|
226
|
+
showEdgeGuard && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_feedback_press.TouchableRipple, { onPress: () => onDeferBottomEdgeGestures(!deferBottomEdgeGestures), style: styles.toggleButton, accessibilityLabel: `Edge guard ${deferBottomEdgeGestures ? "on" : "off"}`, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.toggleContent, children: [
|
|
227
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingIcon, { source: deferBottomEdgeGestures ? "shield-check-outline" : "shield-off-outline", color: deferBottomEdgeGestures ? colors.secondary : colors.onSurfaceVariant, containerColor: deferBottomEdgeGestures ? colors.secondaryContainer : colors.surfaceVariant }),
|
|
228
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.flexShrink, children: [
|
|
229
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Edge Guard" }),
|
|
230
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodySmall", numberOfLines: 1, style: { color: colors.onSurfaceVariant }, children: "Requires a second swipe" })
|
|
231
|
+
] })
|
|
232
|
+
] }) }),
|
|
233
|
+
(showSound || showHaptics) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.toggleRow, children: [
|
|
234
|
+
showSound && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
235
|
+
import_feedback_press.TouchableRipple,
|
|
236
|
+
{
|
|
237
|
+
soundDisabled: true,
|
|
238
|
+
onPress: () => {
|
|
239
|
+
const enabled = !soundSettings.enabled;
|
|
240
|
+
setSoundSettings({ enabled });
|
|
241
|
+
if (enabled) sound.selection?.();
|
|
242
|
+
},
|
|
243
|
+
style: styles.toggleButtonInRow,
|
|
244
|
+
accessibilityLabel: `Sound ${soundSettings.enabled ? "on" : "off"}`,
|
|
245
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.toggleContent, children: [
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingIcon, { source: soundSettings.enabled ? "volume-high" : "volume-off", color: soundSettings.enabled ? colors.tertiary : colors.onSurfaceVariant, containerColor: soundSettings.enabled ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
247
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Sound" })
|
|
248
|
+
] })
|
|
249
|
+
}
|
|
250
|
+
),
|
|
251
|
+
showHaptics && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
252
|
+
import_feedback_press.TouchableRipple,
|
|
253
|
+
{
|
|
254
|
+
hapticDisabled: true,
|
|
255
|
+
onPress: () => {
|
|
256
|
+
const vibrate = !hapticSettings.vibrate;
|
|
257
|
+
setHapticSettings({ vibrate });
|
|
258
|
+
if (vibrate) forceHapticFeedback();
|
|
259
|
+
},
|
|
260
|
+
style: styles.toggleButtonInRow,
|
|
261
|
+
accessibilityLabel: `Haptics ${hapticSettings.vibrate ? "on" : "off"}`,
|
|
262
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.toggleContent, children: [
|
|
263
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettingIcon, { source: hapticSettings.vibrate ? "vibrate" : "vibrate-off", color: hapticSettings.vibrate ? colors.tertiary : colors.onSurfaceVariant, containerColor: hapticSettings.vibrate ? colors.tertiaryContainer : colors.surfaceVariant }),
|
|
264
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodyLarge", style: { color: colors.onSurface }, children: "Haptics" })
|
|
265
|
+
] })
|
|
266
|
+
}
|
|
267
|
+
)
|
|
268
|
+
] })
|
|
269
|
+
] }),
|
|
270
|
+
showAppearance && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.section, children: [
|
|
271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "labelMedium", style: [styles.sectionLabel, { color: colors.onSurfaceVariant }], children: "APPEARANCE" }),
|
|
272
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_auto_paper.AutoAppearancePicker, { showLabels: false })
|
|
273
|
+
] }),
|
|
274
|
+
children,
|
|
275
|
+
showUpdateCheck && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: styles.section, children: [
|
|
276
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_paper.Text, { variant: "labelSmall", style: [styles.sectionLabel, { color: colors.onSurfaceVariant }], children: [
|
|
277
|
+
"VERSION ",
|
|
278
|
+
version,
|
|
279
|
+
updateReady ? " \xB7 UPDATE READY" : ""
|
|
280
|
+
] }),
|
|
281
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_feedback_press.Button, { mode: "outlined", onPress: check, loading: checking, disabled: checking, children: "Check for Updates" })
|
|
282
|
+
] })
|
|
283
|
+
] }) })
|
|
284
|
+
] }),
|
|
285
|
+
infoMessage && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native.View, { style: styles.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native.View, { style: [styles.overlayCard, { backgroundColor: cardBg, borderColor: cardBorder }, rotation % 360 !== 0 && { transform: [{ rotate: `${rotation}deg` }] }], children: [
|
|
286
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Icon, { source: "information-outline", size: 64, color: colors.secondary }),
|
|
287
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "headlineLarge", style: [styles.overlayTitle, { color: colors.secondary }], children: infoMessage.title }),
|
|
288
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper.Text, { variant: "bodyLarge", style: [styles.overlayBody, { color: fg }], children: infoMessage.message }),
|
|
289
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_feedback_press.Button, { mode: "contained", onPress: () => setInfoMessage(null), style: styles.overlayButton, buttonColor: colors.primary, textColor: colors.onPrimary, children: "OK" })
|
|
290
|
+
] }) }) })
|
|
291
|
+
] });
|
|
292
|
+
}
|
|
293
|
+
var styles = import_react_native.StyleSheet.create({
|
|
294
|
+
content: {
|
|
295
|
+
gap: 24,
|
|
296
|
+
paddingVertical: 20
|
|
297
|
+
},
|
|
298
|
+
// Caps the card so it never grows past the screen — without this the dialog just keeps
|
|
299
|
+
// growing to fit its content and the overflow gets clipped by the screen edge, which is
|
|
300
|
+
// what happened in landscape where there's less height to work with. Dialog.ScrollArea +
|
|
301
|
+
// ScrollView below then take over and let the content scroll within that bound.
|
|
302
|
+
dialog: {
|
|
303
|
+
maxHeight: "90%"
|
|
304
|
+
},
|
|
305
|
+
flexShrink: {
|
|
306
|
+
flexShrink: 1
|
|
307
|
+
},
|
|
308
|
+
iconBadge: {
|
|
309
|
+
alignItems: "center",
|
|
310
|
+
borderRadius: 10,
|
|
311
|
+
height: 36,
|
|
312
|
+
justifyContent: "center",
|
|
313
|
+
width: 36
|
|
314
|
+
},
|
|
315
|
+
overlay: {
|
|
316
|
+
alignItems: "center",
|
|
317
|
+
backgroundColor: "rgba(0,0,0,0.72)",
|
|
318
|
+
bottom: 0,
|
|
319
|
+
justifyContent: "center",
|
|
320
|
+
left: 0,
|
|
321
|
+
position: "absolute",
|
|
322
|
+
right: 0,
|
|
323
|
+
top: 0
|
|
324
|
+
},
|
|
325
|
+
overlayBody: { textAlign: "center" },
|
|
326
|
+
overlayButton: { width: 160 },
|
|
327
|
+
overlayCard: {
|
|
328
|
+
alignItems: "center",
|
|
329
|
+
borderRadius: 20,
|
|
330
|
+
borderWidth: 1,
|
|
331
|
+
gap: 16,
|
|
332
|
+
maxWidth: 360,
|
|
333
|
+
padding: 32
|
|
334
|
+
},
|
|
335
|
+
overlayTitle: { fontWeight: "bold" },
|
|
336
|
+
scrollArea: {
|
|
337
|
+
marginBottom: 0
|
|
338
|
+
},
|
|
339
|
+
section: {
|
|
340
|
+
gap: 12
|
|
341
|
+
},
|
|
342
|
+
sectionLabel: {
|
|
343
|
+
letterSpacing: 2
|
|
344
|
+
},
|
|
345
|
+
// Negative margin cancels the padding so the icon still lines up with APPEARANCE/SOUND &
|
|
346
|
+
// HAPTICS below, while the ripple/hover highlight itself gets room to breathe on both sides
|
|
347
|
+
// instead of a flush edge-to-edge slab. overflow: 'hidden' makes sure that highlight actually
|
|
348
|
+
// clips to borderRadius instead of drawing as a plain rectangle.
|
|
349
|
+
toggleButton: {
|
|
350
|
+
borderRadius: 12,
|
|
351
|
+
marginHorizontal: -12,
|
|
352
|
+
overflow: "hidden",
|
|
353
|
+
paddingHorizontal: 12,
|
|
354
|
+
paddingVertical: 10
|
|
355
|
+
},
|
|
356
|
+
// Same shape as toggleButton but `flex: 1` instead of its own `marginHorizontal: -12` — two of
|
|
357
|
+
// these side by side in toggleRow would otherwise both pull inward and collide in the middle.
|
|
358
|
+
// toggleRow carries that edge-alignment margin once, for the row as a whole, instead.
|
|
359
|
+
toggleButtonInRow: {
|
|
360
|
+
borderRadius: 12,
|
|
361
|
+
flex: 1,
|
|
362
|
+
overflow: "hidden",
|
|
363
|
+
paddingHorizontal: 12,
|
|
364
|
+
paddingVertical: 10
|
|
365
|
+
},
|
|
366
|
+
toggleContent: {
|
|
367
|
+
alignItems: "center",
|
|
368
|
+
flexDirection: "row",
|
|
369
|
+
gap: 12
|
|
370
|
+
},
|
|
371
|
+
toggleGroup: {
|
|
372
|
+
gap: 4
|
|
373
|
+
},
|
|
374
|
+
toggleRow: {
|
|
375
|
+
flexDirection: "row",
|
|
376
|
+
gap: 4,
|
|
377
|
+
marginHorizontal: -12
|
|
378
|
+
}
|
|
379
|
+
});
|
|
183
380
|
|
|
184
|
-
// src/
|
|
381
|
+
// src/CornerActionButtons.tsx
|
|
382
|
+
var import_feedback_press2 = require("@rific/feedback-press");
|
|
185
383
|
var import_react_native2 = require("react-native");
|
|
186
|
-
var
|
|
384
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
385
|
+
function CornerActionButtons({ onBack, onSettings, fg, insets }) {
|
|
386
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press2.IconButton, { icon: "arrow-left", iconColor: fg, size: 24, style: [styles2.back, { top: 8 + insets.top, left: 8 + insets.left }], onPress: onBack, accessibilityLabel: "Back" }),
|
|
388
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_feedback_press2.IconButton, { icon: "cog", iconColor: fg, size: 24, style: [styles2.topRight, { top: 8 + insets.top, right: 8 + insets.right }], onPress: onSettings, accessibilityLabel: "Settings" })
|
|
389
|
+
] });
|
|
390
|
+
}
|
|
391
|
+
var styles2 = import_react_native2.StyleSheet.create({
|
|
392
|
+
back: {
|
|
393
|
+
position: "absolute"
|
|
394
|
+
},
|
|
395
|
+
topRight: {
|
|
396
|
+
position: "absolute"
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
// src/fonts.ts
|
|
401
|
+
var import_react_native3 = require("react-native");
|
|
402
|
+
var MONO_FONT = import_react_native3.Platform.select({ ios: "Menlo", android: "monospace", default: "monospace" });
|
|
403
|
+
|
|
404
|
+
// src/InlineColorPicker.tsx
|
|
405
|
+
var import_auto_paper2 = require("@rific/auto-paper");
|
|
406
|
+
var import_feedback_press3 = require("@rific/feedback-press");
|
|
407
|
+
var import_core2 = require("@tastic/core");
|
|
408
|
+
var import_react_native6 = require("react-native");
|
|
409
|
+
var import_react_native_paper2 = require("react-native-paper");
|
|
410
|
+
|
|
411
|
+
// src/PopoverBody.tsx
|
|
412
|
+
var import_react_native4 = require("react-native");
|
|
413
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
187
414
|
var CARET_SIZE = 7;
|
|
188
415
|
var CARET_RING_OFFSET = 2;
|
|
189
416
|
var CARET_DIP = 1;
|
|
190
417
|
function PopoverBody({ visible, children, align = "center", verticalAlign = "below", caretColor, caretBorderColor, caretBorderWidth = 1, triggerSize = 0 }) {
|
|
191
418
|
if (!visible) return null;
|
|
192
419
|
const above = verticalAlign === "above";
|
|
193
|
-
const alignStyle = align === "left" ?
|
|
194
|
-
const verticalStyle = above ?
|
|
420
|
+
const alignStyle = align === "left" ? styles3.contentLeft : align === "right" ? styles3.contentRight : styles3.contentCenter;
|
|
421
|
+
const verticalStyle = above ? styles3.contentAbove : styles3.contentBelow;
|
|
195
422
|
const ringSize = CARET_SIZE + caretBorderWidth;
|
|
196
423
|
const caretOffset = (halfFootprint) => align === "right" ? { right: triggerSize / 2 - halfFootprint } : { left: triggerSize / 2 - halfFootprint };
|
|
197
424
|
const caretFill = above ? "borderTopColor" : "borderBottomColor";
|
|
198
425
|
const caretWidthProp = above ? "borderTopWidth" : "borderBottomWidth";
|
|
199
426
|
const caretEdge = (size) => above ? { bottom: -size + CARET_DIP } : { top: -size + CARET_DIP };
|
|
200
|
-
return /* @__PURE__ */ (0,
|
|
427
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native4.View, { style: [styles3.content, alignStyle, verticalStyle], children: [
|
|
201
428
|
children,
|
|
202
|
-
caretColor && /* @__PURE__ */ (0,
|
|
203
|
-
/* @__PURE__ */ (0,
|
|
204
|
-
/* @__PURE__ */ (0,
|
|
429
|
+
caretColor && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
430
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.caret, caretOffset(ringSize), caretEdge(ringSize), { [caretFill]: caretBorderColor ?? caretColor, [caretWidthProp]: ringSize, borderLeftWidth: ringSize, borderRightWidth: ringSize }] }),
|
|
431
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: [styles3.caret, caretOffset(CARET_SIZE), caretEdge(CARET_SIZE - CARET_RING_OFFSET), { [caretFill]: caretColor, [caretWidthProp]: CARET_SIZE, borderLeftWidth: CARET_SIZE, borderRightWidth: CARET_SIZE }] })
|
|
205
432
|
] })
|
|
206
433
|
] });
|
|
207
434
|
}
|
|
208
|
-
var
|
|
435
|
+
var styles3 = import_react_native4.StyleSheet.create({
|
|
209
436
|
caret: {
|
|
210
437
|
borderLeftColor: "transparent",
|
|
211
438
|
borderRightColor: "transparent",
|
|
@@ -248,22 +475,22 @@ var styles = import_react_native2.StyleSheet.create({
|
|
|
248
475
|
});
|
|
249
476
|
|
|
250
477
|
// src/useAutoAlign.ts
|
|
251
|
-
var
|
|
252
|
-
var
|
|
478
|
+
var import_react2 = require("react");
|
|
479
|
+
var import_react_native5 = require("react-native");
|
|
253
480
|
var EDGE_MARGIN = 12;
|
|
254
481
|
function useAutoAlign(open, contentWidth, contentHeight) {
|
|
255
|
-
const triggerRef = (0,
|
|
256
|
-
const { width: windowWidth, height: windowHeight } = (0,
|
|
257
|
-
const [align, setAlign] = (0,
|
|
258
|
-
const [verticalAlign, setVerticalAlign] = (0,
|
|
259
|
-
const [maxHeight, setMaxHeight] = (0,
|
|
260
|
-
const [measured, setMeasured] = (0,
|
|
261
|
-
const [prevOpen, setPrevOpen] = (0,
|
|
482
|
+
const triggerRef = (0, import_react2.useRef)(null);
|
|
483
|
+
const { width: windowWidth, height: windowHeight } = (0, import_react_native5.useWindowDimensions)();
|
|
484
|
+
const [align, setAlign] = (0, import_react2.useState)("center");
|
|
485
|
+
const [verticalAlign, setVerticalAlign] = (0, import_react2.useState)("below");
|
|
486
|
+
const [maxHeight, setMaxHeight] = (0, import_react2.useState)(contentHeight);
|
|
487
|
+
const [measured, setMeasured] = (0, import_react2.useState)(false);
|
|
488
|
+
const [prevOpen, setPrevOpen] = (0, import_react2.useState)(open);
|
|
262
489
|
if (open !== prevOpen) {
|
|
263
490
|
setPrevOpen(open);
|
|
264
491
|
if (open) setMeasured(false);
|
|
265
492
|
}
|
|
266
|
-
const measure = (0,
|
|
493
|
+
const measure = (0, import_react2.useCallback)(() => {
|
|
267
494
|
triggerRef.current?.measureInWindow((x, y, triggerWidth, triggerHeight) => {
|
|
268
495
|
const centerX = x + triggerWidth / 2;
|
|
269
496
|
const overflowsRight = centerX + contentWidth / 2 > windowWidth - EDGE_MARGIN;
|
|
@@ -279,14 +506,14 @@ function useAutoAlign(open, contentWidth, contentHeight) {
|
|
|
279
506
|
setMeasured(true);
|
|
280
507
|
});
|
|
281
508
|
}, [contentWidth, contentHeight, windowWidth, windowHeight]);
|
|
282
|
-
(0,
|
|
509
|
+
(0, import_react2.useEffect)(() => {
|
|
283
510
|
if (open) measure();
|
|
284
511
|
}, [open, measure]);
|
|
285
512
|
return { align, maxHeight, measured, triggerRef, verticalAlign };
|
|
286
513
|
}
|
|
287
514
|
|
|
288
515
|
// src/InlineColorPicker.tsx
|
|
289
|
-
var
|
|
516
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
290
517
|
var EMOJI_PATTERN = /\p{Extended_Pictographic}/u;
|
|
291
518
|
var DEFAULT_SIZE = 48;
|
|
292
519
|
var SWATCH_SIZE = 28;
|
|
@@ -299,10 +526,10 @@ var SCREEN_MARGIN = 40;
|
|
|
299
526
|
function widthForColumns(columns) {
|
|
300
527
|
return SWATCHES_BORDER_WIDTH * 2 + SWATCHES_PADDING * 2 + SWATCH_SIZE * columns + SWATCHES_GAP * (columns - 1);
|
|
301
528
|
}
|
|
302
|
-
function InlineColorPicker({ id, host, value, onChange, swatches =
|
|
529
|
+
function InlineColorPicker({ id, host, value, onChange, swatches = import_auto_paper2.defaultColors, takenValue, allowSwapTaken, dark, align: alignOverride, icon = "palette", tag, labelFontFamily = MONO_FONT, autoDismiss = true, columns, size = DEFAULT_SIZE }) {
|
|
303
530
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
304
|
-
const { width: windowWidth } = (0,
|
|
305
|
-
const autoColumns = (0,
|
|
531
|
+
const { width: windowWidth } = (0, import_react_native6.useWindowDimensions)();
|
|
532
|
+
const autoColumns = (0, import_core2.clamp)(Math.floor((windowWidth - 2 * SCREEN_MARGIN + SWATCHES_GAP) / (SWATCH_SIZE + SWATCHES_GAP)), MIN_COLUMNS, MAX_COLUMNS);
|
|
306
533
|
const resolvedColumns = columns ?? autoColumns;
|
|
307
534
|
const swatchesWidth = widthForColumns(resolvedColumns);
|
|
308
535
|
const swatchRows = Math.ceil(swatches.length / resolvedColumns);
|
|
@@ -310,16 +537,16 @@ function InlineColorPicker({ id, host, value, onChange, swatches = import_auto_p
|
|
|
310
537
|
const open = host.openId === id;
|
|
311
538
|
const { align: autoAlign, maxHeight, measured, triggerRef, verticalAlign } = useAutoAlign(open, swatchesWidth, swatchesHeight);
|
|
312
539
|
const align = alignOverride ?? autoAlign;
|
|
313
|
-
const contrastColor = (0,
|
|
540
|
+
const contrastColor = (0, import_auto_paper2.getContrastColor)(value);
|
|
314
541
|
const tagFontSize = size * (tag && EMOJI_PATTERN.test(tag) ? 0.6 : 0.4);
|
|
315
|
-
return /* @__PURE__ */ (0,
|
|
316
|
-
/* @__PURE__ */ (0,
|
|
317
|
-
/* @__PURE__ */ (0,
|
|
542
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native6.View, { style: [styles4.anchor, open && styles4.anchorOpen], children: [
|
|
543
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_feedback_press3.TouchableRipple, { onPress: () => host.toggle(id), borderless: true, style: [styles4.trigger, { backgroundColor: value, borderRadius: size / 2, height: size, width: size }], children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.View, { ref: triggerRef, collapsable: false, style: styles4.triggerMeasure, children: tag ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Text, { style: [styles4.tagLabel, { color: contrastColor, fontFamily: labelFontFamily, fontSize: tagFontSize }], numberOfLines: 1, adjustsFontSizeToFit: true, children: tag }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: icon, size: size * 0.6, color: contrastColor }) }) }),
|
|
544
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: value, caretBorderWidth: SWATCHES_BORDER_WIDTH, triggerSize: size, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.ScrollView, { style: [styles4.swatches, { backgroundColor: menuBg, borderColor: value, width: swatchesWidth, maxHeight }], contentContainerStyle: styles4.swatchesContent, showsVerticalScrollIndicator: false, children: swatches.map((swatch) => {
|
|
318
545
|
const selected = swatch.value.toLowerCase() === value.toLowerCase();
|
|
319
546
|
const taken = !selected && !!takenValue && swatch.value.toLowerCase() === takenValue.toLowerCase();
|
|
320
547
|
const swappable = taken && allowSwapTaken;
|
|
321
|
-
return /* @__PURE__ */ (0,
|
|
322
|
-
|
|
548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
549
|
+
import_feedback_press3.TouchableRipple,
|
|
323
550
|
{
|
|
324
551
|
disabled: taken && !swappable,
|
|
325
552
|
onPress: () => {
|
|
@@ -327,15 +554,15 @@ function InlineColorPicker({ id, host, value, onChange, swatches = import_auto_p
|
|
|
327
554
|
if (autoDismiss) host.close();
|
|
328
555
|
},
|
|
329
556
|
borderless: true,
|
|
330
|
-
style: [
|
|
331
|
-
children: selected ? /* @__PURE__ */ (0,
|
|
557
|
+
style: [styles4.swatch, { backgroundColor: swatch.value }, selected && styles4.swatchSelected, taken && !swappable && styles4.swatchTaken],
|
|
558
|
+
children: selected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "check", size: 16, color: (0, import_auto_paper2.getContrastColor)(swatch.value) }) : swappable ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "swap-horizontal", size: 16, color: (0, import_auto_paper2.getContrastColor)(swatch.value) }) : taken ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper2.Icon, { source: "close", size: 16, color: (0, import_auto_paper2.getContrastColor)(swatch.value) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native6.View, {})
|
|
332
559
|
},
|
|
333
560
|
swatch.value
|
|
334
561
|
);
|
|
335
562
|
}) }) })
|
|
336
563
|
] });
|
|
337
564
|
}
|
|
338
|
-
var
|
|
565
|
+
var styles4 = import_react_native6.StyleSheet.create({
|
|
339
566
|
anchor: {
|
|
340
567
|
position: "relative"
|
|
341
568
|
},
|
|
@@ -406,31 +633,126 @@ var styles2 = import_react_native4.StyleSheet.create({
|
|
|
406
633
|
}
|
|
407
634
|
});
|
|
408
635
|
|
|
636
|
+
// src/LabeledDropdown.tsx
|
|
637
|
+
var import_auto_paper3 = require("@rific/auto-paper");
|
|
638
|
+
var import_feedback_press4 = require("@rific/feedback-press");
|
|
639
|
+
var import_react_native7 = require("react-native");
|
|
640
|
+
var import_react_native_paper3 = require("react-native-paper");
|
|
641
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
642
|
+
var TRIGGER_HEIGHT = 28;
|
|
643
|
+
var POPOVER_WIDTH = 180;
|
|
644
|
+
var ROW_HEIGHT = 36;
|
|
645
|
+
var LIST_PADDING = 8;
|
|
646
|
+
var LABELED_DROPDOWN_POPOVER_WIDTH = POPOVER_WIDTH;
|
|
647
|
+
function getLabeledDropdownContentHeight(optionCount) {
|
|
648
|
+
return LIST_PADDING * 2 + optionCount * ROW_HEIGHT;
|
|
649
|
+
}
|
|
650
|
+
function LabeledDropdown({ id, host, options, value, onChange, color, dark, align: forcedAlign, alignOverride }) {
|
|
651
|
+
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
652
|
+
const fg = dark ? "#FFFFFF" : "#000000";
|
|
653
|
+
const open = host.openId === id;
|
|
654
|
+
const selected = options.find((o) => o.value === value) ?? null;
|
|
655
|
+
const contentHeight = LIST_PADDING * 2 + options.length * ROW_HEIGHT;
|
|
656
|
+
const auto = useAutoAlign(open, POPOVER_WIDTH, contentHeight);
|
|
657
|
+
const placement = alignOverride ?? auto;
|
|
658
|
+
const { maxHeight, measured, triggerRef, verticalAlign } = placement;
|
|
659
|
+
const align = forcedAlign ?? placement.align;
|
|
660
|
+
const handleSelect = (option) => {
|
|
661
|
+
onChange(option.value);
|
|
662
|
+
host.close();
|
|
663
|
+
};
|
|
664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native7.View, { style: [styles5.anchor, open && styles5.anchorOpen], children: [
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => host.toggle(id), style: styles5.trigger, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native7.View, { ref: triggerRef, collapsable: false, style: styles5.triggerInner, children: [
|
|
666
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { style: [styles5.triggerLabel, { color }], numberOfLines: 1, children: (selected?.label ?? "").toUpperCase() }),
|
|
667
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Icon, { source: "menu-down", size: 16, color })
|
|
668
|
+
] }) }),
|
|
669
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: color, caretBorderWidth: 2, triggerSize: TRIGGER_HEIGHT, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native7.ScrollView, { style: [styles5.menu, { backgroundColor: menuBg, borderColor: color, width: POPOVER_WIDTH, maxHeight }], contentContainerStyle: styles5.menuContent, showsVerticalScrollIndicator: false, children: options.map((option) => {
|
|
670
|
+
const isSelected = option.value === value;
|
|
671
|
+
const onColor = (0, import_auto_paper3.getContrastColor)(color);
|
|
672
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_feedback_press4.TouchableRipple, { onPress: () => handleSelect(option), style: [styles5.row, isSelected && { backgroundColor: color }], children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native7.View, { style: styles5.rowInner, children: [
|
|
673
|
+
option.icon && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Icon, { source: option.icon, size: 18, color: isSelected ? onColor : fg }),
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native_paper3.Text, { style: [styles5.rowLabel, { color: isSelected ? onColor : fg }], numberOfLines: 1, children: option.label })
|
|
675
|
+
] }) }, option.value);
|
|
676
|
+
}) }) })
|
|
677
|
+
] });
|
|
678
|
+
}
|
|
679
|
+
var styles5 = import_react_native7.StyleSheet.create({
|
|
680
|
+
anchor: {
|
|
681
|
+
position: "relative"
|
|
682
|
+
},
|
|
683
|
+
// React Native Web gives every position:'relative' view its own stacking context, so the
|
|
684
|
+
// elevation has to live on the anchor itself — see PopoverBody's own stacking-context notes.
|
|
685
|
+
anchorOpen: {
|
|
686
|
+
zIndex: 100
|
|
687
|
+
},
|
|
688
|
+
menu: {
|
|
689
|
+
borderRadius: 12,
|
|
690
|
+
borderWidth: 2,
|
|
691
|
+
elevation: 8,
|
|
692
|
+
shadowColor: "#000000",
|
|
693
|
+
shadowOffset: { height: 2, width: 0 },
|
|
694
|
+
shadowOpacity: 0.3,
|
|
695
|
+
shadowRadius: 8
|
|
696
|
+
},
|
|
697
|
+
menuContent: {
|
|
698
|
+
padding: LIST_PADDING
|
|
699
|
+
},
|
|
700
|
+
row: {
|
|
701
|
+
borderRadius: 8,
|
|
702
|
+
height: ROW_HEIGHT
|
|
703
|
+
},
|
|
704
|
+
rowInner: {
|
|
705
|
+
alignItems: "center",
|
|
706
|
+
flexDirection: "row",
|
|
707
|
+
flex: 1,
|
|
708
|
+
gap: 8,
|
|
709
|
+
paddingHorizontal: 12
|
|
710
|
+
},
|
|
711
|
+
rowLabel: {
|
|
712
|
+
flex: 1,
|
|
713
|
+
fontSize: 14
|
|
714
|
+
},
|
|
715
|
+
trigger: {
|
|
716
|
+
alignSelf: "flex-start"
|
|
717
|
+
},
|
|
718
|
+
triggerInner: {
|
|
719
|
+
alignItems: "center",
|
|
720
|
+
flexDirection: "row",
|
|
721
|
+
gap: 2,
|
|
722
|
+
height: TRIGGER_HEIGHT
|
|
723
|
+
},
|
|
724
|
+
triggerLabel: {
|
|
725
|
+
fontSize: 13,
|
|
726
|
+
fontWeight: "700",
|
|
727
|
+
letterSpacing: 1
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
|
|
409
731
|
// src/loadSkiaWeb.ts
|
|
410
732
|
function loadSkiaWeb() {
|
|
411
733
|
return Promise.resolve();
|
|
412
734
|
}
|
|
413
735
|
|
|
414
736
|
// src/PressAwayOverlay.tsx
|
|
415
|
-
var
|
|
416
|
-
var
|
|
737
|
+
var import_react_native8 = require("react-native");
|
|
738
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
417
739
|
function PressAwayOverlay({ active, onPress, style }) {
|
|
418
740
|
if (!active) return null;
|
|
419
|
-
return /* @__PURE__ */ (0,
|
|
741
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native8.Pressable, { accessibilityLabel: "Dismiss", accessibilityRole: "button", onPress, style: [import_react_native8.StyleSheet.absoluteFill, style] });
|
|
420
742
|
}
|
|
421
743
|
|
|
422
744
|
// src/ReadyButton.tsx
|
|
423
|
-
var
|
|
424
|
-
var
|
|
425
|
-
var
|
|
426
|
-
var
|
|
745
|
+
var import_feedback_press5 = require("@rific/feedback-press");
|
|
746
|
+
var import_react_native9 = require("react-native");
|
|
747
|
+
var import_react_native_paper4 = require("react-native-paper");
|
|
748
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
427
749
|
function ReadyButton({ color, ready, onToggleReady, style, labelFontFamily = MONO_FONT }) {
|
|
428
|
-
const readyButtonStyle = [
|
|
750
|
+
const readyButtonStyle = [styles6.readyButton, { borderColor: color }, ready && { backgroundColor: color }, style];
|
|
429
751
|
const labelTextStyle = { fontFamily: labelFontFamily, fontWeight: "bold" };
|
|
430
752
|
const labelColorStyle = { color: ready ? "#000000" : color };
|
|
431
|
-
return /* @__PURE__ */ (0,
|
|
753
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_feedback_press5.TouchableRipple, { onPress: onToggleReady, borderless: true, style: readyButtonStyle, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_native_paper4.Text, { variant: "labelLarge", style: [labelTextStyle, labelColorStyle], children: ready ? "READY \u2713" : "READY?" }) });
|
|
432
754
|
}
|
|
433
|
-
var
|
|
755
|
+
var styles6 = import_react_native9.StyleSheet.create({
|
|
434
756
|
readyButton: {
|
|
435
757
|
alignItems: "center",
|
|
436
758
|
borderRadius: 12,
|
|
@@ -443,21 +765,21 @@ var styles3 = import_react_native6.StyleSheet.create({
|
|
|
443
765
|
});
|
|
444
766
|
|
|
445
767
|
// src/SectionedDropdown.tsx
|
|
446
|
-
var
|
|
447
|
-
var
|
|
448
|
-
var
|
|
449
|
-
var
|
|
768
|
+
var import_auto_paper4 = require("@rific/auto-paper");
|
|
769
|
+
var import_feedback_press6 = require("@rific/feedback-press");
|
|
770
|
+
var import_react_native11 = require("react-native");
|
|
771
|
+
var import_react_native_paper5 = require("react-native-paper");
|
|
450
772
|
|
|
451
773
|
// src/TriggerGaugeHost.tsx
|
|
452
|
-
var
|
|
453
|
-
var
|
|
454
|
-
var LazyTriggerGauge = (0,
|
|
774
|
+
var import_react4 = require("react");
|
|
775
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
776
|
+
var LazyTriggerGauge = (0, import_react4.lazy)(() => loadSkiaWeb().then(() => Promise.resolve().then(() => (init_TriggerGauge(), TriggerGauge_exports)).then((m) => ({ default: m.TriggerGauge }))));
|
|
455
777
|
function TriggerGaugeHost(props) {
|
|
456
|
-
return /* @__PURE__ */ (0,
|
|
778
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react4.Suspense, { fallback: null, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(LazyTriggerGauge, { ...props }) });
|
|
457
779
|
}
|
|
458
780
|
|
|
459
781
|
// src/SectionedDropdown.tsx
|
|
460
|
-
var
|
|
782
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
461
783
|
var MENU_BORDER_WIDTH = 1;
|
|
462
784
|
var TRIGGER_SIZE = 44;
|
|
463
785
|
var MENU_MIN_WIDTH = 200;
|
|
@@ -470,8 +792,8 @@ var MENU_DIVIDER_HEIGHT = 9;
|
|
|
470
792
|
var MENU_VERTICAL_PADDING = 12;
|
|
471
793
|
function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accentColor, mutedColor, onAccentColor, dark, align: alignOverride, autoDismiss = true, labelFontFamily = MONO_FONT, allClearLabels = { all: "All", clear: "Clear" } }) {
|
|
472
794
|
const menuBg = dark ? "#000000" : "#FFFFFF";
|
|
473
|
-
const menuBorderColor = (0,
|
|
474
|
-
const resolvedOnAccentColor = onAccentColor ?? (0,
|
|
795
|
+
const menuBorderColor = (0, import_auto_paper4.getBlendedColor)(mutedColor, menuBg, 0.5);
|
|
796
|
+
const resolvedOnAccentColor = onAccentColor ?? (0, import_auto_paper4.getColorRoles)(accentColor, menuBg).onColor;
|
|
475
797
|
const fg = dark ? "#FFFFFF" : "#000000";
|
|
476
798
|
const open = host.openId === id;
|
|
477
799
|
const estimatedHeight = MENU_VERTICAL_PADDING + sections.reduce((sum, section, sectionIndex) => {
|
|
@@ -503,17 +825,17 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
|
|
|
503
825
|
}
|
|
504
826
|
gaugeOffset += section.options.length;
|
|
505
827
|
}
|
|
506
|
-
const anchorStyle = [
|
|
828
|
+
const anchorStyle = [styles8.anchor, open && styles8.anchorOpen];
|
|
507
829
|
const menuStyle = { backgroundColor: menuBg, borderColor: menuBorderColor, maxHeight };
|
|
508
830
|
const dividerStyle = { backgroundColor: menuBorderColor };
|
|
509
|
-
return /* @__PURE__ */ (0,
|
|
510
|
-
/* @__PURE__ */ (0,
|
|
511
|
-
/* @__PURE__ */ (0,
|
|
512
|
-
/* @__PURE__ */ (0,
|
|
831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: anchorStyle, children: [
|
|
832
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { ref: triggerRef, collapsable: false, style: styles8.triggerBox, children: [
|
|
833
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TriggerGaugeHost, { segments: gaugeSegments, litIndices: gaugeLitIndices, size: TRIGGER_SIZE, accentColor, mutedColor }),
|
|
834
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press6.IconButton, { icon: triggerIcon, iconColor: triggerIconColor, size: triggerIconSize, accessibilityLabel, onPress: () => host.toggle(id) })
|
|
513
835
|
] }),
|
|
514
|
-
/* @__PURE__ */ (0,
|
|
515
|
-
sectionIndex > 0 && /* @__PURE__ */ (0,
|
|
516
|
-
section.kind === "single" ? /* @__PURE__ */ (0,
|
|
836
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PopoverBody, { visible: open && measured, align, verticalAlign, caretColor: menuBg, caretBorderColor: menuBorderColor, caretBorderWidth: MENU_BORDER_WIDTH, triggerSize: TRIGGER_SIZE, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.ScrollView, { style: [styles8.menu, menuStyle], contentContainerStyle: styles8.menuContent, showsVerticalScrollIndicator: false, children: sections.map((section, sectionIndex) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { children: [
|
|
837
|
+
sectionIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native11.View, { style: [styles8.divider, dividerStyle] }),
|
|
838
|
+
section.kind === "single" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
517
839
|
SingleSection,
|
|
518
840
|
{
|
|
519
841
|
section,
|
|
@@ -526,7 +848,7 @@ function SectionedDropdown({ id, host, icon, accessibilityLabel, sections, accen
|
|
|
526
848
|
if (autoDismiss) host.close();
|
|
527
849
|
}
|
|
528
850
|
}
|
|
529
|
-
) : /* @__PURE__ */ (0,
|
|
851
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MultiSection, { section, accentColor, onAccentColor: resolvedOnAccentColor, mutedColor, labelFontFamily, allClearLabels })
|
|
530
852
|
] }, section.id)) }) })
|
|
531
853
|
] });
|
|
532
854
|
}
|
|
@@ -538,17 +860,17 @@ function SingleSection({
|
|
|
538
860
|
labelFontFamily,
|
|
539
861
|
onSelect
|
|
540
862
|
}) {
|
|
541
|
-
return /* @__PURE__ */ (0,
|
|
863
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children: section.options.map((option) => {
|
|
542
864
|
const selected = option.value === section.value;
|
|
543
865
|
const rowColor = selected ? onAccentColor : mutedColor;
|
|
544
|
-
const itemStyle = [
|
|
866
|
+
const itemStyle = [styles8.item, selected && { backgroundColor: accentColor }];
|
|
545
867
|
const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
|
|
546
868
|
const descriptionStyle = { fontFamily: labelFontFamily, color: rowColor };
|
|
547
|
-
return /* @__PURE__ */ (0,
|
|
548
|
-
option.icon && /* @__PURE__ */ (0,
|
|
549
|
-
/* @__PURE__ */ (0,
|
|
550
|
-
/* @__PURE__ */ (0,
|
|
551
|
-
option.description && /* @__PURE__ */ (0,
|
|
869
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => onSelect(option.value), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles8.itemRow, children: [
|
|
870
|
+
option.icon && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper5.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
|
|
871
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles8.itemLabelColumn, children: [
|
|
872
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper5.Text, { variant: "labelLarge", style: labelStyle, children: option.label }),
|
|
873
|
+
option.description && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper5.Text, { variant: "labelSmall", style: descriptionStyle, children: option.description })
|
|
552
874
|
] })
|
|
553
875
|
] }) }, option.value);
|
|
554
876
|
}) });
|
|
@@ -562,23 +884,23 @@ function MultiSection({
|
|
|
562
884
|
allClearLabels
|
|
563
885
|
}) {
|
|
564
886
|
const allSelected = section.value.length === section.options.length;
|
|
565
|
-
return /* @__PURE__ */ (0,
|
|
887
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
566
888
|
section.options.map((option, i) => {
|
|
567
889
|
const selected = section.value.includes(option.value);
|
|
568
890
|
const rowColor = selected ? onAccentColor : mutedColor;
|
|
569
891
|
const prevSelected = selected && i > 0 && section.value.includes(section.options[i - 1].value);
|
|
570
892
|
const nextSelected = selected && i < section.options.length - 1 && section.value.includes(section.options[i + 1].value);
|
|
571
|
-
const itemStyle = [
|
|
893
|
+
const itemStyle = [styles8.item, selected && { backgroundColor: accentColor }, prevSelected && { borderTopLeftRadius: 0, borderTopRightRadius: 0 }, nextSelected && { borderBottomLeftRadius: 0, borderBottomRightRadius: 0 }];
|
|
572
894
|
const labelStyle = { fontFamily: labelFontFamily, color: rowColor, fontWeight: selected ? "bold" : "normal" };
|
|
573
|
-
return /* @__PURE__ */ (0,
|
|
574
|
-
option.icon && /* @__PURE__ */ (0,
|
|
575
|
-
/* @__PURE__ */ (0,
|
|
895
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => section.onChange(selected ? section.value.filter((v) => v !== option.value) : [...section.value, option.value]), style: itemStyle, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_native11.View, { style: styles8.itemRow, children: [
|
|
896
|
+
option.icon && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper5.Icon, { source: option.icon, size: MENU_ITEM_ICON_SIZE, color: rowColor }),
|
|
897
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper5.Text, { variant: "labelLarge", style: [styles8.itemLabelFlex, labelStyle], children: option.label })
|
|
576
898
|
] }) }, option.value);
|
|
577
899
|
}),
|
|
578
|
-
section.allClear && /* @__PURE__ */ (0,
|
|
900
|
+
section.allClear && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_feedback_press6.TouchableRipple, { onPress: () => section.onChange(allSelected ? [] : section.options.map((o) => o.value)), style: styles8.item, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native_paper5.Text, { variant: "labelLarge", style: [styles8.allClearLabel, { fontFamily: labelFontFamily, color: accentColor }], children: allSelected ? allClearLabels.clear : allClearLabels.all }) })
|
|
579
901
|
] });
|
|
580
902
|
}
|
|
581
|
-
var
|
|
903
|
+
var styles8 = import_react_native11.StyleSheet.create({
|
|
582
904
|
allClearLabel: {
|
|
583
905
|
fontWeight: "bold",
|
|
584
906
|
textAlign: "center"
|
|
@@ -595,7 +917,7 @@ var styles5 = import_react_native8.StyleSheet.create({
|
|
|
595
917
|
zIndex: 100
|
|
596
918
|
},
|
|
597
919
|
divider: {
|
|
598
|
-
height:
|
|
920
|
+
height: import_react_native11.StyleSheet.hairlineWidth,
|
|
599
921
|
marginVertical: 4
|
|
600
922
|
},
|
|
601
923
|
item: {
|
|
@@ -642,25 +964,61 @@ var styles5 = import_react_native8.StyleSheet.create({
|
|
|
642
964
|
}
|
|
643
965
|
});
|
|
644
966
|
|
|
967
|
+
// src/SharedActionBand.tsx
|
|
968
|
+
var import_feedback_press7 = require("@rific/feedback-press");
|
|
969
|
+
var import_react_native12 = require("react-native");
|
|
970
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
971
|
+
function SharedActionBand({ onBack, onSettings, onRandomize, onReset, fg, popoverOpen, children }) {
|
|
972
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: [styles9.column, popoverOpen && styles9.columnOpen], children: [
|
|
973
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react_native12.View, { style: styles9.actionsRow, children: [
|
|
974
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press7.IconButton, { icon: "arrow-left", iconColor: fg, size: 20, onPress: onBack, accessibilityLabel: "Back" }),
|
|
975
|
+
onRandomize && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press7.IconButton, { icon: "dice-multiple", iconColor: fg, size: 18, onPress: onRandomize, accessibilityLabel: "Randomize match settings" }),
|
|
976
|
+
onReset && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press7.IconButton, { icon: "restore", iconColor: fg, size: 18, onPress: onReset, accessibilityLabel: "Reset match settings to defaults" }),
|
|
977
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_feedback_press7.IconButton, { icon: "cog", iconColor: fg, size: 20, onPress: onSettings, accessibilityLabel: "Settings" })
|
|
978
|
+
] }),
|
|
979
|
+
children
|
|
980
|
+
] });
|
|
981
|
+
}
|
|
982
|
+
var styles9 = import_react_native12.StyleSheet.create({
|
|
983
|
+
actionsRow: {
|
|
984
|
+
alignItems: "center",
|
|
985
|
+
flexDirection: "row",
|
|
986
|
+
gap: 16
|
|
987
|
+
},
|
|
988
|
+
column: {
|
|
989
|
+
alignItems: "center",
|
|
990
|
+
gap: 8
|
|
991
|
+
},
|
|
992
|
+
columnOpen: {
|
|
993
|
+
zIndex: 100
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
|
|
645
997
|
// src/usePopoverHost.ts
|
|
646
|
-
var
|
|
998
|
+
var import_react5 = require("react");
|
|
647
999
|
function usePopoverHost() {
|
|
648
|
-
const [openId, setOpenId] = (0,
|
|
649
|
-
const toggle = (0,
|
|
1000
|
+
const [openId, setOpenId] = (0, import_react5.useState)(null);
|
|
1001
|
+
const toggle = (0, import_react5.useCallback)((id) => {
|
|
650
1002
|
setOpenId((prev) => prev === id ? null : id);
|
|
651
1003
|
}, []);
|
|
652
|
-
const close = (0,
|
|
1004
|
+
const close = (0, import_react5.useCallback)(() => setOpenId(null), []);
|
|
653
1005
|
return { openId, toggle, close };
|
|
654
1006
|
}
|
|
655
1007
|
// Annotate the CommonJS export names for ESM import in node:
|
|
656
1008
|
0 && (module.exports = {
|
|
1009
|
+
BaseSettingsDialog,
|
|
1010
|
+
CornerActionButtons,
|
|
657
1011
|
InlineColorPicker,
|
|
1012
|
+
LABELED_DROPDOWN_POPOVER_WIDTH,
|
|
1013
|
+
LabeledDropdown,
|
|
658
1014
|
MONO_FONT,
|
|
659
1015
|
PopoverBody,
|
|
660
1016
|
PressAwayOverlay,
|
|
661
1017
|
ReadyButton,
|
|
662
1018
|
SectionedDropdown,
|
|
1019
|
+
SharedActionBand,
|
|
663
1020
|
TriggerGaugeHost,
|
|
1021
|
+
getLabeledDropdownContentHeight,
|
|
664
1022
|
loadSkiaWeb,
|
|
665
1023
|
useAutoAlign,
|
|
666
1024
|
usePopoverHost
|