@buoy-gg/shared-ui 7.0.27 → 7.0.29

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.
Files changed (123) hide show
  1. package/lib/commonjs/JsModal.js +12 -2
  2. package/lib/commonjs/dataViewer/DataTreeActionDock.js +1 -0
  3. package/lib/commonjs/dataViewer/DataViewer.js +6 -3
  4. package/lib/commonjs/dataViewer/VirtualizedDataExplorer.js +13 -4
  5. package/lib/commonjs/hooks/safe-area-impl.js +1 -1
  6. package/lib/commonjs/license/FeatureGate.js +9 -0
  7. package/lib/commonjs/ui/backgrounds/registry.js +3 -2
  8. package/lib/commonjs/ui/backgrounds/variants/meteors.js +222 -78
  9. package/lib/commonjs/ui/components/Badge.js +3 -1
  10. package/lib/commonjs/ui/components/CompactRow.js +14 -1
  11. package/lib/commonjs/ui/components/CopyButton.js +9 -5
  12. package/lib/commonjs/ui/components/DevToolsCard.js +4 -1
  13. package/lib/commonjs/ui/components/DraggableHeader.js +5 -1
  14. package/lib/commonjs/ui/components/DynamicFilterView.js +23 -4
  15. package/lib/commonjs/ui/components/EventStepperFooter.js +8 -0
  16. package/lib/commonjs/ui/components/FilterComponents.js +18 -2
  17. package/lib/commonjs/ui/components/ModalHeader.js +27 -5
  18. package/lib/commonjs/ui/components/PowerToggleButton.js +2 -0
  19. package/lib/commonjs/ui/components/SearchBar.js +6 -1
  20. package/lib/commonjs/ui/components/SectionHeader.js +3 -1
  21. package/lib/commonjs/ui/components/TabSelector.js +15 -4
  22. package/lib/commonjs/ui/components/WindowControls.js +68 -96
  23. package/lib/commonjs/ui/gameUI/constants/gameUIColors.js +12 -8
  24. package/lib/module/JsModal.js +12 -2
  25. package/lib/module/dataViewer/DataTreeActionDock.js +1 -0
  26. package/lib/module/dataViewer/DataViewer.js +6 -3
  27. package/lib/module/dataViewer/VirtualizedDataExplorer.js +13 -4
  28. package/lib/module/hooks/safe-area-impl.js +1 -1
  29. package/lib/module/license/FeatureGate.js +9 -0
  30. package/lib/module/ui/backgrounds/registry.js +3 -2
  31. package/lib/module/ui/backgrounds/variants/meteors.js +224 -80
  32. package/lib/module/ui/components/Badge.js +3 -1
  33. package/lib/module/ui/components/CompactRow.js +14 -1
  34. package/lib/module/ui/components/CopyButton.js +9 -5
  35. package/lib/module/ui/components/DevToolsCard.js +4 -1
  36. package/lib/module/ui/components/DraggableHeader.js +5 -1
  37. package/lib/module/ui/components/DynamicFilterView.js +23 -4
  38. package/lib/module/ui/components/EventStepperFooter.js +8 -0
  39. package/lib/module/ui/components/FilterComponents.js +18 -2
  40. package/lib/module/ui/components/ModalHeader.js +27 -5
  41. package/lib/module/ui/components/PowerToggleButton.js +2 -0
  42. package/lib/module/ui/components/SearchBar.js +6 -1
  43. package/lib/module/ui/components/SectionHeader.js +3 -1
  44. package/lib/module/ui/components/TabSelector.js +15 -4
  45. package/lib/module/ui/components/WindowControls.js +69 -97
  46. package/lib/module/ui/gameUI/constants/gameUIColors.js +12 -8
  47. package/lib/typescript/commonjs/JsModal.d.ts.map +1 -1
  48. package/lib/typescript/commonjs/dataViewer/DataTreeActionDock.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/dataViewer/DataViewer.d.ts +2 -0
  50. package/lib/typescript/commonjs/dataViewer/DataViewer.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/dataViewer/VirtualizedDataExplorer.d.ts +9 -0
  52. package/lib/typescript/commonjs/dataViewer/VirtualizedDataExplorer.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  54. package/lib/typescript/commonjs/license/FeatureGate.d.ts.map +1 -1
  55. package/lib/typescript/commonjs/ui/backgrounds/registry.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/ui/backgrounds/variants/meteors.d.ts +22 -6
  57. package/lib/typescript/commonjs/ui/backgrounds/variants/meteors.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/ui/components/Badge.d.ts +3 -1
  59. package/lib/typescript/commonjs/ui/components/Badge.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/ui/components/CompactRow.d.ts +7 -1
  61. package/lib/typescript/commonjs/ui/components/CompactRow.d.ts.map +1 -1
  62. package/lib/typescript/commonjs/ui/components/CopyButton.d.ts +5 -0
  63. package/lib/typescript/commonjs/ui/components/CopyButton.d.ts.map +1 -1
  64. package/lib/typescript/commonjs/ui/components/DevToolsCard.d.ts +3 -1
  65. package/lib/typescript/commonjs/ui/components/DevToolsCard.d.ts.map +1 -1
  66. package/lib/typescript/commonjs/ui/components/DraggableHeader.d.ts +2 -0
  67. package/lib/typescript/commonjs/ui/components/DraggableHeader.d.ts.map +1 -1
  68. package/lib/typescript/commonjs/ui/components/DynamicFilterView.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/ui/components/EventStepperFooter.d.ts.map +1 -1
  70. package/lib/typescript/commonjs/ui/components/FilterComponents.d.ts +10 -2
  71. package/lib/typescript/commonjs/ui/components/FilterComponents.d.ts.map +1 -1
  72. package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts +16 -2
  73. package/lib/typescript/commonjs/ui/components/ModalHeader.d.ts.map +1 -1
  74. package/lib/typescript/commonjs/ui/components/PowerToggleButton.d.ts +4 -1
  75. package/lib/typescript/commonjs/ui/components/PowerToggleButton.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/ui/components/SearchBar.d.ts +7 -1
  77. package/lib/typescript/commonjs/ui/components/SearchBar.d.ts.map +1 -1
  78. package/lib/typescript/commonjs/ui/components/SectionHeader.d.ts +7 -1
  79. package/lib/typescript/commonjs/ui/components/SectionHeader.d.ts.map +1 -1
  80. package/lib/typescript/commonjs/ui/components/TabSelector.d.ts +20 -1
  81. package/lib/typescript/commonjs/ui/components/TabSelector.d.ts.map +1 -1
  82. package/lib/typescript/commonjs/ui/components/WindowControls.d.ts.map +1 -1
  83. package/lib/typescript/commonjs/ui/gameUI/constants/gameUIColors.d.ts +5 -0
  84. package/lib/typescript/commonjs/ui/gameUI/constants/gameUIColors.d.ts.map +1 -1
  85. package/lib/typescript/module/JsModal.d.ts.map +1 -1
  86. package/lib/typescript/module/dataViewer/DataTreeActionDock.d.ts.map +1 -1
  87. package/lib/typescript/module/dataViewer/DataViewer.d.ts +2 -0
  88. package/lib/typescript/module/dataViewer/DataViewer.d.ts.map +1 -1
  89. package/lib/typescript/module/dataViewer/VirtualizedDataExplorer.d.ts +9 -0
  90. package/lib/typescript/module/dataViewer/VirtualizedDataExplorer.d.ts.map +1 -1
  91. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  92. package/lib/typescript/module/license/FeatureGate.d.ts.map +1 -1
  93. package/lib/typescript/module/ui/backgrounds/registry.d.ts.map +1 -1
  94. package/lib/typescript/module/ui/backgrounds/variants/meteors.d.ts +22 -6
  95. package/lib/typescript/module/ui/backgrounds/variants/meteors.d.ts.map +1 -1
  96. package/lib/typescript/module/ui/components/Badge.d.ts +3 -1
  97. package/lib/typescript/module/ui/components/Badge.d.ts.map +1 -1
  98. package/lib/typescript/module/ui/components/CompactRow.d.ts +7 -1
  99. package/lib/typescript/module/ui/components/CompactRow.d.ts.map +1 -1
  100. package/lib/typescript/module/ui/components/CopyButton.d.ts +5 -0
  101. package/lib/typescript/module/ui/components/CopyButton.d.ts.map +1 -1
  102. package/lib/typescript/module/ui/components/DevToolsCard.d.ts +3 -1
  103. package/lib/typescript/module/ui/components/DevToolsCard.d.ts.map +1 -1
  104. package/lib/typescript/module/ui/components/DraggableHeader.d.ts +2 -0
  105. package/lib/typescript/module/ui/components/DraggableHeader.d.ts.map +1 -1
  106. package/lib/typescript/module/ui/components/DynamicFilterView.d.ts.map +1 -1
  107. package/lib/typescript/module/ui/components/EventStepperFooter.d.ts.map +1 -1
  108. package/lib/typescript/module/ui/components/FilterComponents.d.ts +10 -2
  109. package/lib/typescript/module/ui/components/FilterComponents.d.ts.map +1 -1
  110. package/lib/typescript/module/ui/components/ModalHeader.d.ts +16 -2
  111. package/lib/typescript/module/ui/components/ModalHeader.d.ts.map +1 -1
  112. package/lib/typescript/module/ui/components/PowerToggleButton.d.ts +4 -1
  113. package/lib/typescript/module/ui/components/PowerToggleButton.d.ts.map +1 -1
  114. package/lib/typescript/module/ui/components/SearchBar.d.ts +7 -1
  115. package/lib/typescript/module/ui/components/SearchBar.d.ts.map +1 -1
  116. package/lib/typescript/module/ui/components/SectionHeader.d.ts +7 -1
  117. package/lib/typescript/module/ui/components/SectionHeader.d.ts.map +1 -1
  118. package/lib/typescript/module/ui/components/TabSelector.d.ts +20 -1
  119. package/lib/typescript/module/ui/components/TabSelector.d.ts.map +1 -1
  120. package/lib/typescript/module/ui/components/WindowControls.d.ts.map +1 -1
  121. package/lib/typescript/module/ui/gameUI/constants/gameUIColors.d.ts +5 -0
  122. package/lib/typescript/module/ui/gameUI/constants/gameUIColors.d.ts.map +1 -1
  123. package/package.json +4 -4
@@ -184,10 +184,10 @@ export const CopyButton = /*#__PURE__*/memo(function CopyButton({
184
184
  onPress: copyState === "idle" || !isPro ? handlePress : undefined,
185
185
  activeOpacity: 0.7,
186
186
  hitSlop: {
187
- top: 8,
188
- bottom: 8,
189
- left: 8,
190
- right: 8
187
+ top: 4,
188
+ bottom: 4,
189
+ left: 4,
190
+ right: 4
191
191
  },
192
192
  accessibilityLabel: copyState === "idle" ? "Copy to clipboard" : copyState === "success" ? "Copied to clipboard" : "Failed to copy",
193
193
  accessibilityRole: "button",
@@ -212,6 +212,8 @@ const styles = StyleSheet.create({
212
212
  padding: 4,
213
213
  justifyContent: "center",
214
214
  alignItems: "center",
215
+ alignSelf: "flex-start",
216
+ overflow: "hidden",
215
217
  // Only relevant when a `label` is present; a bare icon button has one
216
218
  // child, so the row direction and gap cost it nothing.
217
219
  flexDirection: "row",
@@ -259,7 +261,8 @@ export const ActionCopyButton = /*#__PURE__*/memo(function ActionCopyButton(prop
259
261
  export const ToolbarClearButton = /*#__PURE__*/memo(function ToolbarClearButton({
260
262
  onPress,
261
263
  disabled = false,
262
- buttonStyle
264
+ buttonStyle,
265
+ testID
263
266
  }) {
264
267
  return /*#__PURE__*/_jsx(TouchableOpacity, {
265
268
  onPress: onPress,
@@ -271,6 +274,7 @@ export const ToolbarClearButton = /*#__PURE__*/memo(function ToolbarClearButton(
271
274
  left: 8,
272
275
  right: 8
273
276
  },
277
+ testID: testID,
274
278
  accessibilityLabel: "Clear",
275
279
  accessibilityRole: "button",
276
280
  children: /*#__PURE__*/_jsx(Trash2, {
@@ -44,7 +44,8 @@ export function DevToolsCard({
44
44
  activeOpacity = 0.8,
45
45
  style,
46
46
  contentStyle,
47
- testID
47
+ testID,
48
+ accessibilityLabel
48
49
  }) {
49
50
  const isInteractive = !!onPress || !!onLongPress;
50
51
 
@@ -53,6 +54,7 @@ export function DevToolsCard({
53
54
  return /*#__PURE__*/_jsx(View, {
54
55
  style: [styles.wrapper, style],
55
56
  testID: testID,
57
+ accessibilityLabel: accessibilityLabel,
56
58
  children: /*#__PURE__*/_jsx(View, {
57
59
  style: [styles.card, isSelected && styles.selectedCard, contentStyle],
58
60
  children: children
@@ -70,6 +72,7 @@ export function DevToolsCard({
70
72
  activeOpacity: activeOpacity,
71
73
  disabled: disabled,
72
74
  testID: testID,
75
+ accessibilityLabel: accessibilityLabel,
73
76
  children: children
74
77
  })
75
78
  });
@@ -36,7 +36,9 @@ export const DraggableHeader = /*#__PURE__*/memo(function DraggableHeader({
36
36
  },
37
37
  style,
38
38
  enabled = true,
39
- maxOverflowX = 0
39
+ maxOverflowX = 0,
40
+ testID,
41
+ accessibilityLabel
40
42
  }) {
41
43
  const isDraggingRef = useRef(false);
42
44
  const dragDistanceRef = useRef(0);
@@ -186,6 +188,8 @@ export const DraggableHeader = /*#__PURE__*/memo(function DraggableHeader({
186
188
  }, [position]);
187
189
  return /*#__PURE__*/_jsx(View, {
188
190
  style: style,
191
+ testID: testID,
192
+ accessibilityLabel: accessibilityLabel,
189
193
  ...panResponder.panHandlers,
190
194
  children: children
191
195
  });
@@ -103,6 +103,9 @@ export function DynamicFilterView({
103
103
  const countIsZero = hasCount && option.count === 0;
104
104
  const showLabel = section.type !== "method" || option.icon;
105
105
  return /*#__PURE__*/_jsxs(TouchableOpacity, {
106
+ testID: `buoy-filter-option-${option.id}`,
107
+ accessibilityRole: "button",
108
+ accessibilityLabel: String(option.label ?? option.id),
106
109
  style: [styles.filterCard, option.isActive && styles.activeFilterCard],
107
110
  onPress: () => onFilterChange?.(option.id, option.value),
108
111
  children: [option.icon ? /*#__PURE__*/_jsx(option.icon, {
@@ -187,7 +190,8 @@ export function DynamicFilterView({
187
190
  children: !includeFilterManager.showAddInput ? /*#__PURE__*/_jsx(AddFilterButton, {
188
191
  onPress: () => includeFilterManager.setShowAddInput(true),
189
192
  color: buoyColors.success,
190
- label: "Add include pattern"
193
+ label: "Add include pattern",
194
+ testID: "buoy-filter-include-add-open"
191
195
  }) : /*#__PURE__*/_jsx(AddFilterInput, {
192
196
  value: includeFilterManager.newFilter,
193
197
  onChange: includeFilterManager.setNewFilter,
@@ -197,9 +201,11 @@ export function DynamicFilterView({
197
201
  includeFilterManager.setNewFilter("");
198
202
  },
199
203
  placeholder: includeOnlySection.placeholder || "Enter pattern to include...",
200
- color: buoyColors.success
204
+ color: buoyColors.success,
205
+ testID: "buoy-filter-include-input"
201
206
  })
202
207
  }), includeOnlySection.patterns.size > 0 && /*#__PURE__*/_jsx(ScrollView, {
208
+ testID: "buoy-filter-include-scroll",
203
209
  style: styles.includeOnlyFiltersContent,
204
210
  showsVerticalScrollIndicator: true,
205
211
  nestedScrollEnabled: true,
@@ -244,7 +250,11 @@ export function DynamicFilterView({
244
250
  color: buoyColors.primary
245
251
  })]
246
252
  })
247
- }), activePatterns.size > 0 && /*#__PURE__*/_jsx(ScrollView, {
253
+ }), activePatterns.size > 0 && /*#__PURE__*/_jsx(ScrollView
254
+ // The active patterns live in their own short scroller, so a
255
+ // pattern added a moment ago is usually below its fold.
256
+ , {
257
+ testID: "buoy-filter-active-scroll",
248
258
  style: styles.excludeFiltersContent,
249
259
  showsVerticalScrollIndicator: true,
250
260
  nestedScrollEnabled: true,
@@ -283,6 +293,9 @@ export function DynamicFilterView({
283
293
  },
284
294
  style: styles.availableKeyItem,
285
295
  "sentry-label": "ignore-touchable-opacity",
296
+ testID: `buoy-filter-available-${item}`,
297
+ accessibilityRole: "button",
298
+ accessibilityLabel: `Add filter ${item}`,
286
299
  children: [/*#__PURE__*/_jsx(Text, {
287
300
  style: styles.availableKeyText,
288
301
  numberOfLines: 1,
@@ -340,7 +353,13 @@ export function DynamicFilterView({
340
353
  };
341
354
  return /*#__PURE__*/_jsxs(View, {
342
355
  style: styles.container,
343
- children: [renderTabs(), /*#__PURE__*/_jsx(ScrollView, {
356
+ children: [renderTabs(), /*#__PURE__*/_jsx(ScrollView
357
+ // The filter screen's own scroller. Named because the sections it
358
+ // holds — including the active-pattern list — run past the bottom of
359
+ // a docked sheet, so reaching one means scrolling THIS, not the short
360
+ // nested scroller the pattern happens to sit in.
361
+ , {
362
+ testID: "buoy-filter-scroll",
344
363
  style: styles.content,
345
364
  contentContainerStyle: styles.scrollContent,
346
365
  showsVerticalScrollIndicator: false,
@@ -48,6 +48,9 @@ export const EventStepperFooter = /*#__PURE__*/memo(function EventStepperFooter(
48
48
  children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
49
49
  onPress: onPrevious,
50
50
  disabled: isFirstItem,
51
+ testID: "tool-stepper-previous",
52
+ accessibilityRole: "button",
53
+ accessibilityLabel: "Previous",
51
54
  style: [styles.navButton, isNight && styles.nightNavButton, isFirstItem && styles.navButtonDisabled],
52
55
  activeOpacity: 0.7,
53
56
  children: [/*#__PURE__*/_jsx(ChevronLeft, {
@@ -60,15 +63,20 @@ export const EventStepperFooter = /*#__PURE__*/memo(function EventStepperFooter(
60
63
  }), /*#__PURE__*/_jsxs(View, {
61
64
  style: styles.counterContainer,
62
65
  children: [/*#__PURE__*/_jsxs(Text, {
66
+ testID: "tool-stepper-counter",
63
67
  style: [styles.counterText, isNight && styles.nightCounterText],
64
68
  children: [itemLabel, " ", currentIndex + 1, " of ", totalItems]
65
69
  }), subtitle && /*#__PURE__*/_jsx(Text, {
70
+ testID: "tool-stepper-subtitle",
66
71
  style: [styles.subtitleText, isNight && styles.nightSubtitleText],
67
72
  children: subtitle
68
73
  })]
69
74
  }), /*#__PURE__*/_jsxs(TouchableOpacity, {
70
75
  onPress: onNext,
71
76
  disabled: isLastItem,
77
+ testID: "tool-stepper-next",
78
+ accessibilityRole: "button",
79
+ accessibilityLabel: "Next",
72
80
  style: [styles.navButton, isNight && styles.nightNavButton, isLastItem && styles.navButtonDisabled],
73
81
  activeOpacity: 0.7,
74
82
  children: [/*#__PURE__*/_jsx(Text, {
@@ -59,13 +59,16 @@ export function AddFilterInput({
59
59
  onSubmit,
60
60
  onCancel,
61
61
  placeholder = "Add filter...",
62
- color = "#E5E7EB"
62
+ color = "#E5E7EB",
63
+ testID = "buoy-filter-input"
63
64
  }) {
64
65
  return /*#__PURE__*/_jsxs(View, {
65
66
  style: [styles.inputContainer, {
66
67
  borderColor: `${color}40`
67
68
  }],
68
69
  children: [/*#__PURE__*/_jsx(TextInput, {
70
+ testID: testID,
71
+ accessibilityLabel: placeholder,
69
72
  value: value,
70
73
  onChangeText: onChange,
71
74
  onSubmitEditing: onSubmit,
@@ -84,6 +87,9 @@ export function AddFilterInput({
84
87
  style: styles.inputButtons,
85
88
  children: [value.trim() && /*#__PURE__*/_jsx(TouchableOpacity, {
86
89
  onPress: onSubmit,
90
+ testID: `${testID}-add`,
91
+ accessibilityLabel: "Add filter",
92
+ accessibilityRole: "button",
87
93
  style: [styles.inlineAddButton, {
88
94
  backgroundColor: `${color}15`,
89
95
  borderColor: `${color}40`
@@ -96,6 +102,9 @@ export function AddFilterInput({
96
102
  })
97
103
  }), /*#__PURE__*/_jsx(TouchableOpacity, {
98
104
  onPress: onCancel,
105
+ testID: `${testID}-cancel`,
106
+ accessibilityLabel: "Cancel adding filter",
107
+ accessibilityRole: "button",
99
108
  style: styles.cancelButton,
100
109
  children: /*#__PURE__*/_jsx(X, {
101
110
  size: 16,
@@ -111,13 +120,17 @@ export function AddFilterInput({
111
120
  export function AddFilterButton({
112
121
  onPress,
113
122
  color = "#E5E7EB",
114
- label = "Add Filter"
123
+ label = "Add Filter",
124
+ testID = "buoy-filter-add-open"
115
125
  }) {
116
126
  return /*#__PURE__*/_jsxs(TouchableOpacity, {
117
127
  style: [styles.addButton, {
118
128
  borderColor: `${color}40`
119
129
  }],
120
130
  onPress: onPress,
131
+ testID: testID,
132
+ accessibilityLabel: label,
133
+ accessibilityRole: "button",
121
134
  children: [/*#__PURE__*/_jsx(Plus, {
122
135
  size: 14,
123
136
  color: color
@@ -146,6 +159,9 @@ export function FilterList({
146
159
  style: styles.filterItemRow,
147
160
  onPress: () => onRemoveFilter?.(filter),
148
161
  activeOpacity: 0.8,
162
+ testID: `buoy-filter-active-${filter}`,
163
+ accessibilityLabel: `Remove filter ${filter}`,
164
+ accessibilityRole: "button",
149
165
  children: [/*#__PURE__*/_jsx(Text, {
150
166
  style: [styles.filterItemText, {
151
167
  color
@@ -35,6 +35,9 @@ export function Navigation({
35
35
  }), /*#__PURE__*/_jsx(TouchableOpacity, {
36
36
  onPress: onClose,
37
37
  style: styles.navigationButton,
38
+ testID: "tool-close",
39
+ accessibilityLabel: "Close",
40
+ accessibilityRole: "button",
38
41
  children: closeIcon || /*#__PURE__*/_jsx(X, {
39
42
  size: 20,
40
43
  color: night.color.textSecondary
@@ -48,6 +51,9 @@ export function Navigation({
48
51
  return /*#__PURE__*/_jsx(TouchableOpacity, {
49
52
  onPress: onBack,
50
53
  style: styles.navigationButton,
54
+ testID: "tool-back",
55
+ accessibilityLabel: "Back",
56
+ accessibilityRole: "button",
51
57
  children: backIcon || /*#__PURE__*/_jsx(ChevronLeft, {
52
58
  size: 20,
53
59
  color: night.color.textSecondary
@@ -61,6 +67,9 @@ export function Navigation({
61
67
  return /*#__PURE__*/_jsx(TouchableOpacity, {
62
68
  onPress: onBack,
63
69
  style: styles.navigationButton,
70
+ testID: "tool-back",
71
+ accessibilityLabel: "Back",
72
+ accessibilityRole: "button",
64
73
  children: backIcon || /*#__PURE__*/_jsx(ChevronLeft, {
65
74
  size: 20,
66
75
  color: night.color.textSecondary
@@ -77,7 +86,8 @@ export function Content({
77
86
  subtitle,
78
87
  children,
79
88
  centered,
80
- noMargin
89
+ noMargin,
90
+ testID
81
91
  }) {
82
92
  if (children) {
83
93
  return /*#__PURE__*/_jsx(View, {
@@ -90,10 +100,12 @@ export function Content({
90
100
  children: [title && /*#__PURE__*/_jsx(Text, {
91
101
  style: [styles.headerTitle, centered && styles.headerTitleCentered],
92
102
  numberOfLines: 1,
103
+ testID: testID,
93
104
  children: title
94
105
  }), subtitle && /*#__PURE__*/_jsx(Text, {
95
106
  style: [styles.headerSubtitle, centered && styles.headerSubtitleCentered],
96
107
  numberOfLines: 1,
108
+ testID: testID ? `${testID}-subtitle` : undefined,
97
109
  children: subtitle
98
110
  })]
99
111
  });
@@ -121,7 +133,8 @@ export function HeaderSearch({
121
133
  onChangeText,
122
134
  onCancel,
123
135
  placeholder = "Search...",
124
- autoFocus = true
136
+ autoFocus = true,
137
+ testID
125
138
  }) {
126
139
  const inputRef = useRef(null);
127
140
  useEffect(() => {
@@ -140,10 +153,15 @@ export function HeaderSearch({
140
153
  value: value,
141
154
  onChangeText: onChangeText,
142
155
  autoCorrect: false,
143
- autoCapitalize: "none"
156
+ autoCapitalize: "none",
157
+ testID: testID,
158
+ accessibilityLabel: placeholder
144
159
  }), /*#__PURE__*/_jsx(TouchableOpacity, {
145
160
  onPress: onCancel,
146
161
  style: styles.searchCancelButton,
162
+ accessibilityRole: "button",
163
+ accessibilityLabel: "Clear search",
164
+ testID: testID ? `${testID}-clear` : undefined,
147
165
  children: /*#__PURE__*/_jsx(X, {
148
166
  size: 12,
149
167
  color: night.color.textSecondary
@@ -164,7 +182,10 @@ const styles = StyleSheet.create({
164
182
  flex: 1,
165
183
  gap: 8,
166
184
  minHeight: 32,
167
- paddingLeft: 4
185
+ paddingLeft: 4,
186
+ // Traffic-light window controls sit absolutely in this corner. Reserve
187
+ // space so Copy / search / extra actions never paint under them.
188
+ paddingRight: 56
168
189
  },
169
190
  navigationButton: {
170
191
  padding: 4
@@ -200,7 +221,8 @@ const styles = StyleSheet.create({
200
221
  flexDirection: "row",
201
222
  gap: 6,
202
223
  marginLeft: "auto",
203
- marginRight: 4
224
+ marginRight: 4,
225
+ flexShrink: 0
204
226
  },
205
227
  headerContentNoMargin: {
206
228
  marginHorizontal: 0
@@ -28,6 +28,7 @@ export function PowerToggleButton({
28
28
  onToggle,
29
29
  size = "medium",
30
30
  accessibilityLabel,
31
+ testID,
31
32
  disabled = false
32
33
  }) {
33
34
  const buttonSize = size === "small" ? 28 : 32;
@@ -36,6 +37,7 @@ export function PowerToggleButton({
36
37
  onPress: onToggle,
37
38
  disabled: disabled,
38
39
  accessibilityLabel: accessibilityLabel,
40
+ testID: testID,
39
41
  accessibilityRole: "button",
40
42
  style: [styles.button, {
41
43
  width: buttonSize,
@@ -18,6 +18,7 @@ export function SearchBar({
18
18
  containerStyle,
19
19
  autoFocus = false,
20
20
  onSubmitEditing,
21
+ testID,
21
22
  returnKeyType
22
23
  }) {
23
24
  const [isFocused, setIsFocused] = useState(false);
@@ -75,10 +76,14 @@ export function SearchBar({
75
76
  autoCapitalize: "none",
76
77
  autoCorrect: false,
77
78
  onSubmitEditing: onSubmitEditing,
78
- returnKeyType: returnKeyType
79
+ returnKeyType: returnKeyType,
80
+ testID: testID
79
81
  }), value.length > 0 && /*#__PURE__*/_jsx(TouchableOpacity, {
80
82
  onPress: handleClear,
81
83
  style: styles.clearButton,
84
+ testID: testID ? `${testID}-clear` : undefined,
85
+ accessibilityLabel: "Clear search",
86
+ accessibilityRole: "button",
82
87
  children: /*#__PURE__*/_jsx(X, {
83
88
  size: 14,
84
89
  color: gameUIColors.secondary
@@ -50,7 +50,8 @@ function Title({
50
50
  function Badge({
51
51
  count,
52
52
  color = buoyColors.primary,
53
- children
53
+ children,
54
+ testID
54
55
  }) {
55
56
  const backgroundColor = `${color}15`;
56
57
  const borderColor = `${color}33`;
@@ -60,6 +61,7 @@ function Badge({
60
61
  borderColor
61
62
  }],
62
63
  children: count !== undefined ? /*#__PURE__*/_jsx(Text, {
64
+ testID: testID,
63
65
  style: [styles.badgeText, {
64
66
  color
65
67
  }],
@@ -15,24 +15,29 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
15
  export function TabSelector({
16
16
  tabs,
17
17
  activeTab,
18
- onTabChange
18
+ onTabChange,
19
+ testIDPrefix
19
20
  }) {
20
21
  return /*#__PURE__*/_jsx(View, {
21
22
  style: styles.container,
22
23
  children: tabs.map(tab => {
23
24
  const active = activeTab === tab.key;
25
+ const disabled = !!tab.disabled && !active;
24
26
  return /*#__PURE__*/_jsxs(TouchableOpacity, {
25
27
  "sentry-label": "ignore user interaction",
28
+ testID: testIDPrefix ? `${testIDPrefix}-${tab.key}` : undefined,
26
29
  accessibilityRole: "tab",
27
30
  accessibilityState: {
28
- selected: active
31
+ selected: active,
32
+ disabled
29
33
  },
30
34
  accessibilityLabel: tab.label,
31
35
  accessibilityHint: `View ${tab.label.toLowerCase()}`,
36
+ disabled: disabled,
32
37
  onPress: () => onTabChange(tab.key),
33
- style: [styles.tabButton, active && styles.tabButtonActive],
38
+ style: [styles.tabButton, active && styles.tabButtonActive, disabled && styles.tabButtonDisabled],
34
39
  children: [/*#__PURE__*/_jsx(Text, {
35
- style: [styles.tabButtonText, active && styles.tabButtonTextActive],
40
+ style: [styles.tabButtonText, active && styles.tabButtonTextActive, disabled && styles.tabButtonTextDisabled],
36
41
  children: tab.label
37
42
  }), active ? /*#__PURE__*/_jsx(View, {
38
43
  style: styles.underline
@@ -69,6 +74,12 @@ const styles = StyleSheet.create({
69
74
  fontWeight: "600",
70
75
  color: night.color.text
71
76
  },
77
+ tabButtonDisabled: {
78
+ opacity: 0.45
79
+ },
80
+ tabButtonTextDisabled: {
81
+ color: night.color.textTertiary
82
+ },
72
83
  underline: {
73
84
  position: "absolute",
74
85
  bottom: 1.5,